From 623d718487da29e06ea93c2a83601edb33d5f618 Mon Sep 17 00:00:00 2001 From: Daniel Colson Date: Fri, 21 Nov 2025 12:48:35 -0500 Subject: [PATCH] Add Ruby 4.0.0-preview2 headers Fixes https://github.com/DataDog/datadog-ruby_core_source/issues/17 Along the same lines as 852162a708cf471e7dafd7f297030eb7adc0e6a6, this commit imports the Ruby 4.0.0-preview2 headers into the gem. ** Motivation ** It's not possible to install this gem on 4.0.0-preview2 without these headers. Falling back to 3.5.0-preview1 does not work, since there is an ABI change in shape.h ** How to test the change? ** Adding these headers allowed me to install the gem on Ruby 4.0.0-preview2. I guess we'll eventually want dd-trace-rb CI to run against Ruby 4.0. --- .../ccan/build_assert/build_assert.h | 40 + .../ccan/check_type/check_type.h | 63 + .../ccan/container_of/container_of.h | 142 + .../ruby-4.0.0-preview2/ccan/list/list.h | 791 ++ .../ruby-4.0.0-preview2/ccan/str/str.h | 17 + .../ruby_core_source/ruby-4.0.0-preview2/id.h | 354 + .../ruby-4.0.0-preview2/id_table.h | 54 + .../ruby-4.0.0-preview2/internal.h | 105 + .../ruby-4.0.0-preview2/internal/array.h | 154 + .../internal/basic_operators.h | 65 + .../ruby-4.0.0-preview2/internal/bignum.h | 245 + .../ruby-4.0.0-preview2/internal/bits.h | 650 ++ .../ruby-4.0.0-preview2/internal/box.h | 81 + .../ruby-4.0.0-preview2/internal/class.h | 805 ++ .../ruby-4.0.0-preview2/internal/cmdlineopt.h | 64 + .../ruby-4.0.0-preview2/internal/compar.h | 29 + .../ruby-4.0.0-preview2/internal/compile.h | 34 + .../ruby-4.0.0-preview2/internal/compilers.h | 107 + .../ruby-4.0.0-preview2/internal/complex.h | 29 + .../internal/concurrent_set.h | 21 + .../ruby-4.0.0-preview2/internal/cont.h | 35 + .../ruby-4.0.0-preview2/internal/dir.h | 16 + .../ruby-4.0.0-preview2/internal/enc.h | 19 + .../ruby-4.0.0-preview2/internal/encoding.h | 39 + .../ruby-4.0.0-preview2/internal/enum.h | 18 + .../ruby-4.0.0-preview2/internal/enumerator.h | 21 + .../ruby-4.0.0-preview2/internal/error.h | 251 + .../ruby-4.0.0-preview2/internal/eval.h | 41 + .../ruby-4.0.0-preview2/internal/file.h | 38 + .../ruby-4.0.0-preview2/internal/fixnum.h | 185 + .../ruby-4.0.0-preview2/internal/gc.h | 358 + .../ruby-4.0.0-preview2/internal/hash.h | 194 + .../ruby-4.0.0-preview2/internal/imemo.h | 322 + .../ruby-4.0.0-preview2/internal/inits.h | 51 + .../ruby-4.0.0-preview2/internal/io.h | 163 + .../ruby-4.0.0-preview2/internal/load.h | 20 + .../ruby-4.0.0-preview2/internal/loadpath.h | 16 + .../ruby-4.0.0-preview2/internal/math.h | 23 + .../ruby-4.0.0-preview2/internal/missing.h | 19 + .../ruby-4.0.0-preview2/internal/numeric.h | 275 + .../ruby-4.0.0-preview2/internal/object.h | 63 + .../ruby-4.0.0-preview2/internal/parse.h | 131 + .../ruby-4.0.0-preview2/internal/proc.h | 30 + .../ruby-4.0.0-preview2/internal/process.h | 124 + .../ruby-4.0.0-preview2/internal/ractor.h | 10 + .../ruby-4.0.0-preview2/internal/random.h | 17 + .../ruby-4.0.0-preview2/internal/range.h | 40 + .../ruby-4.0.0-preview2/internal/rational.h | 71 + .../ruby-4.0.0-preview2/internal/re.h | 33 + .../internal/ruby_parser.h | 102 + .../ruby-4.0.0-preview2/internal/sanitizers.h | 346 + .../ruby-4.0.0-preview2/internal/serial.h | 23 + .../ruby-4.0.0-preview2/internal/set_table.h | 70 + .../ruby-4.0.0-preview2/internal/signal.h | 25 + .../ruby-4.0.0-preview2/internal/st.h | 11 + .../internal/static_assert.h | 16 + .../ruby-4.0.0-preview2/internal/string.h | 203 + .../ruby-4.0.0-preview2/internal/struct.h | 160 + .../ruby-4.0.0-preview2/internal/symbol.h | 46 + .../ruby-4.0.0-preview2/internal/thread.h | 112 + .../ruby-4.0.0-preview2/internal/time.h | 37 + .../ruby-4.0.0-preview2/internal/transcode.h | 23 + .../ruby-4.0.0-preview2/internal/util.h | 27 + .../ruby-4.0.0-preview2/internal/variable.h | 74 + .../ruby-4.0.0-preview2/internal/vm.h | 136 + .../ruby-4.0.0-preview2/internal/warnings.h | 16 + .../ruby-4.0.0-preview2/iseq.h | 357 + .../ruby-4.0.0-preview2/method.h | 271 + .../ruby-4.0.0-preview2/node.h | 122 + .../ruby-4.0.0-preview2/parser_st.h | 162 + .../ruby-4.0.0-preview2/parser_value.h | 106 + .../ruby-4.0.0-preview2/prism/ast.h | 8233 +++++++++++++++++ .../ruby-4.0.0-preview2/prism/defines.h | 260 + .../ruby-4.0.0-preview2/prism/diagnostic.h | 458 + .../ruby-4.0.0-preview2/prism/encoding.h | 283 + .../ruby-4.0.0-preview2/prism/extension.h | 19 + .../ruby-4.0.0-preview2/prism/node.h | 129 + .../ruby-4.0.0-preview2/prism/options.h | 485 + .../ruby-4.0.0-preview2/prism/pack.h | 163 + .../ruby-4.0.0-preview2/prism/parser.h | 936 ++ .../ruby-4.0.0-preview2/prism/prettyprint.h | 34 + .../ruby-4.0.0-preview2/prism/prism.h | 408 + .../ruby-4.0.0-preview2/prism/regexp.h | 43 + .../prism/static_literals.h | 121 + .../prism/util/pm_buffer.h | 236 + .../ruby-4.0.0-preview2/prism/util/pm_char.h | 204 + .../prism/util/pm_constant_pool.h | 218 + .../prism/util/pm_integer.h | 130 + .../ruby-4.0.0-preview2/prism/util/pm_list.h | 103 + .../prism/util/pm_memchr.h | 29 + .../prism/util/pm_newline_list.h | 113 + .../prism/util/pm_string.h | 200 + .../prism/util/pm_strncasecmp.h | 32 + .../prism/util/pm_strpbrk.h | 46 + .../ruby-4.0.0-preview2/prism/version.h | 29 + .../ruby-4.0.0-preview2/prism_compile.h | 106 + .../ruby-4.0.0-preview2/ractor_core.h | 306 + .../ruby-4.0.0-preview2/ruby_assert.h | 14 + .../ruby-4.0.0-preview2/ruby_atomic.h | 66 + .../ruby-4.0.0-preview2/rubyparser.h | 1394 +++ .../ruby-4.0.0-preview2/shape.h | 444 + .../ruby-4.0.0-preview2/thread_none.h | 21 + .../ruby-4.0.0-preview2/thread_pthread.h | 175 + .../ruby-4.0.0-preview2/vm_core.h | 2350 +++++ .../ruby-4.0.0-preview2/vm_debug.h | 124 + .../ruby-4.0.0-preview2/vm_opts.h | 67 + 106 files changed, 26897 insertions(+) create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/ccan/build_assert/build_assert.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/ccan/check_type/check_type.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/ccan/container_of/container_of.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/ccan/list/list.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/ccan/str/str.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/id.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/id_table.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/array.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/basic_operators.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/bignum.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/bits.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/box.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/class.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/cmdlineopt.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/compar.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/compile.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/compilers.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/complex.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/concurrent_set.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/cont.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/dir.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/enc.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/encoding.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/enum.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/enumerator.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/error.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/eval.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/file.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/fixnum.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/gc.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/hash.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/imemo.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/inits.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/io.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/load.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/loadpath.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/math.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/missing.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/numeric.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/object.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/parse.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/proc.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/process.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/ractor.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/random.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/range.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/rational.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/re.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/ruby_parser.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/sanitizers.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/serial.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/set_table.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/signal.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/st.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/static_assert.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/string.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/struct.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/symbol.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/thread.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/time.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/transcode.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/util.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/variable.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/vm.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/warnings.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/iseq.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/method.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/node.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/parser_st.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/parser_value.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/ast.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/defines.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/diagnostic.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/encoding.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/extension.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/node.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/options.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/pack.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/parser.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/prettyprint.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/prism.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/regexp.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/static_literals.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/util/pm_buffer.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/util/pm_char.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/util/pm_constant_pool.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/util/pm_integer.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/util/pm_list.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/util/pm_memchr.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/util/pm_newline_list.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/util/pm_string.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/util/pm_strncasecmp.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/util/pm_strpbrk.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/version.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism_compile.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/ractor_core.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/ruby_assert.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/ruby_atomic.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/rubyparser.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/shape.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/thread_none.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/thread_pthread.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/vm_core.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/vm_debug.h create mode 100644 lib/datadog/ruby_core_source/ruby-4.0.0-preview2/vm_opts.h diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/ccan/build_assert/build_assert.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/ccan/build_assert/build_assert.h new file mode 100644 index 0000000..b846849 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/ccan/build_assert/build_assert.h @@ -0,0 +1,40 @@ +/* CC0 (Public domain) - see ccan/licenses/CC0 file for details */ +#ifndef CCAN_BUILD_ASSERT_H +#define CCAN_BUILD_ASSERT_H + +/** + * CCAN_BUILD_ASSERT - assert a build-time dependency. + * @cond: the compile-time condition which must be true. + * + * Your compile will fail if the condition isn't true, or can't be evaluated + * by the compiler. This can only be used within a function. + * + * Example: + * #include + * ... + * static char *foo_to_char(struct foo *foo) + * { + * // This code needs string to be at start of foo. + * CCAN_BUILD_ASSERT(offsetof(struct foo, string) == 0); + * return (char *)foo; + * } + */ +#define CCAN_BUILD_ASSERT(cond) \ + do { (void) sizeof(char [1 - 2*!(cond)]); } while(0) + +/** + * CCAN_BUILD_ASSERT_OR_ZERO - assert a build-time dependency, as an expression. + * @cond: the compile-time condition which must be true. + * + * Your compile will fail if the condition isn't true, or can't be evaluated + * by the compiler. This can be used in an expression: its value is "0". + * + * Example: + * #define foo_to_char(foo) \ + * ((char *)(foo) \ + * + CCAN_BUILD_ASSERT_OR_ZERO(offsetof(struct foo, string) == 0)) + */ +#define CCAN_BUILD_ASSERT_OR_ZERO(cond) \ + (sizeof(char [1 - 2*!(cond)]) - 1) + +#endif /* CCAN_BUILD_ASSERT_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/ccan/check_type/check_type.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/ccan/check_type/check_type.h new file mode 100644 index 0000000..659e1a5 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/ccan/check_type/check_type.h @@ -0,0 +1,63 @@ +/* CC0 (Public domain) - see ccan/licenses/CC0 file for details */ +#ifndef CCAN_CHECK_TYPE_H +#define CCAN_CHECK_TYPE_H + +/** + * ccan_check_type - issue a warning or build failure if type is not correct. + * @expr: the expression whose type we should check (not evaluated). + * @type: the exact type we expect the expression to be. + * + * This macro is usually used within other macros to try to ensure that a macro + * argument is of the expected type. No type promotion of the expression is + * done: an unsigned int is not the same as an int! + * + * ccan_check_type() always evaluates to 0. + * + * If your compiler does not support typeof, then the best we can do is fail + * to compile if the sizes of the types are unequal (a less complete check). + * + * Example: + * // They should always pass a 64-bit value to _set_some_value! + * #define set_some_value(expr) \ + * _set_some_value((ccan_check_type((expr), uint64_t), (expr))) + */ + +/** + * ccan_check_types_match - issue a warning or build failure if types are not same. + * @expr1: the first expression (not evaluated). + * @expr2: the second expression (not evaluated). + * + * This macro is usually used within other macros to try to ensure that + * arguments are of identical types. No type promotion of the expressions is + * done: an unsigned int is not the same as an int! + * + * ccan_check_types_match() always evaluates to 0. + * + * If your compiler does not support typeof, then the best we can do is fail + * to compile if the sizes of the types are unequal (a less complete check). + * + * Example: + * // Do subtraction to get to enclosing type, but make sure that + * // pointer is of correct type for that member. + * #define ccan_container_of(mbr_ptr, encl_type, mbr) \ + * (ccan_check_types_match((mbr_ptr), &((encl_type *)0)->mbr), \ + * ((encl_type *) \ + * ((char *)(mbr_ptr) - offsetof(enclosing_type, mbr)))) + */ +#if defined(HAVE_TYPEOF) && HAVE_TYPEOF +#define ccan_check_type(expr, type) \ + ((typeof(expr) *)0 != (type *)0) + +#define ccan_check_types_match(expr1, expr2) \ + ((typeof(expr1) *)0 != (typeof(expr2) *)0) +#else +#include "ccan/build_assert/build_assert.h" +/* Without typeof, we can only test the sizes. */ +#define ccan_check_type(expr, type) \ + CCAN_BUILD_ASSERT_OR_ZERO(sizeof(expr) == sizeof(type)) + +#define ccan_check_types_match(expr1, expr2) \ + CCAN_BUILD_ASSERT_OR_ZERO(sizeof(expr1) == sizeof(expr2)) +#endif /* HAVE_TYPEOF */ + +#endif /* CCAN_CHECK_TYPE_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/ccan/container_of/container_of.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/ccan/container_of/container_of.h new file mode 100644 index 0000000..872bb6e --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/ccan/container_of/container_of.h @@ -0,0 +1,142 @@ +/* CC0 (Public domain) - see ccan/licenses/CC0 file for details */ +#ifndef CCAN_CONTAINER_OF_H +#define CCAN_CONTAINER_OF_H +#include "ccan/check_type/check_type.h" + +/** + * ccan_container_of - get pointer to enclosing structure + * @member_ptr: pointer to the structure member + * @containing_type: the type this member is within + * @member: the name of this member within the structure. + * + * Given a pointer to a member of a structure, this macro does pointer + * subtraction to return the pointer to the enclosing type. + * + * Example: + * struct foo { + * int fielda, fieldb; + * // ... + * }; + * struct info { + * int some_other_field; + * struct foo my_foo; + * }; + * + * static struct info *foo_to_info(struct foo *foo) + * { + * return ccan_container_of(foo, struct info, my_foo); + * } + */ +#define ccan_container_of(member_ptr, containing_type, member) \ + ((containing_type *) \ + ((char *)(member_ptr) \ + - ccan_container_off(containing_type, member)) \ + + ccan_check_types_match(*(member_ptr), ((containing_type *)0)->member)) + + +/** + * ccan_container_of_or_null - get pointer to enclosing structure, or NULL + * @member_ptr: pointer to the structure member + * @containing_type: the type this member is within + * @member: the name of this member within the structure. + * + * Given a pointer to a member of a structure, this macro does pointer + * subtraction to return the pointer to the enclosing type, unless it + * is given NULL, in which case it also returns NULL. + * + * Example: + * struct foo { + * int fielda, fieldb; + * // ... + * }; + * struct info { + * int some_other_field; + * struct foo my_foo; + * }; + * + * static struct info *foo_to_info_allowing_null(struct foo *foo) + * { + * return ccan_container_of_or_null(foo, struct info, my_foo); + * } + */ +static inline char *container_of_or_null_(void *member_ptr, size_t offset) +{ + return member_ptr ? (char *)member_ptr - offset : NULL; +} +#define ccan_container_of_or_null(member_ptr, containing_type, member) \ + ((containing_type *) \ + ccan_container_of_or_null_(member_ptr, \ + ccan_container_off(containing_type, member)) \ + + ccan_check_types_match(*(member_ptr), ((containing_type *)0)->member)) + +/** + * ccan_container_off - get offset to enclosing structure + * @containing_type: the type this member is within + * @member: the name of this member within the structure. + * + * Given a pointer to a member of a structure, this macro does + * typechecking and figures out the offset to the enclosing type. + * + * Example: + * struct foo { + * int fielda, fieldb; + * // ... + * }; + * struct info { + * int some_other_field; + * struct foo my_foo; + * }; + * + * static struct info *foo_to_info(struct foo *foo) + * { + * size_t off = ccan_container_off(struct info, my_foo); + * return (void *)((char *)foo - off); + * } + */ +#define ccan_container_off(containing_type, member) \ + offsetof(containing_type, member) + +/** + * ccan_container_of_var - get pointer to enclosing structure using a variable + * @member_ptr: pointer to the structure member + * @container_var: a pointer of same type as this member's container + * @member: the name of this member within the structure. + * + * Given a pointer to a member of a structure, this macro does pointer + * subtraction to return the pointer to the enclosing type. + * + * Example: + * static struct info *foo_to_i(struct foo *foo) + * { + * struct info *i = ccan_container_of_var(foo, i, my_foo); + * return i; + * } + */ +#if defined(HAVE_TYPEOF) && HAVE_TYPEOF +#define ccan_container_of_var(member_ptr, container_var, member) \ + ccan_container_of(member_ptr, typeof(*container_var), member) +#else +#define ccan_container_of_var(member_ptr, container_var, member) \ + ((void *)((char *)(member_ptr) - \ + ccan_container_off_var(container_var, member))) +#endif + +/** + * ccan_container_off_var - get offset of a field in enclosing structure + * @container_var: a pointer to a container structure + * @member: the name of a member within the structure. + * + * Given (any) pointer to a structure and a its member name, this + * macro does pointer subtraction to return offset of member in a + * structure memory layout. + * + */ +#if defined(HAVE_TYPEOF) && HAVE_TYPEOF +#define ccan_container_off_var(var, member) \ + ccan_container_off(typeof(*var), member) +#else +#define ccan_container_off_var(var, member) \ + ((const char *)&(var)->member - (const char *)(var)) +#endif + +#endif /* CCAN_CONTAINER_OF_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/ccan/list/list.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/ccan/list/list.h new file mode 100644 index 0000000..bf692a6 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/ccan/list/list.h @@ -0,0 +1,791 @@ +/* Licensed under BSD-MIT - see ccan/licenses/BSD-MIT file for details */ +#ifndef CCAN_LIST_H +#define CCAN_LIST_H +#include +#include "ccan/str/str.h" +#include "ccan/container_of/container_of.h" +#include "ccan/check_type/check_type.h" + +/** + * struct ccan_list_node - an entry in a doubly-linked list + * @next: next entry (self if empty) + * @prev: previous entry (self if empty) + * + * This is used as an entry in a linked list. + * Example: + * struct child { + * const char *name; + * // Linked list of all us children. + * struct ccan_list_node list; + * }; + */ +struct ccan_list_node +{ + struct ccan_list_node *next, *prev; +}; + +/** + * struct ccan_list_head - the head of a doubly-linked list + * @h: the ccan_list_head (containing next and prev pointers) + * + * This is used as the head of a linked list. + * Example: + * struct parent { + * const char *name; + * struct ccan_list_head children; + * unsigned int num_children; + * }; + */ +struct ccan_list_head +{ + struct ccan_list_node n; +}; + +#define CCAN_LIST_LOC __FILE__ ":" ccan_stringify(__LINE__) +#define ccan_list_debug(h, loc) ((void)loc, h) +#define ccan_list_debug_node(n, loc) ((void)loc, n) + +/** + * CCAN_LIST_HEAD_INIT - initializer for an empty ccan_list_head + * @name: the name of the list. + * + * Explicit initializer for an empty list. + * + * See also: + * CCAN_LIST_HEAD, ccan_list_head_init() + * + * Example: + * static struct ccan_list_head my_list = CCAN_LIST_HEAD_INIT(my_list); + */ +#define CCAN_LIST_HEAD_INIT(name) { { &(name).n, &(name).n } } + +/** + * CCAN_LIST_HEAD - define and initialize an empty ccan_list_head + * @name: the name of the list. + * + * The CCAN_LIST_HEAD macro defines a ccan_list_head and initializes it to an empty + * list. It can be prepended by "static" to define a static ccan_list_head. + * + * See also: + * CCAN_LIST_HEAD_INIT, ccan_list_head_init() + * + * Example: + * static CCAN_LIST_HEAD(my_global_list); + */ +#define CCAN_LIST_HEAD(name) \ + struct ccan_list_head name = CCAN_LIST_HEAD_INIT(name) + +/** + * ccan_list_head_init - initialize a ccan_list_head + * @h: the ccan_list_head to set to the empty list + * + * Example: + * ... + * struct parent *parent = malloc(sizeof(*parent)); + * + * ccan_list_head_init(&parent->children); + * parent->num_children = 0; + */ +static inline void ccan_list_head_init(struct ccan_list_head *h) +{ + h->n.next = h->n.prev = &h->n; +} + +/** + * ccan_list_node_init - initialize a ccan_list_node + * @n: the ccan_list_node to link to itself. + * + * You don't need to use this normally! But it lets you ccan_list_del(@n) + * safely. + */ +static inline void ccan_list_node_init(struct ccan_list_node *n) +{ + n->next = n->prev = n; +} + +/** + * ccan_list_add_after - add an entry after an existing node in a linked list + * @h: the ccan_list_head to add the node to (for debugging) + * @p: the existing ccan_list_node to add the node after + * @n: the new ccan_list_node to add to the list. + * + * The existing ccan_list_node must already be a member of the list. + * The new ccan_list_node does not need to be initialized; it will be overwritten. + * + * Example: + * struct child c1, c2, c3; + * CCAN_LIST_HEAD(h); + * + * ccan_list_add_tail(&h, &c1.list); + * ccan_list_add_tail(&h, &c3.list); + * ccan_list_add_after(&h, &c1.list, &c2.list); + */ +#define ccan_list_add_after(h, p, n) ccan_list_add_after_(h, p, n, CCAN_LIST_LOC) +static inline void ccan_list_add_after_(struct ccan_list_head *h, + struct ccan_list_node *p, + struct ccan_list_node *n, + const char *abortstr) +{ + n->next = p->next; + n->prev = p; + p->next->prev = n; + p->next = n; + (void)ccan_list_debug(h, abortstr); +} + +/** + * ccan_list_add - add an entry at the start of a linked list. + * @h: the ccan_list_head to add the node to + * @n: the ccan_list_node to add to the list. + * + * The ccan_list_node does not need to be initialized; it will be overwritten. + * Example: + * struct child *child = malloc(sizeof(*child)); + * + * child->name = "marvin"; + * ccan_list_add(&parent->children, &child->list); + * parent->num_children++; + */ +#define ccan_list_add(h, n) ccan_list_add_(h, n, CCAN_LIST_LOC) +static inline void ccan_list_add_(struct ccan_list_head *h, + struct ccan_list_node *n, + const char *abortstr) +{ + ccan_list_add_after_(h, &h->n, n, abortstr); +} + +/** + * ccan_list_add_before - add an entry before an existing node in a linked list + * @h: the ccan_list_head to add the node to (for debugging) + * @p: the existing ccan_list_node to add the node before + * @n: the new ccan_list_node to add to the list. + * + * The existing ccan_list_node must already be a member of the list. + * The new ccan_list_node does not need to be initialized; it will be overwritten. + * + * Example: + * ccan_list_head_init(&h); + * ccan_list_add_tail(&h, &c1.list); + * ccan_list_add_tail(&h, &c3.list); + * ccan_list_add_before(&h, &c3.list, &c2.list); + */ +#define ccan_list_add_before(h, p, n) ccan_list_add_before_(h, p, n, CCAN_LIST_LOC) +static inline void ccan_list_add_before_(struct ccan_list_head *h, + struct ccan_list_node *p, + struct ccan_list_node *n, + const char *abortstr) +{ + n->next = p; + n->prev = p->prev; + p->prev->next = n; + p->prev = n; + (void)ccan_list_debug(h, abortstr); +} + +/** + * ccan_list_add_tail - add an entry at the end of a linked list. + * @h: the ccan_list_head to add the node to + * @n: the ccan_list_node to add to the list. + * + * The ccan_list_node does not need to be initialized; it will be overwritten. + * Example: + * ccan_list_add_tail(&parent->children, &child->list); + * parent->num_children++; + */ +#define ccan_list_add_tail(h, n) ccan_list_add_tail_(h, n, CCAN_LIST_LOC) +static inline void ccan_list_add_tail_(struct ccan_list_head *h, + struct ccan_list_node *n, + const char *abortstr) +{ + ccan_list_add_before_(h, &h->n, n, abortstr); +} + +/** + * ccan_list_empty - is a list empty? + * @h: the ccan_list_head + * + * If the list is empty, returns true. + * + * Example: + * assert(ccan_list_empty(&parent->children) == (parent->num_children == 0)); + */ +#define ccan_list_empty(h) ccan_list_empty_(h, CCAN_LIST_LOC) +static inline int ccan_list_empty_(const struct ccan_list_head *h, const char* abortstr) +{ + (void)ccan_list_debug(h, abortstr); + return h->n.next == &h->n; +} + +/** + * ccan_list_empty_nodebug - is a list empty (and don't perform debug checks)? + * @h: the ccan_list_head + * + * If the list is empty, returns true. + * This differs from list_empty() in that if CCAN_LIST_DEBUG is set it + * will NOT perform debug checks. Only use this function if you REALLY + * know what you're doing. + * + * Example: + * assert(ccan_list_empty_nodebug(&parent->children) == (parent->num_children == 0)); + */ +#ifndef CCAN_LIST_DEBUG +#define ccan_list_empty_nodebug(h) ccan_list_empty(h) +#else +static inline int ccan_list_empty_nodebug(const struct ccan_list_head *h) +{ + return h->n.next == &h->n; +} +#endif + +/** + * ccan_list_empty_nocheck - is a list empty? + * @h: the ccan_list_head + * + * If the list is empty, returns true. This doesn't perform any + * debug check for list consistency, so it can be called without + * locks, racing with the list being modified. This is ok for + * checks where an incorrect result is not an issue (optimized + * bail out path for example). + */ +static inline bool ccan_list_empty_nocheck(const struct ccan_list_head *h) +{ + return h->n.next == &h->n; +} + +/** + * ccan_list_del - delete an entry from an (unknown) linked list. + * @n: the ccan_list_node to delete from the list. + * + * Note that this leaves @n in an undefined state; it can be added to + * another list, but not deleted again. + * + * See also: + * ccan_list_del_from(), ccan_list_del_init() + * + * Example: + * ccan_list_del(&child->list); + * parent->num_children--; + */ +#define ccan_list_del(n) ccan_list_del_(n, CCAN_LIST_LOC) +static inline void ccan_list_del_(struct ccan_list_node *n, const char* abortstr) +{ + (void)ccan_list_debug_node(n, abortstr); + n->next->prev = n->prev; + n->prev->next = n->next; +#ifdef CCAN_LIST_DEBUG + /* Catch use-after-del. */ + n->next = n->prev = NULL; +#endif +} + +/** + * ccan_list_del_init - delete a node, and reset it so it can be deleted again. + * @n: the ccan_list_node to be deleted. + * + * ccan_list_del(@n) or ccan_list_del_init() again after this will be safe, + * which can be useful in some cases. + * + * See also: + * ccan_list_del_from(), ccan_list_del() + * + * Example: + * ccan_list_del_init(&child->list); + * parent->num_children--; + */ +#define ccan_list_del_init(n) ccan_list_del_init_(n, CCAN_LIST_LOC) +static inline void ccan_list_del_init_(struct ccan_list_node *n, const char *abortstr) +{ + ccan_list_del_(n, abortstr); + ccan_list_node_init(n); +} + +/** + * ccan_list_del_from - delete an entry from a known linked list. + * @h: the ccan_list_head the node is in. + * @n: the ccan_list_node to delete from the list. + * + * This explicitly indicates which list a node is expected to be in, + * which is better documentation and can catch more bugs. + * + * See also: ccan_list_del() + * + * Example: + * ccan_list_del_from(&parent->children, &child->list); + * parent->num_children--; + */ +static inline void ccan_list_del_from(struct ccan_list_head *h, struct ccan_list_node *n) +{ +#ifdef CCAN_LIST_DEBUG + { + /* Thorough check: make sure it was in list! */ + struct ccan_list_node *i; + for (i = h->n.next; i != n; i = i->next) + assert(i != &h->n); + } +#endif /* CCAN_LIST_DEBUG */ + + /* Quick test that catches a surprising number of bugs. */ + assert(!ccan_list_empty(h)); + ccan_list_del(n); +} + +/** + * ccan_list_swap - swap out an entry from an (unknown) linked list for a new one. + * @o: the ccan_list_node to replace from the list. + * @n: the ccan_list_node to insert in place of the old one. + * + * Note that this leaves @o in an undefined state; it can be added to + * another list, but not deleted/swapped again. + * + * See also: + * ccan_list_del() + * + * Example: + * struct child x1, x2; + * CCAN_LIST_HEAD(xh); + * + * ccan_list_add(&xh, &x1.list); + * ccan_list_swap(&x1.list, &x2.list); + */ +#define ccan_list_swap(o, n) ccan_list_swap_(o, n, CCAN_LIST_LOC) +static inline void ccan_list_swap_(struct ccan_list_node *o, + struct ccan_list_node *n, + const char* abortstr) +{ + (void)ccan_list_debug_node(o, abortstr); + *n = *o; + n->next->prev = n; + n->prev->next = n; +#ifdef CCAN_LIST_DEBUG + /* Catch use-after-del. */ + o->next = o->prev = NULL; +#endif +} + +/** + * ccan_list_entry - convert a ccan_list_node back into the structure containing it. + * @n: the ccan_list_node + * @type: the type of the entry + * @member: the ccan_list_node member of the type + * + * Example: + * // First list entry is children.next; convert back to child. + * child = ccan_list_entry(parent->children.n.next, struct child, list); + * + * See Also: + * ccan_list_top(), ccan_list_for_each() + */ +#define ccan_list_entry(n, type, member) ccan_container_of(n, type, member) + +/** + * ccan_list_top - get the first entry in a list + * @h: the ccan_list_head + * @type: the type of the entry + * @member: the ccan_list_node member of the type + * + * If the list is empty, returns NULL. + * + * Example: + * struct child *first; + * first = ccan_list_top(&parent->children, struct child, list); + * if (!first) + * printf("Empty list!\n"); + */ +#define ccan_list_top(h, type, member) \ + ((type *)ccan_list_top_((h), ccan_list_off_(type, member))) + +static inline const void *ccan_list_top_(const struct ccan_list_head *h, size_t off) +{ + if (ccan_list_empty(h)) + return NULL; + return (const char *)h->n.next - off; +} + +/** + * ccan_list_pop - remove the first entry in a list + * @h: the ccan_list_head + * @type: the type of the entry + * @member: the ccan_list_node member of the type + * + * If the list is empty, returns NULL. + * + * Example: + * struct child *one; + * one = ccan_list_pop(&parent->children, struct child, list); + * if (!one) + * printf("Empty list!\n"); + */ +#define ccan_list_pop(h, type, member) \ + ((type *)ccan_list_pop_((h), ccan_list_off_(type, member))) + +static inline const void *ccan_list_pop_(const struct ccan_list_head *h, size_t off) +{ + struct ccan_list_node *n; + + if (ccan_list_empty(h)) + return NULL; + n = h->n.next; + ccan_list_del(n); + return (const char *)n - off; +} + +/** + * ccan_list_tail - get the last entry in a list + * @h: the ccan_list_head + * @type: the type of the entry + * @member: the ccan_list_node member of the type + * + * If the list is empty, returns NULL. + * + * Example: + * struct child *last; + * last = ccan_list_tail(&parent->children, struct child, list); + * if (!last) + * printf("Empty list!\n"); + */ +#define ccan_list_tail(h, type, member) \ + ((type *)ccan_list_tail_((h), ccan_list_off_(type, member))) + +static inline const void *ccan_list_tail_(const struct ccan_list_head *h, size_t off) +{ + if (ccan_list_empty(h)) + return NULL; + return (const char *)h->n.prev - off; +} + +/** + * ccan_list_for_each - iterate through a list. + * @h: the ccan_list_head (warning: evaluated multiple times!) + * @i: the structure containing the ccan_list_node + * @member: the ccan_list_node member of the structure + * + * This is a convenient wrapper to iterate @i over the entire list. It's + * a for loop, so you can break and continue as normal. + * + * Example: + * ccan_list_for_each(&parent->children, child, list) + * printf("Name: %s\n", child->name); + */ +#define ccan_list_for_each(h, i, member) \ + ccan_list_for_each_off(h, i, ccan_list_off_var_(i, member)) + +/** + * ccan_list_for_each_rev - iterate through a list backwards. + * @h: the ccan_list_head + * @i: the structure containing the ccan_list_node + * @member: the ccan_list_node member of the structure + * + * This is a convenient wrapper to iterate @i over the entire list. It's + * a for loop, so you can break and continue as normal. + * + * Example: + * ccan_list_for_each_rev(&parent->children, child, list) + * printf("Name: %s\n", child->name); + */ +#define ccan_list_for_each_rev(h, i, member) \ + ccan_list_for_each_rev_off(h, i, ccan_list_off_var_(i, member)) + +/** + * ccan_list_for_each_rev_safe - iterate through a list backwards, + * maybe during deletion + * @h: the ccan_list_head + * @i: the structure containing the ccan_list_node + * @nxt: the structure containing the ccan_list_node + * @member: the ccan_list_node member of the structure + * + * This is a convenient wrapper to iterate @i over the entire list backwards. + * It's a for loop, so you can break and continue as normal. The extra + * variable * @nxt is used to hold the next element, so you can delete @i + * from the list. + * + * Example: + * struct child *next; + * ccan_list_for_each_rev_safe(&parent->children, child, next, list) { + * printf("Name: %s\n", child->name); + * } + */ +#define ccan_list_for_each_rev_safe(h, i, nxt, member) \ + ccan_list_for_each_rev_safe_off(h, i, nxt, ccan_list_off_var_(i, member)) + +/** + * ccan_list_for_each_safe - iterate through a list, maybe during deletion + * @h: the ccan_list_head + * @i: the structure containing the ccan_list_node + * @nxt: the structure containing the ccan_list_node + * @member: the ccan_list_node member of the structure + * + * This is a convenient wrapper to iterate @i over the entire list. It's + * a for loop, so you can break and continue as normal. The extra variable + * @nxt is used to hold the next element, so you can delete @i from the list. + * + * Example: + * ccan_list_for_each_safe(&parent->children, child, next, list) { + * ccan_list_del(&child->list); + * parent->num_children--; + * } + */ +#define ccan_list_for_each_safe(h, i, nxt, member) \ + ccan_list_for_each_safe_off(h, i, nxt, ccan_list_off_var_(i, member)) + +/** + * ccan_list_next - get the next entry in a list + * @h: the ccan_list_head + * @i: a pointer to an entry in the list. + * @member: the ccan_list_node member of the structure + * + * If @i was the last entry in the list, returns NULL. + * + * Example: + * struct child *second; + * second = ccan_list_next(&parent->children, first, list); + * if (!second) + * printf("No second child!\n"); + */ +#define ccan_list_next(h, i, member) \ + ((ccan_list_typeof(i))ccan_list_entry_or_null(ccan_list_debug(h, \ + __FILE__ ":" ccan_stringify(__LINE__)), \ + (i)->member.next, \ + ccan_list_off_var_((i), member))) + +/** + * ccan_list_prev - get the previous entry in a list + * @h: the ccan_list_head + * @i: a pointer to an entry in the list. + * @member: the ccan_list_node member of the structure + * + * If @i was the first entry in the list, returns NULL. + * + * Example: + * first = ccan_list_prev(&parent->children, second, list); + * if (!first) + * printf("Can't go back to first child?!\n"); + */ +#define ccan_list_prev(h, i, member) \ + ((ccan_list_typeof(i))ccan_list_entry_or_null(ccan_list_debug(h, \ + __FILE__ ":" ccan_stringify(__LINE__)), \ + (i)->member.prev, \ + ccan_list_off_var_((i), member))) + +/** + * ccan_list_append_list - empty one list onto the end of another. + * @to: the list to append into + * @from: the list to empty. + * + * This takes the entire contents of @from and moves it to the end of + * @to. After this @from will be empty. + * + * Example: + * struct ccan_list_head adopter; + * + * ccan_list_append_list(&adopter, &parent->children); + * assert(ccan_list_empty(&parent->children)); + * parent->num_children = 0; + */ +#define ccan_list_append_list(t, f) ccan_list_append_list_(t, f, \ + __FILE__ ":" ccan_stringify(__LINE__)) +static inline void ccan_list_append_list_(struct ccan_list_head *to, + struct ccan_list_head *from, + const char *abortstr) +{ + struct ccan_list_node *from_tail = ccan_list_debug(from, abortstr)->n.prev; + struct ccan_list_node *to_tail = ccan_list_debug(to, abortstr)->n.prev; + + /* Sew in head and entire list. */ + to->n.prev = from_tail; + from_tail->next = &to->n; + to_tail->next = &from->n; + from->n.prev = to_tail; + + /* Now remove head. */ + ccan_list_del(&from->n); + ccan_list_head_init(from); +} + +/** + * ccan_list_prepend_list - empty one list into the start of another. + * @to: the list to prepend into + * @from: the list to empty. + * + * This takes the entire contents of @from and moves it to the start + * of @to. After this @from will be empty. + * + * Example: + * ccan_list_prepend_list(&adopter, &parent->children); + * assert(ccan_list_empty(&parent->children)); + * parent->num_children = 0; + */ +#define ccan_list_prepend_list(t, f) ccan_list_prepend_list_(t, f, CCAN_LIST_LOC) +static inline void ccan_list_prepend_list_(struct ccan_list_head *to, + struct ccan_list_head *from, + const char *abortstr) +{ + struct ccan_list_node *from_tail = ccan_list_debug(from, abortstr)->n.prev; + struct ccan_list_node *to_head = ccan_list_debug(to, abortstr)->n.next; + + /* Sew in head and entire list. */ + to->n.next = &from->n; + from->n.prev = &to->n; + to_head->prev = from_tail; + from_tail->next = to_head; + + /* Now remove head. */ + ccan_list_del(&from->n); + ccan_list_head_init(from); +} + +/* internal macros, do not use directly */ +#define ccan_list_for_each_off_dir_(h, i, off, dir) \ + for (i = 0, \ + i = ccan_list_node_to_off_(ccan_list_debug(h, CCAN_LIST_LOC)->n.dir, \ + (off)); \ + ccan_list_node_from_off_((void *)i, (off)) != &(h)->n; \ + i = ccan_list_node_to_off_(ccan_list_node_from_off_((void *)i, (off))->dir, \ + (off))) + +#define ccan_list_for_each_safe_off_dir_(h, i, nxt, off, dir) \ + for (i = 0, \ + i = ccan_list_node_to_off_(ccan_list_debug(h, CCAN_LIST_LOC)->n.dir, \ + (off)), \ + nxt = ccan_list_node_to_off_(ccan_list_node_from_off_(i, (off))->dir, \ + (off)); \ + ccan_list_node_from_off_(i, (off)) != &(h)->n; \ + i = nxt, \ + nxt = ccan_list_node_to_off_(ccan_list_node_from_off_(i, (off))->dir, \ + (off))) + +/** + * ccan_list_for_each_off - iterate through a list of memory regions. + * @h: the ccan_list_head + * @i: the pointer to a memory region which contains list node data. + * @off: offset(relative to @i) at which list node data resides. + * + * This is a low-level wrapper to iterate @i over the entire list, used to + * implement all other, more high-level, for-each constructs. It's a for loop, + * so you can break and continue as normal. + * + * WARNING! Being the low-level macro that it is, this wrapper doesn't know + * nor care about the type of @i. The only assumption made is that @i points + * to a chunk of memory that at some @offset, relative to @i, contains a + * properly filled `struct ccan_list_node' which in turn contains pointers to + * memory chunks and it's turtles all the way down. With all that in mind + * remember that given the wrong pointer/offset couple this macro will + * happily churn all you memory until SEGFAULT stops it, in other words + * caveat emptor. + * + * It is worth mentioning that one of legitimate use-cases for that wrapper + * is operation on opaque types with known offset for `struct ccan_list_node' + * member(preferably 0), because it allows you not to disclose the type of + * @i. + * + * Example: + * ccan_list_for_each_off(&parent->children, child, + * offsetof(struct child, list)) + * printf("Name: %s\n", child->name); + */ +#define ccan_list_for_each_off(h, i, off) \ + ccan_list_for_each_off_dir_((h),(i),(off),next) + +/** + * ccan_list_for_each_rev_off - iterate through a list of memory regions backwards + * @h: the ccan_list_head + * @i: the pointer to a memory region which contains list node data. + * @off: offset(relative to @i) at which list node data resides. + * + * See ccan_list_for_each_off for details + */ +#define ccan_list_for_each_rev_off(h, i, off) \ + ccan_list_for_each_off_dir_((h),(i),(off),prev) + +/** + * ccan_list_for_each_safe_off - iterate through a list of memory regions, maybe + * during deletion + * @h: the ccan_list_head + * @i: the pointer to a memory region which contains list node data. + * @nxt: the structure containing the ccan_list_node + * @off: offset(relative to @i) at which list node data resides. + * + * For details see `ccan_list_for_each_off' and `ccan_list_for_each_safe' + * descriptions. + * + * Example: + * ccan_list_for_each_safe_off(&parent->children, child, + * next, offsetof(struct child, list)) + * printf("Name: %s\n", child->name); + */ +#define ccan_list_for_each_safe_off(h, i, nxt, off) \ + ccan_list_for_each_safe_off_dir_((h),(i),(nxt),(off),next) + +/** + * ccan_list_for_each_rev_safe_off - iterate backwards through a list of + * memory regions, maybe during deletion + * @h: the ccan_list_head + * @i: the pointer to a memory region which contains list node data. + * @nxt: the structure containing the ccan_list_node + * @off: offset(relative to @i) at which list node data resides. + * + * For details see `ccan_list_for_each_rev_off' and `ccan_list_for_each_rev_safe' + * descriptions. + * + * Example: + * ccan_list_for_each_rev_safe_off(&parent->children, child, + * next, offsetof(struct child, list)) + * printf("Name: %s\n", child->name); + */ +#define ccan_list_for_each_rev_safe_off(h, i, nxt, off) \ + ccan_list_for_each_safe_off_dir_((h),(i),(nxt),(off),prev) + +/* Other -off variants. */ +#define ccan_list_entry_off(n, type, off) \ + ((type *)ccan_list_node_from_off_((n), (off))) + +#define ccan_list_head_off(h, type, off) \ + ((type *)ccan_list_head_off((h), (off))) + +#define ccan_list_tail_off(h, type, off) \ + ((type *)ccan_list_tail_((h), (off))) + +#define ccan_list_add_off(h, n, off) \ + ccan_list_add((h), ccan_list_node_from_off_((n), (off))) + +#define ccan_list_del_off(n, off) \ + ccan_list_del(ccan_list_node_from_off_((n), (off))) + +#define ccan_list_del_from_off(h, n, off) \ + ccan_list_del_from(h, ccan_list_node_from_off_((n), (off))) + +/* Offset helper functions so we only single-evaluate. */ +static inline void *ccan_list_node_to_off_(struct ccan_list_node *node, size_t off) +{ + return (void *)((char *)node - off); +} +static inline struct ccan_list_node *ccan_list_node_from_off_(void *ptr, size_t off) +{ + return (struct ccan_list_node *)((char *)ptr + off); +} + +/* Get the offset of the member, but make sure it's a ccan_list_node. */ +#define ccan_list_off_(type, member) \ + (ccan_container_off(type, member) + \ + ccan_check_type(((type *)0)->member, struct ccan_list_node)) + +#define ccan_list_off_var_(var, member) \ + (ccan_container_off_var(var, member) + \ + ccan_check_type(var->member, struct ccan_list_node)) + +#if defined(HAVE_TYPEOF) && HAVE_TYPEOF +#define ccan_list_typeof(var) typeof(var) +#else +#define ccan_list_typeof(var) void * +#endif + +/* Returns member, or NULL if at end of list. */ +static inline void *ccan_list_entry_or_null(const struct ccan_list_head *h, + const struct ccan_list_node *n, + size_t off) +{ + if (n == &h->n) + return NULL; + return (char *)n - off; +} + +#endif /* CCAN_LIST_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/ccan/str/str.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/ccan/str/str.h new file mode 100644 index 0000000..6d4cf62 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/ccan/str/str.h @@ -0,0 +1,17 @@ +/* CC0 (Public domain) - see ccan/licenses/CC0 file for details */ +#ifndef CCAN_STR_H +#define CCAN_STR_H +/** + * ccan_stringify - Turn expression into a string literal + * @expr: any C expression + * + * Example: + * #define PRINT_COND_IF_FALSE(cond) \ + * ((cond) || printf("%s is false!", ccan_stringify(cond))) + */ +#define stringify(expr) ccan_stringify_1(expr) +#define ccan_stringify(expr) ccan_stringify_1(expr) +/* Double-indirection required to stringify expansions */ +#define ccan_stringify_1(expr) #expr + +#endif /* CCAN_STR_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/id.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/id.h new file mode 100644 index 0000000..387a924 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/id.h @@ -0,0 +1,354 @@ +/* DO NOT EDIT THIS FILE DIRECTLY: source is at template/id.h.tmpl */ +/********************************************************************** + + id.h - + + $Author$ + created at: Sun Oct 19 21:12:51 2008 + + Copyright (C) 2007 Koichi Sasada + +**********************************************************************/ + +#ifndef RUBY_ID_H +#define RUBY_ID_H + +enum ruby_id_types { + RUBY_ID_LOCAL = 0x00, + RUBY_ID_STATIC_SYM = 0x01, + RUBY_ID_INSTANCE = (0x01<<1), + RUBY_ID_GLOBAL = (0x03<<1), + RUBY_ID_ATTRSET = (0x04<<1), + RUBY_ID_CONST = (0x05<<1), + RUBY_ID_CLASS = (0x06<<1), + RUBY_ID_INTERNAL = (0x07<<1), + RUBY_ID_SCOPE_SHIFT = 4, + RUBY_ID_SCOPE_MASK = (~(~0U<<(RUBY_ID_SCOPE_SHIFT-1))<<1) +}; + +#define ID_STATIC_SYM RUBY_ID_STATIC_SYM +#define ID_SCOPE_SHIFT RUBY_ID_SCOPE_SHIFT +#define ID_SCOPE_MASK RUBY_ID_SCOPE_MASK +#define ID_LOCAL RUBY_ID_LOCAL +#define ID_INSTANCE RUBY_ID_INSTANCE +#define ID_GLOBAL RUBY_ID_GLOBAL +#define ID_ATTRSET RUBY_ID_ATTRSET +#define ID_CONST RUBY_ID_CONST +#define ID_CLASS RUBY_ID_CLASS +#define ID_INTERNAL RUBY_ID_INTERNAL + +#define symIFUNC ID2SYM(idIFUNC) +#define symCFUNC ID2SYM(idCFUNC) + +#define RUBY_TOKEN_DOT2 128 +#define RUBY_TOKEN_DOT3 129 +#define RUBY_TOKEN_BDOT2 130 +#define RUBY_TOKEN_BDOT3 131 +#define RUBY_TOKEN_UPLUS 132 +#define RUBY_TOKEN_UMINUS 133 +#define RUBY_TOKEN_POW 134 +#define RUBY_TOKEN_CMP 135 +#define RUBY_TOKEN_LSHFT 136 +#define RUBY_TOKEN_RSHFT 137 +#define RUBY_TOKEN_LEQ 138 +#define RUBY_TOKEN_GEQ 139 +#define RUBY_TOKEN_EQ 140 +#define RUBY_TOKEN_EQQ 141 +#define RUBY_TOKEN_NEQ 142 +#define RUBY_TOKEN_MATCH 143 +#define RUBY_TOKEN_NMATCH 144 +#define RUBY_TOKEN_AREF 145 +#define RUBY_TOKEN_ASET 146 +#define RUBY_TOKEN_COLON2 147 +#define RUBY_TOKEN_ANDOP 148 +#define RUBY_TOKEN_OROP 149 +#define RUBY_TOKEN_ANDDOT 150 +#define RUBY_TOKEN(t) RUBY_TOKEN_##t + +#define RUBY_TOKEN2ID_TYPE(tok, type) ((tok<> ID_SCOPE_SHIFT +}; + +#endif /* RUBY_ID_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/id_table.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/id_table.h new file mode 100644 index 0000000..0c8cd34 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/id_table.h @@ -0,0 +1,54 @@ +#ifndef RUBY_ID_TABLE_H +#define RUBY_ID_TABLE_H 1 +#include "ruby/internal/config.h" +#include +#include "ruby/ruby.h" + +struct rb_id_table; + +/* compatible with ST_* */ +enum rb_id_table_iterator_result { + ID_TABLE_CONTINUE = ST_CONTINUE, + ID_TABLE_STOP = ST_STOP, + ID_TABLE_DELETE = ST_DELETE, + ID_TABLE_REPLACE = ST_REPLACE, + ID_TABLE_ITERATOR_RESULT_END +}; + +struct rb_id_table *rb_id_table_create(size_t size); +struct rb_id_table *rb_id_table_init(struct rb_id_table *tbl, size_t capa); + +void rb_id_table_free(struct rb_id_table *tbl); +void rb_id_table_free_items(struct rb_id_table *tbl); +void rb_id_table_clear(struct rb_id_table *tbl); + +size_t rb_id_table_memsize(const struct rb_id_table *tbl); + +int rb_id_table_insert(struct rb_id_table *tbl, ID id, VALUE val); +int rb_id_table_lookup(struct rb_id_table *tbl, ID id, VALUE *valp); +int rb_id_table_delete(struct rb_id_table *tbl, ID id); + +typedef enum rb_id_table_iterator_result rb_id_table_update_value_callback_func_t(VALUE *val, void *data, int existing); +typedef enum rb_id_table_iterator_result rb_id_table_foreach_func_t(ID id, VALUE val, void *data); +typedef enum rb_id_table_iterator_result rb_id_table_foreach_values_func_t(VALUE val, void *data); +void rb_id_table_foreach(struct rb_id_table *tbl, rb_id_table_foreach_func_t *func, void *data); +void rb_id_table_foreach_values(struct rb_id_table *tbl, rb_id_table_foreach_values_func_t *func, void *data); +void rb_id_table_foreach_values_with_replace(struct rb_id_table *tbl, rb_id_table_foreach_values_func_t *func, rb_id_table_update_value_callback_func_t *replace, void *data); + +VALUE rb_managed_id_table_create(const rb_data_type_t *type, size_t capa); +VALUE rb_managed_id_table_new(size_t capa); +VALUE rb_managed_id_table_dup(VALUE table); +int rb_managed_id_table_insert(VALUE table, ID id, VALUE val); +int rb_managed_id_table_lookup(VALUE table, ID id, VALUE *valp); +size_t rb_managed_id_table_size(VALUE table); +void rb_managed_id_table_foreach(VALUE table, rb_id_table_foreach_func_t *func, void *data); +void rb_managed_id_table_foreach_values(VALUE table, rb_id_table_foreach_values_func_t *func, void *data); +int rb_managed_id_table_delete(VALUE table, ID id); + +extern const rb_data_type_t rb_managed_id_table_type; + +RUBY_SYMBOL_EXPORT_BEGIN +size_t rb_id_table_size(const struct rb_id_table *tbl); +RUBY_SYMBOL_EXPORT_END + +#endif /* RUBY_ID_TABLE_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal.h new file mode 100644 index 0000000..002044c --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal.h @@ -0,0 +1,105 @@ +#ifndef RUBY_INTERNAL_H /*-*-C-*-vi:se ft=c:*/ +#define RUBY_INTERNAL_H 1 +/** + * @author $Author$ + * @date Tue May 17 11:42:20 JST 2011 + * @copyright Copyright (C) 2011 Yukihiro Matsumoto + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + */ +#include "ruby/internal/config.h" + +#ifdef __cplusplus +# error not for C++ +#endif + +#define LIKELY(x) RB_LIKELY(x) +#define UNLIKELY(x) RB_UNLIKELY(x) + +#define numberof(array) ((int)(sizeof(array) / sizeof((array)[0]))) +#define roomof(x, y) (((x) + (y) - 1) / (y)) +#define type_roomof(x, y) roomof(sizeof(x), sizeof(y)) + +/* Prevent compiler from reordering access */ +#define ACCESS_ONCE(type,x) (*((volatile type *)&(x))) + +#define UNDEF_P RB_UNDEF_P +#define NIL_OR_UNDEF_P RB_NIL_OR_UNDEF_P + +#include "ruby/ruby.h" + +/* Following macros were formerly defined in this header but moved to somewhere + * else. In order to detect them we undef here. */ + +/* internal/array.h */ +#undef RARRAY_AREF + +/* internal/class.h */ +#undef RClass +#undef RCLASS_SUPER + +/* internal/hash.h */ +#undef RHASH_IFNONE +#undef RHASH_SIZE +#undef RHASH_TBL +#undef RHASH_EMPTY_P + +/* internal/struct.h */ +#undef RSTRUCT_LEN +#undef RSTRUCT_PTR +#undef RSTRUCT_SET +#undef RSTRUCT_GET + +/* Also, we keep the following macros here. They are expected to be + * overridden in each headers. */ + +/* internal/array.h */ +#define rb_ary_new_from_args(...) rb_nonexistent_symbol(__VA_ARGS__) + +/* internal/string.h */ +#define rb_fstring_cstr(...) rb_nonexistent_symbol(__VA_ARGS__) + +/* internal/symbol.h */ +#define rb_sym_intern_ascii_cstr(...) rb_nonexistent_symbol(__VA_ARGS__) + +/* internal/vm.h */ +#define rb_funcallv(...) rb_nonexistent_symbol(__VA_ARGS__) +#define rb_method_basic_definition_p(...) rb_nonexistent_symbol(__VA_ARGS__) + + +/* MRI debug support */ + +/* gc.c */ +void rb_obj_info_dump(VALUE obj); +void rb_obj_info_dump_loc(VALUE obj, const char *file, int line, const char *func); + +/* debug.c */ + +RUBY_SYMBOL_EXPORT_BEGIN +void ruby_debug_breakpoint(void); +PRINTF_ARGS(void ruby_debug_printf(const char*, ...), 1, 2); +RUBY_SYMBOL_EXPORT_END + +// show obj data structure without any side-effect +#define rp(obj) rb_obj_info_dump_loc((VALUE)(obj), __FILE__, __LINE__, RUBY_FUNCTION_NAME_STRING) + +// same as rp, but add message header +#define rp_m(msg, obj) do { \ + fputs((msg), stderr); \ + rb_obj_info_dump((VALUE)(obj)); \ +} while (0) + +// `ruby_debug_breakpoint()` does nothing, +// but breakpoint is set in run.gdb, so `make gdb` can stop here. +#define bp() ruby_debug_breakpoint() + +#define RBOOL(v) ((v) ? Qtrue : Qfalse) +#define RB_BIGNUM_TYPE_P(x) RB_TYPE_P((x), T_BIGNUM) + +#ifndef __MINGW32__ +#undef memcpy +#define memcpy ruby_nonempty_memcpy +#endif +#endif /* RUBY_INTERNAL_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/array.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/array.h new file mode 100644 index 0000000..3a68964 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/array.h @@ -0,0 +1,154 @@ +#ifndef INTERNAL_ARRAY_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_ARRAY_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Array. + */ +#include "ruby/internal/config.h" +#include /* for size_t */ +#include "internal/static_assert.h" /* for STATIC_ASSERT */ +#include "ruby/internal/stdbool.h" /* for bool */ +#include "ruby/ruby.h" /* for RARRAY_LEN */ + +#ifndef ARRAY_DEBUG +# define ARRAY_DEBUG (0+RUBY_DEBUG) +#endif + +#define RARRAY_SHARED_FLAG ELTS_SHARED +#define RARRAY_SHARED_ROOT_FLAG FL_USER12 +#define RARRAY_PTR_IN_USE_FLAG FL_USER14 + +/* array.c */ +VALUE rb_ary_hash_values(long len, const VALUE *elements); +VALUE rb_ary_last(int, const VALUE *, VALUE); +void rb_ary_set_len(VALUE, long); +void rb_ary_delete_same(VALUE, VALUE); +VALUE rb_ary_hidden_new_fill(long capa); +VALUE rb_ary_at(VALUE, VALUE); +size_t rb_ary_memsize(VALUE); +VALUE rb_to_array_type(VALUE obj); +VALUE rb_to_array(VALUE obj); +void rb_ary_cancel_sharing(VALUE ary); +size_t rb_ary_size_as_embedded(VALUE ary); +void rb_ary_make_embedded(VALUE ary); +bool rb_ary_embeddable_p(VALUE ary); +VALUE rb_ary_diff(VALUE ary1, VALUE ary2); +RUBY_EXTERN VALUE rb_cArray_empty_frozen; + +static inline VALUE rb_ary_entry_internal(VALUE ary, long offset); +static inline bool ARY_PTR_USING_P(VALUE ary); + +VALUE rb_ary_tmp_new_from_values(VALUE, long, const VALUE *); +VALUE rb_check_to_array(VALUE ary); +VALUE rb_ary_behead(VALUE, long); +VALUE rb_ary_aref1(VALUE ary, VALUE i); + +struct rb_execution_context_struct; +VALUE rb_ec_ary_new_from_values(struct rb_execution_context_struct *ec, long n, const VALUE *elts); + +// YJIT needs this function to never allocate and never raise +static inline VALUE +rb_ary_entry_internal(VALUE ary, long offset) +{ + long len = RARRAY_LEN(ary); + const VALUE *ptr = RARRAY_CONST_PTR(ary); + if (len == 0) return Qnil; + if (offset < 0) { + offset += len; + if (offset < 0) return Qnil; + } + else if (len <= offset) { + return Qnil; + } + return ptr[offset]; +} + +static inline bool +ARY_PTR_USING_P(VALUE ary) +{ + return FL_TEST_RAW(ary, RARRAY_PTR_IN_USE_FLAG); +} + +RBIMPL_ATTR_MAYBE_UNUSED() +static inline int +ary_should_not_be_shared_and_embedded(VALUE ary) +{ + return !FL_ALL_RAW(ary, RARRAY_SHARED_FLAG|RARRAY_EMBED_FLAG); +} + +static inline bool +ARY_SHARED_P(VALUE ary) +{ + assert(RB_TYPE_P(ary, T_ARRAY)); + assert(ary_should_not_be_shared_and_embedded(ary)); + return FL_TEST_RAW(ary, RARRAY_SHARED_FLAG); +} + +static inline bool +ARY_EMBED_P(VALUE ary) +{ + assert(RB_TYPE_P(ary, T_ARRAY)); + assert(ary_should_not_be_shared_and_embedded(ary)); + return FL_TEST_RAW(ary, RARRAY_EMBED_FLAG); +} + +static inline VALUE +ARY_SHARED_ROOT(VALUE ary) +{ + assert(ARY_SHARED_P(ary)); + return RARRAY(ary)->as.heap.aux.shared_root; +} + +static inline bool +ARY_SHARED_ROOT_P(VALUE ary) +{ + assert(RB_TYPE_P(ary, T_ARRAY)); + return FL_TEST_RAW(ary, RARRAY_SHARED_ROOT_FLAG); +} + +static inline long +ARY_SHARED_ROOT_REFCNT(VALUE ary) +{ + assert(ARY_SHARED_ROOT_P(ary)); + return RARRAY(ary)->as.heap.aux.capa; +} + +#undef rb_ary_new_from_args +#if RBIMPL_HAS_WARNING("-Wgnu-zero-variadic-macro-arguments") +# /* Skip it; clang -pedantic doesn't like the following */ +#elif defined(__GNUC__) && defined(HAVE_VA_ARGS_MACRO) +#define rb_ary_new_from_args(n, ...) \ + __extension__ ({ \ + const VALUE args_to_new_ary[] = {__VA_ARGS__}; \ + if (__builtin_constant_p(n)) { \ + STATIC_ASSERT(rb_ary_new_from_args, numberof(args_to_new_ary) == (n)); \ + } \ + rb_ary_new_from_values(numberof(args_to_new_ary), args_to_new_ary); \ + }) +#endif + +#undef RARRAY_AREF +RBIMPL_ATTR_PURE_UNLESS_DEBUG() +RBIMPL_ATTR_ARTIFICIAL() +static inline VALUE +RARRAY_AREF(VALUE ary, long i) +{ + VALUE val; + RBIMPL_ASSERT_TYPE(ary, RUBY_T_ARRAY); + + RUBY_ASSERT(i < RARRAY_LEN(ary)); + + RBIMPL_WARNING_PUSH(); +#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ == 13 + RBIMPL_WARNING_IGNORED(-Warray-bounds); +#endif + val = RARRAY_CONST_PTR(ary)[i]; + RBIMPL_WARNING_POP(); + return val; +} + +#endif /* INTERNAL_ARRAY_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/basic_operators.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/basic_operators.h new file mode 100644 index 0000000..5dc8d7f --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/basic_operators.h @@ -0,0 +1,65 @@ +#ifndef INTERNAL_BOP_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_BOP_H + +#include "internal.h" +#include "ruby/internal/dllexport.h" + +enum ruby_basic_operators { + BOP_PLUS, + BOP_MINUS, + BOP_MULT, + BOP_DIV, + BOP_MOD, + BOP_EQ, + BOP_EQQ, + BOP_LT, + BOP_LE, + BOP_LTLT, + BOP_AREF, + BOP_ASET, + BOP_LENGTH, + BOP_SIZE, + BOP_EMPTY_P, + BOP_NIL_P, + BOP_SUCC, + BOP_GT, + BOP_GE, + BOP_NOT, + BOP_NEQ, + BOP_MATCH, + BOP_FREEZE, + BOP_UMINUS, + BOP_MAX, + BOP_MIN, + BOP_HASH, + BOP_CALL, + BOP_AND, + BOP_OR, + BOP_CMP, + BOP_DEFAULT, + BOP_PACK, + BOP_INCLUDE_P, + + BOP_LAST_ +}; + +RUBY_EXTERN short ruby_vm_redefined_flag[BOP_LAST_]; + +/* optimize insn */ +#define INTEGER_REDEFINED_OP_FLAG (1 << 0) +#define FLOAT_REDEFINED_OP_FLAG (1 << 1) +#define STRING_REDEFINED_OP_FLAG (1 << 2) +#define ARRAY_REDEFINED_OP_FLAG (1 << 3) +#define HASH_REDEFINED_OP_FLAG (1 << 4) +/* #define BIGNUM_REDEFINED_OP_FLAG (1 << 5) */ +#define SYMBOL_REDEFINED_OP_FLAG (1 << 6) +#define TIME_REDEFINED_OP_FLAG (1 << 7) +#define REGEXP_REDEFINED_OP_FLAG (1 << 8) +#define NIL_REDEFINED_OP_FLAG (1 << 9) +#define TRUE_REDEFINED_OP_FLAG (1 << 10) +#define FALSE_REDEFINED_OP_FLAG (1 << 11) +#define PROC_REDEFINED_OP_FLAG (1 << 12) + +#define BASIC_OP_UNREDEFINED_P(op, klass) (LIKELY((ruby_vm_redefined_flag[(op)]&(klass)) == 0)) + +#endif diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/bignum.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/bignum.h new file mode 100644 index 0000000..0ba21a4 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/bignum.h @@ -0,0 +1,245 @@ +#ifndef INTERNAL_BIGNUM_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_BIGNUM_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Bignums. + */ +#include "ruby/internal/config.h" /* for HAVE_LIBGMP */ +#include /* for size_t */ + +#ifdef HAVE_SYS_TYPES_H +# include /* for ssize_t (note: on Windows ssize_t is */ +#endif /* `#define`d in ruby/config.h) */ + +#include "ruby/internal/stdbool.h" /* for bool */ +#include "ruby/ruby.h" /* for struct RBasic */ + +#ifndef BDIGIT +# if SIZEOF_INT*2 <= SIZEOF_LONG_LONG +# define BDIGIT unsigned int +# define SIZEOF_BDIGIT SIZEOF_INT +# define BDIGIT_DBL unsigned LONG_LONG +# define BDIGIT_DBL_SIGNED LONG_LONG +# define PRI_BDIGIT_PREFIX "" +# define PRI_BDIGIT_DBL_PREFIX PRI_LL_PREFIX +# elif SIZEOF_INT*2 <= SIZEOF_LONG +# define BDIGIT unsigned int +# define SIZEOF_BDIGIT SIZEOF_INT +# define BDIGIT_DBL unsigned long +# define BDIGIT_DBL_SIGNED long +# define PRI_BDIGIT_PREFIX "" +# define PRI_BDIGIT_DBL_PREFIX "l" +# elif SIZEOF_SHORT*2 <= SIZEOF_LONG +# define BDIGIT unsigned short +# define SIZEOF_BDIGIT SIZEOF_SHORT +# define BDIGIT_DBL unsigned long +# define BDIGIT_DBL_SIGNED long +# define PRI_BDIGIT_PREFIX "h" +# define PRI_BDIGIT_DBL_PREFIX "l" +# else +# define BDIGIT unsigned short +# define SIZEOF_BDIGIT (SIZEOF_LONG/2) +# define SIZEOF_ACTUAL_BDIGIT SIZEOF_LONG +# define BDIGIT_DBL unsigned long +# define BDIGIT_DBL_SIGNED long +# define PRI_BDIGIT_PREFIX "h" +# define PRI_BDIGIT_DBL_PREFIX "l" +# endif +#endif + +#ifndef SIZEOF_ACTUAL_BDIGIT +# define SIZEOF_ACTUAL_BDIGIT SIZEOF_BDIGIT +#endif + +#ifdef PRI_BDIGIT_PREFIX +# define PRIdBDIGIT PRI_BDIGIT_PREFIX"d" +# define PRIiBDIGIT PRI_BDIGIT_PREFIX"i" +# define PRIoBDIGIT PRI_BDIGIT_PREFIX"o" +# define PRIuBDIGIT PRI_BDIGIT_PREFIX"u" +# define PRIxBDIGIT PRI_BDIGIT_PREFIX"x" +# define PRIXBDIGIT PRI_BDIGIT_PREFIX"X" +#endif + +#ifdef PRI_BDIGIT_DBL_PREFIX +# define PRIdBDIGIT_DBL PRI_BDIGIT_DBL_PREFIX"d" +# define PRIiBDIGIT_DBL PRI_BDIGIT_DBL_PREFIX"i" +# define PRIoBDIGIT_DBL PRI_BDIGIT_DBL_PREFIX"o" +# define PRIuBDIGIT_DBL PRI_BDIGIT_DBL_PREFIX"u" +# define PRIxBDIGIT_DBL PRI_BDIGIT_DBL_PREFIX"x" +# define PRIXBDIGIT_DBL PRI_BDIGIT_DBL_PREFIX"X" +#endif + +#define RBIGNUM(obj) ((struct RBignum *)(obj)) +#define BIGNUM_SIGN_BIT FL_USER1 +#define BIGNUM_EMBED_FLAG ((VALUE)FL_USER2) +#define BIGNUM_EMBED_LEN_NUMBITS 3 +#define BIGNUM_EMBED_LEN_MASK \ + (~(~(VALUE)0U << BIGNUM_EMBED_LEN_NUMBITS) << BIGNUM_EMBED_LEN_SHIFT) +#define BIGNUM_EMBED_LEN_SHIFT \ + (FL_USHIFT+3) /* bit offset of BIGNUM_EMBED_LEN_MASK */ +#ifndef BIGNUM_EMBED_LEN_MAX +# if (SIZEOF_VALUE*RBIMPL_RVALUE_EMBED_LEN_MAX/SIZEOF_ACTUAL_BDIGIT) < (1 << BIGNUM_EMBED_LEN_NUMBITS)-1 +# define BIGNUM_EMBED_LEN_MAX (SIZEOF_VALUE*RBIMPL_RVALUE_EMBED_LEN_MAX/SIZEOF_ACTUAL_BDIGIT) +# else +# define BIGNUM_EMBED_LEN_MAX ((1 << BIGNUM_EMBED_LEN_NUMBITS)-1) +# endif +#endif + +enum rb_int_parse_flags { + RB_INT_PARSE_SIGN = 0x01, + RB_INT_PARSE_UNDERSCORE = 0x02, + RB_INT_PARSE_PREFIX = 0x04, + RB_INT_PARSE_ALL = 0x07, + RB_INT_PARSE_DEFAULT = 0x07, +}; + +struct RBignum { + struct RBasic basic; + union { + struct { + size_t len; + BDIGIT *digits; + } heap; + BDIGIT ary[BIGNUM_EMBED_LEN_MAX]; + } as; +}; + +/* bignum.c */ +extern const char ruby_digitmap[]; +double rb_big_fdiv_double(VALUE x, VALUE y); +VALUE rb_big_uminus(VALUE x); +VALUE rb_big_hash(VALUE); +VALUE rb_big_odd_p(VALUE); +VALUE rb_big_even_p(VALUE); +size_t rb_big_size(VALUE); +VALUE rb_integer_float_cmp(VALUE x, VALUE y); +VALUE rb_integer_float_eq(VALUE x, VALUE y); +VALUE rb_str_convert_to_inum(VALUE str, int base, int badcheck, int raise_exception); +VALUE rb_big_comp(VALUE x); +VALUE rb_big_aref(VALUE x, VALUE y); +VALUE rb_big_aref2(VALUE num, VALUE beg, VALUE len); +VALUE rb_big_abs(VALUE x); +VALUE rb_big_size_m(VALUE big); +VALUE rb_big_bit_length(VALUE big); +VALUE rb_big_remainder(VALUE x, VALUE y); +VALUE rb_big_gt(VALUE x, VALUE y); +VALUE rb_big_ge(VALUE x, VALUE y); +VALUE rb_big_lt(VALUE x, VALUE y); +VALUE rb_big_le(VALUE x, VALUE y); +VALUE rb_int_powm(int const argc, VALUE * const argv, VALUE const num); +VALUE rb_big_isqrt(VALUE n); +static inline bool BIGNUM_SIGN(VALUE b); +static inline bool BIGNUM_POSITIVE_P(VALUE b); +static inline bool BIGNUM_NEGATIVE_P(VALUE b); +static inline void BIGNUM_SET_SIGN(VALUE b, bool sign); +static inline void BIGNUM_NEGATE(VALUE b); +static inline size_t BIGNUM_LEN(VALUE b); +static inline BDIGIT *BIGNUM_DIGITS(VALUE b); +static inline int BIGNUM_LENINT(VALUE b); +static inline bool BIGNUM_EMBED_P(VALUE b); + +RUBY_SYMBOL_EXPORT_BEGIN +/* bignum.c (export) */ +VALUE rb_big_mul_normal(VALUE x, VALUE y); +VALUE rb_big_mul_balance(VALUE x, VALUE y); +VALUE rb_big_mul_karatsuba(VALUE x, VALUE y); +VALUE rb_big_mul_toom3(VALUE x, VALUE y); +VALUE rb_big_sq_fast(VALUE x); +VALUE rb_big_divrem_normal(VALUE x, VALUE y); +VALUE rb_big2str_poweroftwo(VALUE x, int base); +VALUE rb_big2str_generic(VALUE x, int base); +VALUE rb_str2big_poweroftwo(VALUE arg, int base, int badcheck); +VALUE rb_str2big_normal(VALUE arg, int base, int badcheck); +VALUE rb_str2big_karatsuba(VALUE arg, int base, int badcheck); +#if defined(HAVE_LIBGMP) && defined(HAVE_GMP_H) +VALUE rb_big_mul_gmp(VALUE x, VALUE y); +VALUE rb_big_divrem_gmp(VALUE x, VALUE y); +VALUE rb_big2str_gmp(VALUE x, int base); +VALUE rb_str2big_gmp(VALUE arg, int base, int badcheck); +#endif +VALUE rb_int_parse_cstr(const char *str, ssize_t len, char **endp, size_t *ndigits, int base, int flags); +RUBY_SYMBOL_EXPORT_END + +#if defined(HAVE_INT128_T) +VALUE rb_int128t2big(int128_t n); +#endif + +/* sign: positive:1, negative:0 */ +static inline bool +BIGNUM_SIGN(VALUE b) +{ + return FL_TEST_RAW(b, BIGNUM_SIGN_BIT); +} + +static inline bool +BIGNUM_POSITIVE_P(VALUE b) +{ + return BIGNUM_SIGN(b); +} + +static inline bool +BIGNUM_NEGATIVE_P(VALUE b) +{ + return ! BIGNUM_POSITIVE_P(b); +} + +static inline void +BIGNUM_SET_SIGN(VALUE b, bool sign) +{ + if (sign) { + FL_SET_RAW(b, BIGNUM_SIGN_BIT); + } + else { + FL_UNSET_RAW(b, BIGNUM_SIGN_BIT); + } +} + +static inline void +BIGNUM_NEGATE(VALUE b) +{ + FL_REVERSE_RAW(b, BIGNUM_SIGN_BIT); +} + +static inline size_t +BIGNUM_LEN(VALUE b) +{ + if (! BIGNUM_EMBED_P(b)) { + return RBIGNUM(b)->as.heap.len; + } + else { + size_t ret = RBASIC(b)->flags; + ret &= BIGNUM_EMBED_LEN_MASK; + ret >>= BIGNUM_EMBED_LEN_SHIFT; + return ret; + } +} + +static inline int +BIGNUM_LENINT(VALUE b) +{ + return rb_long2int(BIGNUM_LEN(b)); +} + +/* LSB:BIGNUM_DIGITS(b)[0], MSB:BIGNUM_DIGITS(b)[BIGNUM_LEN(b)-1] */ +static inline BDIGIT * +BIGNUM_DIGITS(VALUE b) +{ + if (BIGNUM_EMBED_P(b)) { + return RBIGNUM(b)->as.ary; + } + else { + return RBIGNUM(b)->as.heap.digits; + } +} + +static inline bool +BIGNUM_EMBED_P(VALUE b) +{ + return FL_TEST_RAW(b, BIGNUM_EMBED_FLAG); +} + +#endif /* INTERNAL_BIGNUM_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/bits.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/bits.h new file mode 100644 index 0000000..2b5aecf --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/bits.h @@ -0,0 +1,650 @@ +#ifndef INTERNAL_BITS_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_BITS_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for bitwise integer algorithms. + * @see Henry S. Warren Jr., "Hacker's Delight" (2nd ed.), 2013. + * @see SEI CERT C Coding Standard INT32-C. "Ensure that operations on + * signed integers do not result in overflow" + * @see https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html + * @see https://clang.llvm.org/docs/LanguageExtensions.html#builtin-rotateleft + * @see https://clang.llvm.org/docs/LanguageExtensions.html#builtin-rotateright + * @see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/byteswap-uint64-byteswap-ulong-byteswap-ushort + * @see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/rotl-rotl64-rotr-rotr64 + * @see https://docs.microsoft.com/en-us/cpp/intrinsics/bitscanforward-bitscanforward64 + * @see https://docs.microsoft.com/en-us/cpp/intrinsics/bitscanreverse-bitscanreverse64 + * @see https://docs.microsoft.com/en-us/cpp/intrinsics/lzcnt16-lzcnt-lzcnt64 + * @see https://docs.microsoft.com/en-us/cpp/intrinsics/popcnt16-popcnt-popcnt64 + * @see https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_lzcnt_u32 + * @see https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_tzcnt_u32 + * @see https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_rotl64 + * @see https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_rotr64 + * @see https://stackoverflow.com/a/776523 + */ +#include "ruby/internal/config.h" +#include /* for CHAR_BITS */ +#include /* for uintptr_t */ +#include "internal/compilers.h" /* for MSC_VERSION_SINCE */ + +#if MSC_VERSION_SINCE(1310) +# include /* for _byteswap_uint64 */ +#endif + +#if defined(HAVE_X86INTRIN_H) +# include /* for _lzcnt_u64 */ +#elif MSC_VERSION_SINCE(1310) +# include /* for the following intrinsics */ +#endif + +#if defined(_MSC_VER) && defined(__AVX__) +# pragma intrinsic(__popcnt) +# pragma intrinsic(__popcnt64) +#endif + +#if defined(_MSC_VER) && defined(__AVX2__) +# pragma intrinsic(__lzcnt) +# pragma intrinsic(__lzcnt64) +#endif + +#if MSC_VERSION_SINCE(1310) +# pragma intrinsic(_rotl) +# pragma intrinsic(_rotr) +# ifdef _WIN64 +# pragma intrinsic(_rotl64) +# pragma intrinsic(_rotr64) +# endif +#endif + +#if MSC_VERSION_SINCE(1400) +# pragma intrinsic(_BitScanForward) +# pragma intrinsic(_BitScanReverse) +# ifdef _WIN64 +# pragma intrinsic(_BitScanForward64) +# pragma intrinsic(_BitScanReverse64) +# endif +#endif + +#include "ruby/ruby.h" /* for VALUE */ +#include "internal/static_assert.h" /* for STATIC_ASSERT */ + +/* The most significant bit of the lower part of half-long integer. + * If sizeof(long) == 4, this is 0x8000. + * If sizeof(long) == 8, this is 0x80000000. + */ +#define HALF_LONG_MSB ((SIGNED_VALUE)1<<((SIZEOF_LONG*CHAR_BIT-1)/2)) + +#define SIGNED_INTEGER_TYPE_P(T) (0 > ((T)0)-1) + +#define SIGNED_INTEGER_MIN(T) \ + ((sizeof(T) == sizeof(int8_t)) ? ((T)INT8_MIN) : \ + ((sizeof(T) == sizeof(int16_t)) ? ((T)INT16_MIN) : \ + ((sizeof(T) == sizeof(int32_t)) ? ((T)INT32_MIN) : \ + ((sizeof(T) == sizeof(int64_t)) ? ((T)INT64_MIN) : \ + 0)))) + +#define SIGNED_INTEGER_MAX(T) ((T)(SIGNED_INTEGER_MIN(T) ^ ((T)~(T)0))) + +#define UNSIGNED_INTEGER_MAX(T) ((T)~(T)0) + +#ifndef MUL_OVERFLOW_SIGNED_INTEGER_P +#if __has_builtin(__builtin_mul_overflow_p) +# define MUL_OVERFLOW_P(a, b) \ + __builtin_mul_overflow_p((a), (b), (__typeof__(a * b))0) +#elif __has_builtin(__builtin_mul_overflow) +# define MUL_OVERFLOW_P(a, b) \ + __extension__ ({ __typeof__(a) c; __builtin_mul_overflow((a), (b), &c); }) +#endif + +#define MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, min, max) ( \ + (a) == 0 ? 0 : \ + (a) == -1 ? (b) < -(max) : \ + (a) > 0 ? \ + ((b) > 0 ? (max) / (a) < (b) : (min) / (a) > (b)) : \ + ((b) > 0 ? (min) / (a) < (b) : (max) / (a) > (b))) + +#if __has_builtin(__builtin_mul_overflow_p) +/* __builtin_mul_overflow_p can take bitfield */ +/* and GCC permits bitfields for integers other than int */ +# define MUL_OVERFLOW_FIXNUM_P(a, b) \ + __extension__ ({ \ + struct { long fixnum : sizeof(long) * CHAR_BIT - 1; } c = { 0 }; \ + __builtin_mul_overflow_p((a), (b), c.fixnum); \ + }) +#else +# define MUL_OVERFLOW_FIXNUM_P(a, b) \ + MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, FIXNUM_MIN, FIXNUM_MAX) +#endif + +#if defined(MUL_OVERFLOW_P) && defined(USE___BUILTIN_MUL_OVERFLOW_LONG_LONG) +# define MUL_OVERFLOW_LONG_LONG_P(a, b) MUL_OVERFLOW_P(a, b) +#else +# define MUL_OVERFLOW_LONG_LONG_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, LLONG_MIN, LLONG_MAX) +#endif + +#ifdef MUL_OVERFLOW_P +# define MUL_OVERFLOW_LONG_P(a, b) MUL_OVERFLOW_P(a, b) +# define MUL_OVERFLOW_INT_P(a, b) MUL_OVERFLOW_P(a, b) +#else +# define MUL_OVERFLOW_LONG_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, LONG_MIN, LONG_MAX) +# define MUL_OVERFLOW_INT_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, INT_MIN, INT_MAX) +#endif +#endif + +#ifndef ADD_OVERFLOW_SIGNED_INTEGER_P +#if __has_builtin(__builtin_add_overflow_p) +# define ADD_OVERFLOW_P(a, b) \ + __builtin_add_overflow_p((a), (b), (__typeof__(a * b))0) +#elif __has_builtin(__builtin_add_overflow) +# define ADD_OVERFLOW_P(a, b) \ + __extension__ ({ __typeof__(a) c; __builtin_add_overflow((a), (b), &c); }) +#endif + +#define ADD_OVERFLOW_SIGNED_INTEGER_P(a, b, min, max) ( \ + (a) > 0 ? (b) > (max) - (a) : (b) < (min) - (a)) + +#if __has_builtin(__builtin_add_overflow_p) +/* __builtin_add_overflow_p can take bitfield */ +/* and GCC permits bitfields for integers other than int */ +# define ADD_OVERFLOW_FIXNUM_P(a, b) \ + __extension__ ({ \ + struct { long fixnum : sizeof(long) * CHAR_BIT - 1; } c = { 0 }; \ + __builtin_add_overflow_p((a), (b), c.fixnum); \ + }) +#else +# define ADD_OVERFLOW_FIXNUM_P(a, b) \ + ADD_OVERFLOW_SIGNED_INTEGER_P(a, b, FIXNUM_MIN, FIXNUM_MAX) +#endif + +#if defined(ADD_OVERFLOW_P) && defined(USE___BUILTIN_ADD_OVERFLOW_LONG_LONG) +# define ADD_OVERFLOW_LONG_LONG_P(a, b) ADD_OVERFLOW_P(a, b) +#else +# define ADD_OVERFLOW_LONG_LONG_P(a, b) ADD_OVERFLOW_SIGNED_INTEGER_P(a, b, LLONG_MIN, LLONG_MAX) +#endif + +#ifdef ADD_OVERFLOW_P +# define ADD_OVERFLOW_LONG_P(a, b) ADD_OVERFLOW_P(a, b) +# define ADD_OVERFLOW_INT_P(a, b) ADD_OVERFLOW_P(a, b) +#else +# define ADD_OVERFLOW_LONG_P(a, b) ADD_OVERFLOW_SIGNED_INTEGER_P(a, b, LONG_MIN, LONG_MAX) +# define ADD_OVERFLOW_INT_P(a, b) ADD_OVERFLOW_SIGNED_INTEGER_P(a, b, INT_MIN, INT_MAX) +#endif +#endif + +#ifndef SUB_OVERFLOW_SIGNED_INTEGER_P +#if __has_builtin(__builtin_sub_overflow_p) +# define SUB_OVERFLOW_P(a, b) \ + __builtin_sub_overflow_p((a), (b), (__typeof__(a * b))0) +#elif __has_builtin(__builtin_sub_overflow) +# define SUB_OVERFLOW_P(a, b) \ + __extension__ ({ __typeof__(a) c; __builtin_sub_overflow((a), (b), &c); }) +#endif + +#define SUB_OVERFLOW_SIGNED_INTEGER_P(a, b, min, max) ( \ + (b) > 0 ? (a) < (min) + (b) : (a) > (max) + (b)) + +#if __has_builtin(__builtin_sub_overflow_p) +/* __builtin_sub_overflow_p can take bitfield */ +/* and GCC permits bitfields for integers other than int */ +# define SUB_OVERFLOW_FIXNUM_P(a, b) \ + __extension__ ({ \ + struct { long fixnum : sizeof(long) * CHAR_BIT - 1; } c = { 0 }; \ + __builtin_sub_overflow_p((a), (b), c.fixnum); \ + }) +#else +# define SUB_OVERFLOW_FIXNUM_P(a, b) \ + SUB_OVERFLOW_SIGNED_INTEGER_P(a, b, FIXNUM_MIN, FIXNUM_MAX) +#endif + +#if defined(SUB_OVERFLOW_P) && defined(USE___BUILTIN_SUB_OVERFLOW_LONG_LONG) +# define SUB_OVERFLOW_LONG_LONG_P(a, b) SUB_OVERFLOW_P(a, b) +#else +# define SUB_OVERFLOW_LONG_LONG_P(a, b) SUB_OVERFLOW_SIGNED_INTEGER_P(a, b, LLONG_MIN, LLONG_MAX) +#endif + +#ifdef SUB_OVERFLOW_P +# define SUB_OVERFLOW_LONG_P(a, b) SUB_OVERFLOW_P(a, b) +# define SUB_OVERFLOW_INT_P(a, b) SUB_OVERFLOW_P(a, b) +#else +# define SUB_OVERFLOW_LONG_P(a, b) SUB_OVERFLOW_SIGNED_INTEGER_P(a, b, LONG_MIN, LONG_MAX) +# define SUB_OVERFLOW_INT_P(a, b) SUB_OVERFLOW_SIGNED_INTEGER_P(a, b, INT_MIN, INT_MAX) +#endif +#endif + +#ifdef HAVE_UINT128_T +# define bit_length(x) \ + (unsigned int) \ + (sizeof(x) <= sizeof(int32_t) ? 32 - nlz_int32((uint32_t)(x)) : \ + sizeof(x) <= sizeof(int64_t) ? 64 - nlz_int64((uint64_t)(x)) : \ + 128 - nlz_int128((uint128_t)(x))) +#else +# define bit_length(x) \ + (unsigned int) \ + (sizeof(x) <= sizeof(int32_t) ? 32 - nlz_int32((uint32_t)(x)) : \ + 64 - nlz_int64((uint64_t)(x))) +#endif + +#ifndef swap16 +# define swap16 ruby_swap16 +#endif + +#ifndef swap32 +# define swap32 ruby_swap32 +#endif + +#ifndef swap64 +# define swap64 ruby_swap64 +#endif + +static inline uint16_t ruby_swap16(uint16_t); +static inline uint32_t ruby_swap32(uint32_t); +static inline uint64_t ruby_swap64(uint64_t); +static inline unsigned nlz_int(unsigned x); +static inline unsigned nlz_long(unsigned long x); +static inline unsigned nlz_long_long(unsigned long long x); +static inline unsigned nlz_intptr(uintptr_t x); +static inline unsigned nlz_int32(uint32_t x); +static inline unsigned nlz_int64(uint64_t x); +#ifdef HAVE_UINT128_T +static inline unsigned nlz_int128(uint128_t x); +#endif +static inline unsigned rb_popcount32(uint32_t x); +static inline unsigned rb_popcount64(uint64_t x); +static inline unsigned rb_popcount_intptr(uintptr_t x); +static inline int ntz_int32(uint32_t x); +static inline int ntz_int64(uint64_t x); +static inline int ntz_intptr(uintptr_t x); +static inline VALUE RUBY_BIT_ROTL(VALUE, int); +static inline VALUE RUBY_BIT_ROTR(VALUE, int); + +static inline uint16_t +ruby_swap16(uint16_t x) +{ +#if __has_builtin(__builtin_bswap16) + return __builtin_bswap16(x); + +#elif MSC_VERSION_SINCE(1310) + return _byteswap_ushort(x); + +#else + return (x << 8) | (x >> 8); + +#endif +} + +static inline uint32_t +ruby_swap32(uint32_t x) +{ +#if __has_builtin(__builtin_bswap32) + return __builtin_bswap32(x); + +#elif MSC_VERSION_SINCE(1310) + return _byteswap_ulong(x); + +#else + x = ((x & 0x0000FFFF) << 16) | ((x & 0xFFFF0000) >> 16); + x = ((x & 0x00FF00FF) << 8) | ((x & 0xFF00FF00) >> 8); + return x; + +#endif +} + +static inline uint64_t +ruby_swap64(uint64_t x) +{ +#if __has_builtin(__builtin_bswap64) + return __builtin_bswap64(x); + +#elif MSC_VERSION_SINCE(1310) + return _byteswap_uint64(x); + +#else + x = ((x & 0x00000000FFFFFFFFULL) << 32) | ((x & 0xFFFFFFFF00000000ULL) >> 32); + x = ((x & 0x0000FFFF0000FFFFULL) << 16) | ((x & 0xFFFF0000FFFF0000ULL) >> 16); + x = ((x & 0x00FF00FF00FF00FFULL) << 8) | ((x & 0xFF00FF00FF00FF00ULL) >> 8); + return x; + +#endif +} + +static inline unsigned int +nlz_int32(uint32_t x) +{ +#if defined(_MSC_VER) && defined(__AVX2__) + /* Note: It seems there is no such thing like __LZCNT__ predefined in MSVC. + * AMD CPUs have had this instruction for decades (since K10) but for + * Intel, Haswell is the oldest one. We need to use __AVX2__ for maximum + * safety. */ + return (unsigned int)__lzcnt(x); + +#elif defined(__x86_64__) && defined(__LZCNT__) + return (unsigned int)_lzcnt_u32(x); + +#elif MSC_VERSION_SINCE(1400) /* &&! defined(__AVX2__) */ + unsigned long r; + return _BitScanReverse(&r, x) ? (31 - (int)r) : 32; + +#elif __has_builtin(__builtin_clz) + STATIC_ASSERT(sizeof_int, sizeof(int) * CHAR_BIT == 32); + return x ? (unsigned int)__builtin_clz(x) : 32; + +#else + uint32_t y; + unsigned n = 32; + y = x >> 16; if (y) {n -= 16; x = y;} + y = x >> 8; if (y) {n -= 8; x = y;} + y = x >> 4; if (y) {n -= 4; x = y;} + y = x >> 2; if (y) {n -= 2; x = y;} + y = x >> 1; if (y) {return n - 2;} + return (unsigned int)(n - x); +#endif +} + +static inline unsigned int +nlz_int64(uint64_t x) +{ +#if defined(_MSC_VER) && defined(__AVX2__) + return (unsigned int)__lzcnt64(x); + +#elif defined(__x86_64__) && defined(__LZCNT__) + return (unsigned int)_lzcnt_u64(x); + +#elif defined(_WIN64) && MSC_VERSION_SINCE(1400) /* &&! defined(__AVX2__) */ + unsigned long r; + return _BitScanReverse64(&r, x) ? (63u - (unsigned int)r) : 64; + +#elif __has_builtin(__builtin_clzl) + if (x == 0) { + return 64; + } + else if (sizeof(long) * CHAR_BIT == 64) { + return (unsigned int)__builtin_clzl((unsigned long)x); + } + else if (sizeof(long long) * CHAR_BIT == 64) { + return (unsigned int)__builtin_clzll((unsigned long long)x); + } + else { + /* :FIXME: Is there a way to make this branch a compile-time error? */ + UNREACHABLE_RETURN(~0); + } + +#else + uint64_t y; + unsigned int n = 64; + y = x >> 32; if (y) {n -= 32; x = y;} + y = x >> 16; if (y) {n -= 16; x = y;} + y = x >> 8; if (y) {n -= 8; x = y;} + y = x >> 4; if (y) {n -= 4; x = y;} + y = x >> 2; if (y) {n -= 2; x = y;} + y = x >> 1; if (y) {return n - 2;} + return (unsigned int)(n - x); + +#endif +} + +#ifdef HAVE_UINT128_T +static inline unsigned int +nlz_int128(uint128_t x) +{ + uint64_t y = (uint64_t)(x >> 64); + + if (x == 0) { + return 128; + } + else if (y == 0) { + return (unsigned int)nlz_int64(x) + 64; + } + else { + return (unsigned int)nlz_int64(y); + } +} +#endif + +static inline unsigned int +nlz_int(unsigned int x) +{ + if (sizeof(unsigned int) * CHAR_BIT == 32) { + return nlz_int32((uint32_t)x); + } + else if (sizeof(unsigned int) * CHAR_BIT == 64) { + return nlz_int64((uint64_t)x); + } + else { + UNREACHABLE_RETURN(~0); + } +} + +static inline unsigned int +nlz_long(unsigned long x) +{ + if (sizeof(unsigned long) * CHAR_BIT == 32) { + return nlz_int32((uint32_t)x); + } + else if (sizeof(unsigned long) * CHAR_BIT == 64) { + return nlz_int64((uint64_t)x); + } + else { + UNREACHABLE_RETURN(~0); + } +} + +static inline unsigned int +nlz_long_long(unsigned long long x) +{ + if (sizeof(unsigned long long) * CHAR_BIT == 64) { + return nlz_int64((uint64_t)x); + } +#ifdef HAVE_UINT128_T + else if (sizeof(unsigned long long) * CHAR_BIT == 128) { + return nlz_int128((uint128_t)x); + } +#endif + else { + UNREACHABLE_RETURN(~0); + } +} + +static inline unsigned int +nlz_intptr(uintptr_t x) +{ + if (sizeof(uintptr_t) == sizeof(unsigned int)) { + return nlz_int((unsigned int)x); + } + if (sizeof(uintptr_t) == sizeof(unsigned long)) { + return nlz_long((unsigned long)x); + } + if (sizeof(uintptr_t) == sizeof(unsigned long long)) { + return nlz_long_long((unsigned long long)x); + } + else { + UNREACHABLE_RETURN(~0); + } +} + +static inline unsigned int +rb_popcount32(uint32_t x) +{ +#if defined(_MSC_VER) && defined(__AVX__) + /* Note: CPUs since Nehalem and Barcelona have had this instruction so SSE + * 4.2 should suffice, but it seems there is no such thing like __SSE_4_2__ + * predefined macro in MSVC. They do have __AVX__ so use it instead. */ + return (unsigned int)__popcnt(x); + +#elif __has_builtin(__builtin_popcount) + STATIC_ASSERT(sizeof_int, sizeof(int) * CHAR_BIT >= 32); + return (unsigned int)__builtin_popcount(x); + +#else + x = (x & 0x55555555) + (x >> 1 & 0x55555555); + x = (x & 0x33333333) + (x >> 2 & 0x33333333); + x = (x & 0x07070707) + (x >> 4 & 0x07070707); + x = (x & 0x000f000f) + (x >> 8 & 0x000f000f); + x = (x & 0x0000001f) + (x >>16 & 0x0000001f); + return (unsigned int)x; + +#endif +} + +static inline unsigned int +rb_popcount64(uint64_t x) +{ +#if defined(_MSC_VER) && defined(__AVX__) + return (unsigned int)__popcnt64(x); + +#elif __has_builtin(__builtin_popcount) + if (sizeof(long) * CHAR_BIT == 64) { + return (unsigned int)__builtin_popcountl((unsigned long)x); + } + else if (sizeof(long long) * CHAR_BIT == 64) { + return (unsigned int)__builtin_popcountll((unsigned long long)x); + } + else { + /* :FIXME: Is there a way to make this branch a compile-time error? */ + UNREACHABLE_RETURN(~0); + } + +#else + x = (x & 0x5555555555555555) + (x >> 1 & 0x5555555555555555); + x = (x & 0x3333333333333333) + (x >> 2 & 0x3333333333333333); + x = (x & 0x0707070707070707) + (x >> 4 & 0x0707070707070707); + x = (x & 0x000f000f000f000f) + (x >> 8 & 0x000f000f000f000f); + x = (x & 0x0000001f0000001f) + (x >>16 & 0x0000001f0000001f); + x = (x & 0x000000000000003f) + (x >>32 & 0x000000000000003f); + return (unsigned int)x; + +#endif +} + +static inline unsigned int +rb_popcount_intptr(uintptr_t x) +{ + if (sizeof(uintptr_t) * CHAR_BIT == 64) { + return rb_popcount64((uint64_t)x); + } + else if (sizeof(uintptr_t) * CHAR_BIT == 32) { + return rb_popcount32((uint32_t)x); + } + else { + UNREACHABLE_RETURN(~0); + } +} + +static inline int +ntz_int32(uint32_t x) +{ +#if defined(__x86_64__) && defined(__BMI__) + return (unsigned)_tzcnt_u32(x); + +#elif MSC_VERSION_SINCE(1400) + /* :FIXME: Is there any way to issue TZCNT instead of BSF, apart from using + * assembly? Because issuing LZCNT seems possible (see nlz.h). */ + unsigned long r; + return _BitScanForward(&r, x) ? (int)r : 32; + +#elif __has_builtin(__builtin_ctz) + STATIC_ASSERT(sizeof_int, sizeof(int) * CHAR_BIT == 32); + return x ? (unsigned)__builtin_ctz(x) : 32; + +#else + return rb_popcount32((~x) & (x-1)); + +#endif +} + +static inline int +ntz_int64(uint64_t x) +{ +#if defined(__x86_64__) && defined(__BMI__) + return (unsigned)_tzcnt_u64(x); + +#elif defined(_WIN64) && MSC_VERSION_SINCE(1400) + unsigned long r; + return _BitScanForward64(&r, x) ? (int)r : 64; + +#elif __has_builtin(__builtin_ctzl) + if (x == 0) { + return 64; + } + else if (sizeof(long) * CHAR_BIT == 64) { + return (unsigned)__builtin_ctzl((unsigned long)x); + } + else if (sizeof(long long) * CHAR_BIT == 64) { + return (unsigned)__builtin_ctzll((unsigned long long)x); + } + else { + /* :FIXME: Is there a way to make this branch a compile-time error? */ + UNREACHABLE_RETURN(~0); + } + +#else + return rb_popcount64((~x) & (x-1)); + +#endif +} + +static inline int +ntz_intptr(uintptr_t x) +{ + if (sizeof(uintptr_t) * CHAR_BIT == 64) { + return ntz_int64((uint64_t)x); + } + else if (sizeof(uintptr_t) * CHAR_BIT == 32) { + return ntz_int32((uint32_t)x); + } + else { + UNREACHABLE_RETURN(~0); + } +} + +static inline VALUE +RUBY_BIT_ROTL(VALUE v, int n) +{ +#if __has_builtin(__builtin_rotateleft32) && (SIZEOF_VALUE * CHAR_BIT == 32) + return __builtin_rotateleft32(v, n); + +#elif __has_builtin(__builtin_rotateleft64) && (SIZEOF_VALUE * CHAR_BIT == 64) + return __builtin_rotateleft64(v, n); + +#elif MSC_VERSION_SINCE(1310) && (SIZEOF_VALUE * CHAR_BIT == 32) + return _rotl(v, n); + +#elif MSC_VERSION_SINCE(1310) && (SIZEOF_VALUE * CHAR_BIT == 64) + return _rotl64(v, n); + +#elif defined(_lrotl) && (SIZEOF_VALUE == SIZEOF_LONG) + return _lrotl(v, n); + +#else + const int m = (sizeof(VALUE) * CHAR_BIT) - 1; + return (v << (n & m)) | (v >> (-n & m)); +#endif +} + +static inline VALUE +RUBY_BIT_ROTR(VALUE v, int n) +{ +#if __has_builtin(__builtin_rotateright32) && (SIZEOF_VALUE * CHAR_BIT == 32) + return __builtin_rotateright32(v, n); + +#elif __has_builtin(__builtin_rotateright64) && (SIZEOF_VALUE * CHAR_BIT == 64) + return __builtin_rotateright64(v, n); + +#elif MSC_VERSION_SINCE(1310) && (SIZEOF_VALUE * CHAR_BIT == 32) + return _rotr(v, n); + +#elif MSC_VERSION_SINCE(1310) && (SIZEOF_VALUE * CHAR_BIT == 64) + return _rotr64(v, n); + +#elif defined(_lrotr) && (SIZEOF_VALUE == SIZEOF_LONG) + return _lrotr(v, n); + +#else + const int m = (sizeof(VALUE) * CHAR_BIT) - 1; + return (v << (-n & m)) | (v >> (n & m)); +#endif +} + +#endif /* INTERNAL_BITS_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/box.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/box.h new file mode 100644 index 0000000..41cad63 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/box.h @@ -0,0 +1,81 @@ +#ifndef INTERNAL_BOX_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_BOX_H + +#include "ruby/ruby.h" /* for VALUE */ + +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Ruby Box. + */ +struct rb_box_struct { + /* + * To retrieve Ruby::Box object that provides #require and so on. + * That is used from load.c, etc., that uses rb_box_t internally. + */ + VALUE box_object; + long box_id; // box_id to generate ext filenames + + VALUE top_self; + + VALUE load_path; + VALUE load_path_snapshot; + VALUE load_path_check_cache; + VALUE expanded_load_path; + VALUE loaded_features; + VALUE loaded_features_snapshot; + VALUE loaded_features_realpaths; + VALUE loaded_features_realpath_map; + struct st_table *loaded_features_index; + struct st_table *loading_table; + VALUE ruby_dln_libmap; + + VALUE gvar_tbl; + + bool is_user; + bool is_optional; +}; +typedef struct rb_box_struct rb_box_t; + +#define BOX_OBJ_P(obj) (rb_obj_class(obj) == rb_cBox) + +#define BOX_ROOT_P(box) (box && !box->is_user) +#define BOX_USER_P(box) (box && box->is_user) +#define BOX_OPTIONAL_P(box) (box && box->is_optional) +#define BOX_MAIN_P(box) (box && box->is_user && !box->is_optional) + +#define BOX_METHOD_DEFINITION(mdef) (mdef ? mdef->ns : NULL) +#define BOX_METHOD_ENTRY(me) (me ? BOX_METHOD_DEFINITION(me->def) : NULL) +#define BOX_CC(cc) (cc ? BOX_METHOD_ENTRY(cc->cme_) : NULL) +#define BOX_CC_ENTRIES(ccs) (ccs ? BOX_METHOD_ENTRY(ccs->cme) : NULL) + +RUBY_EXTERN bool ruby_box_enabled; +RUBY_EXTERN bool ruby_box_init_done; +RUBY_EXTERN bool ruby_box_crashed; + +static inline bool +rb_box_available(void) +{ + return ruby_box_enabled; +} + +const rb_box_t * rb_root_box(void); +const rb_box_t * rb_main_box(void); +const rb_box_t * rb_current_box(void); +const rb_box_t * rb_loading_box(void); +const rb_box_t * rb_current_box_in_crash_report(void); + +void rb_box_entry_mark(void *); +void rb_box_gc_update_references(void *ptr); + +rb_box_t * rb_get_box_t(VALUE ns); +VALUE rb_get_box_object(rb_box_t *ns); + +VALUE rb_box_local_extension(VALUE box, VALUE fname, VALUE path); + +void rb_initialize_main_box(void); +void rb_box_init_done(void); +#endif /* INTERNAL_BOX_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/class.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/class.h new file mode 100644 index 0000000..f122d2f --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/class.h @@ -0,0 +1,805 @@ +#ifndef INTERNAL_CLASS_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_CLASS_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Class. + */ +#include "id.h" +#include "id_table.h" /* for struct rb_id_table */ +#include "internal/box.h" +#include "internal/serial.h" /* for rb_serial_t */ +#include "internal/static_assert.h" +#include "internal/variable.h" /* for rb_class_ivar_set */ +#include "ruby/internal/stdbool.h" /* for bool */ +#include "ruby/intern.h" /* for rb_alloc_func_t */ +#include "ruby/ruby.h" /* for struct RBasic */ +#include "shape.h" +#include "ruby_assert.h" +#include "vm_core.h" +#include "vm_sync.h" +#include "method.h" /* for rb_cref_t */ + +#ifdef RCLASS_SUPER +# undef RCLASS_SUPER +#endif + +struct rb_box_subclasses { + long refcount; + struct st_table *tbl; +}; +typedef struct rb_box_subclasses rb_box_subclasses_t; + +static inline long +rb_box_subclasses_ref_count(rb_box_subclasses_t *box_sub) +{ + return box_sub->refcount; +} + +static inline rb_box_subclasses_t * +rb_box_subclasses_ref_inc(rb_box_subclasses_t *box_sub) +{ + box_sub->refcount++; + return box_sub; +} + +static inline void +rb_box_subclasses_ref_dec(rb_box_subclasses_t *box_sub) +{ + box_sub->refcount--; + if (box_sub->refcount == 0) { + st_free_table(box_sub->tbl); + xfree(box_sub); + } +} + +struct rb_subclass_anchor { + rb_box_subclasses_t *box_subclasses; + struct rb_subclass_entry *head; +}; +typedef struct rb_subclass_anchor rb_subclass_anchor_t; + +struct rb_subclass_entry { + VALUE klass; + struct rb_subclass_entry *next; + struct rb_subclass_entry *prev; +}; +typedef struct rb_subclass_entry rb_subclass_entry_t; + +struct rb_cvar_class_tbl_entry { + uint32_t index; + rb_serial_t global_cvar_state; + const rb_cref_t * cref; + VALUE class_value; +}; + +struct rb_classext_struct { + const rb_box_t *box; + VALUE super; + VALUE fields_obj; // Fields are either ivar or other internal properties stored inline + struct rb_id_table *m_tbl; + struct rb_id_table *const_tbl; + struct rb_id_table *callable_m_tbl; + VALUE cc_tbl; /* { ID => { cme, [cc1, cc2, ...] }, ... } */ + struct rb_id_table *cvc_tbl; + VALUE *superclasses; + /** + * The head of subclasses is a blank (w/o klass) entry to be referred from anchor (and be never deleted). + * (anchor -> head -> 1st-entry) + */ + struct rb_subclass_anchor *subclasses; + /** + * The `box_super_subclasses` points the `box_subclasses` struct to retreive the subclasses + * of the super class in a specific box. + * In compaction GCs, collecting a classext should trigger the deletion of a rb_subclass_entry + * from the super's subclasses. But it may be prevented by the read barrier. + * Fetching the super's subclasses for a ns is to avoid the read barrier in that process. + */ + rb_box_subclasses_t *box_super_subclasses; + /** + * In the case that this is an `ICLASS`, `box_module_subclasses` points to the link + * in the module's `subclasses` list that indicates that the klass has been + * included. Hopefully that makes sense. + */ + rb_box_subclasses_t *box_module_subclasses; + + const VALUE origin_; + const VALUE refined_class; + union { + struct { + rb_alloc_func_t allocator; + } class; + struct { + VALUE attached_object; + } singleton_class; + struct { + const VALUE includer; + } iclass; + } as; + attr_index_t max_iv_count; + uint16_t superclass_depth; + unsigned char variation_count; + bool permanent_classpath : 1; + bool cloned : 1; + bool shared_const_tbl : 1; + bool iclass_is_origin : 1; + bool iclass_origin_shared_mtbl : 1; + bool superclasses_with_self : 1; + VALUE classpath; +}; +typedef struct rb_classext_struct rb_classext_t; + +STATIC_ASSERT(shape_max_variations, SHAPE_MAX_VARIATIONS < (1 << (sizeof(((rb_classext_t *)0)->variation_count) * CHAR_BIT))); + +struct RClass { + struct RBasic basic; + VALUE object_id; + /* + * If box_classext_tbl is NULL, then the prime classext is readable (because no other classext exists). + * For the check whether writable or not, check flag RCLASS_PRIME_CLASSEXT_WRITABLE + */ +}; + +struct RClass_and_rb_classext_t { + struct RClass rclass; + rb_classext_t classext; +}; + +#if SIZEOF_VALUE >= SIZEOF_LONG_LONG +// Assert that classes can be embedded in heaps[2] (which has 160B slot size) +// On 32bit platforms there is no variable width allocation so it doesn't matter. +STATIC_ASSERT(sizeof_rb_classext_t, sizeof(struct RClass_and_rb_classext_t) <= 4 * RVALUE_SIZE); +#endif + +struct RClass_boxable { + struct RClass_and_rb_classext_t base; + st_table *box_classext_tbl; // box_object -> (rb_classext_t *) +}; + +static const uint16_t RCLASS_MAX_SUPERCLASS_DEPTH = ((uint16_t)-1); + +static inline bool RCLASS_SINGLETON_P(VALUE klass); + +static inline bool RCLASS_PRIME_CLASSEXT_READABLE_P(VALUE obj); +static inline bool RCLASS_PRIME_CLASSEXT_WRITABLE_P(VALUE obj); +static inline void RCLASS_SET_PRIME_CLASSEXT_WRITABLE(VALUE obj, bool writable); + +#define RCLASS_EXT_PRIME(c) (&((struct RClass_and_rb_classext_t*)(c))->classext) +#define RCLASS_EXT_PRIME_P(ext, c) (&((struct RClass_and_rb_classext_t*)(c))->classext == ext) + +static inline rb_classext_t * RCLASS_EXT_READABLE_IN_BOX(VALUE obj, const rb_box_t *box); +static inline rb_classext_t * RCLASS_EXT_READABLE(VALUE obj); +static inline rb_classext_t * RCLASS_EXT_WRITABLE_IN_BOX(VALUE obj, const rb_box_t *box); +static inline rb_classext_t * RCLASS_EXT_WRITABLE(VALUE obj); + +// Raw accessor +#define RCLASSEXT_BOX(ext) (ext->box) +#define RCLASSEXT_SUPER(ext) (ext->super) +#define RCLASSEXT_FIELDS(ext) (ext->fields_obj ? ROBJECT_FIELDS(ext->fields_obj) : NULL) +#define RCLASSEXT_FIELDS_OBJ(ext) (ext->fields_obj) +#define RCLASSEXT_M_TBL(ext) (ext->m_tbl) +#define RCLASSEXT_CONST_TBL(ext) (ext->const_tbl) +#define RCLASSEXT_CALLABLE_M_TBL(ext) (ext->callable_m_tbl) +#define RCLASSEXT_CC_TBL(ext) (ext->cc_tbl) +#define RCLASSEXT_CVC_TBL(ext) (ext->cvc_tbl) +#define RCLASSEXT_SUPERCLASS_DEPTH(ext) (ext->superclass_depth) +#define RCLASSEXT_SUPERCLASSES(ext) (ext->superclasses) +#define RCLASSEXT_SUBCLASSES(ext) (ext->subclasses) +#define RCLASSEXT_BOX_SUPER_SUBCLASSES(ext) (ext->box_super_subclasses) +#define RCLASSEXT_BOX_MODULE_SUBCLASSES(ext) (ext->box_module_subclasses) +#define RCLASSEXT_ORIGIN(ext) (ext->origin_) +#define RCLASSEXT_REFINED_CLASS(ext) (ext->refined_class) +// class.allocator/singleton_class.attached_object are not accessed directly via RCLASSEXT_* +#define RCLASSEXT_INCLUDER(ext) (ext->as.iclass.includer) +#define RCLASSEXT_PERMANENT_CLASSPATH(ext) (ext->permanent_classpath) +#define RCLASSEXT_CLONED(ext) (ext->cloned) +#define RCLASSEXT_SHARED_CONST_TBL(ext) (ext->shared_const_tbl) +#define RCLASSEXT_ICLASS_IS_ORIGIN(ext) (ext->iclass_is_origin) +#define RCLASSEXT_ICLASS_ORIGIN_SHARED_MTBL(ext) (ext->iclass_origin_shared_mtbl) +#define RCLASSEXT_SUPERCLASSES_WITH_SELF(ext) (ext->superclasses_with_self) +#define RCLASSEXT_CLASSPATH(ext) (ext->classpath) + +static inline void RCLASSEXT_SET_ORIGIN(rb_classext_t *ext, VALUE klass, VALUE origin); +static inline void RCLASSEXT_SET_INCLUDER(rb_classext_t *ext, VALUE klass, VALUE includer); + +/* Prime classext entry accessor for very specific reason */ +#define RCLASS_PRIME_BOX(c) (RCLASS_EXT_PRIME(c)->box) +// To invalidate CC by inserting&invalidating method entry into tables containing the target cme +// See clear_method_cache_by_id_in_class() +#define RCLASS_PRIME_FIELDS_OBJ(c) (RCLASS_EXT_PRIME(c)->fields_obj) +#define RCLASS_PRIME_M_TBL(c) (RCLASS_EXT_PRIME(c)->m_tbl) +#define RCLASS_PRIME_CONST_TBL(c) (RCLASS_EXT_PRIME(c)->const_tbl) +#define RCLASS_PRIME_CALLABLE_M_TBL(c) (RCLASS_EXT_PRIME(c)->callable_m_tbl) +#define RCLASS_PRIME_CC_TBL(c) (RCLASS_EXT_PRIME(c)->cc_tbl) +#define RCLASS_M_TBL_NOT_PRIME_P(c, tbl) (RCLASS_EXT_PRIME(c)->m_tbl != tbl) +#define RCLASS_CALLABLE_M_TBL_NOT_PRIME_P(c, tbl) (RCLASS_EXT_PRIME(c)->callable_m_tbl != tbl) +#define RCLASS_CC_TBL_NOT_PRIME_P(c, tbl) (RCLASS_EXT_PRIME(c)->cc_tbl != tbl) + +// Read accessor, regarding box +#define RCLASS_SUPER(c) (RCLASS_EXT_READABLE(c)->super) +#define RCLASS_M_TBL(c) (RCLASS_EXT_READABLE(c)->m_tbl) +#define RCLASS_CONST_TBL(c) (RCLASS_EXT_READABLE(c)->const_tbl) +/* + * Both cc_tbl/callable_m_tbl are cache-like and always be changed when referreed, + * so always those should be writable. + */ +#define RCLASS_CVC_TBL(c) (RCLASS_EXT_READABLE(c)->cvc_tbl) +#define RCLASS_SUBCLASSES_X(c) (RCLASS_EXT_READABLE(c)->subclasses) +#define RCLASS_SUBCLASSES_FIRST(c) (RCLASS_EXT_READABLE(c)->subclasses->head->next) +#define RCLASS_ORIGIN(c) (RCLASS_EXT_READABLE(c)->origin_) +#define RICLASS_IS_ORIGIN_P(c) (RCLASS_EXT_READABLE(c)->iclass_is_origin) +#define RCLASS_PERMANENT_CLASSPATH_P(c) (RCLASS_EXT_READABLE(c)->permanent_classpath) +#define RCLASS_CLONED_P(c) (RCLASS_EXT_READABLE(c)->cloned) +#define RCLASS_CLASSPATH(c) (RCLASS_EXT_READABLE(c)->classpath) + +// Superclasses can't be changed after initialization +#define RCLASS_SUPERCLASS_DEPTH(c) (RCLASS_EXT_PRIME(c)->superclass_depth) +#define RCLASS_SUPERCLASSES(c) (RCLASS_EXT_PRIME(c)->superclasses) +#define RCLASS_SUPERCLASSES_WITH_SELF_P(c) (RCLASS_EXT_PRIME(c)->superclasses_with_self) + +// Ruby Box doesn't make changes on these refined_class/attached_object/includer +#define RCLASS_REFINED_CLASS(c) (RCLASS_EXT_PRIME(c)->refined_class) +#define RCLASS_ATTACHED_OBJECT(c) (RCLASS_EXT_PRIME(c)->as.singleton_class.attached_object) +#define RCLASS_INCLUDER(c) (RCLASS_EXT_PRIME(c)->as.iclass.includer) + +// max IV count and variation count are just hints, so they don't need to be per-box +#define RCLASS_MAX_IV_COUNT(ext) (RCLASS_EXT_PRIME(ext)->max_iv_count) +#define RCLASS_VARIATION_COUNT(ext) (RCLASS_EXT_PRIME(ext)->variation_count) + +// Writable classext entries (instead of RCLASS_SET_*) because member data will be operated directly +#define RCLASS_WRITABLE_M_TBL(c) (RCLASS_EXT_WRITABLE(c)->m_tbl) +#define RCLASS_WRITABLE_CONST_TBL(c) (RCLASS_EXT_WRITABLE(c)->const_tbl) +#define RCLASS_WRITABLE_CALLABLE_M_TBL(c) (RCLASS_EXT_WRITABLE(c)->callable_m_tbl) +#define RCLASS_WRITABLE_CC_TBL(c) (RCLASS_EXT_WRITABLE(c)->cc_tbl) +#define RCLASS_WRITABLE_CVC_TBL(c) (RCLASS_EXT_WRITABLE(c)->cvc_tbl) +#define RCLASS_WRITABLE_SUBCLASSES(c) (RCLASS_EXT_WRITABLE(c)->subclasses) + +static inline void RCLASS_SET_SUPER(VALUE klass, VALUE super); +static inline void RCLASS_WRITE_SUPER(VALUE klass, VALUE super); +static inline void RCLASS_SET_CONST_TBL(VALUE klass, struct rb_id_table *table, bool shared); +static inline void RCLASS_WRITE_CONST_TBL(VALUE klass, struct rb_id_table *table, bool shared); +static inline void RCLASS_WRITE_CALLABLE_M_TBL(VALUE klass, struct rb_id_table *table); +static inline void RCLASS_WRITE_CC_TBL(VALUE klass, VALUE table); +static inline void RCLASS_SET_CVC_TBL(VALUE klass, struct rb_id_table *table); +static inline void RCLASS_WRITE_CVC_TBL(VALUE klass, struct rb_id_table *table); + +static inline void RCLASS_WRITE_SUPERCLASSES(VALUE klass, size_t depth, VALUE *superclasses, bool with_self); +static inline void RCLASS_SET_SUBCLASSES(VALUE klass, rb_subclass_anchor_t *anchor); +static inline void RCLASS_WRITE_BOX_SUPER_SUBCLASSES(VALUE klass, rb_box_subclasses_t *box_subclasses); +static inline void RCLASS_WRITE_BOX_MODULE_SUBCLASSES(VALUE klass, rb_box_subclasses_t *box_subclasses); + +static inline void RCLASS_SET_ORIGIN(VALUE klass, VALUE origin); +static inline void RCLASS_WRITE_ORIGIN(VALUE klass, VALUE origin); +static inline void RICLASS_SET_ORIGIN_SHARED_MTBL(VALUE iclass); +static inline void RICLASS_WRITE_ORIGIN_SHARED_MTBL(VALUE iclass); +static inline bool RICLASS_OWNS_M_TBL_P(VALUE iclass); + +static inline void RCLASS_SET_REFINED_CLASS(VALUE klass, VALUE refined); +static inline rb_alloc_func_t RCLASS_ALLOCATOR(VALUE klass); +static inline void RCLASS_SET_ALLOCATOR(VALUE klass, rb_alloc_func_t allocator); +static inline VALUE RCLASS_SET_ATTACHED_OBJECT(VALUE klass, VALUE attached_object); + +static inline void RCLASS_SET_INCLUDER(VALUE iclass, VALUE klass); +static inline void RCLASS_SET_MAX_IV_COUNT(VALUE klass, attr_index_t count); +static inline void RCLASS_SET_CLONED(VALUE klass, bool cloned); +static inline void RCLASS_SET_CLASSPATH(VALUE klass, VALUE classpath, bool permanent); +static inline void RCLASS_WRITE_CLASSPATH(VALUE klass, VALUE classpath, bool permanent); + +#define RCLASS_IS_ROOT FL_USER0 +// 1 is for RUBY_FL_SINGLETON or RMODULE_IS_REFINEMENT +#define RCLASS_PRIME_CLASSEXT_WRITABLE FL_USER2 +#define RCLASS_IS_INITIALIZED FL_USER3 +// 3 is RMODULE_IS_REFINEMENT for RMODULE +#define RCLASS_BOXABLE FL_USER4 + +static inline st_table * +RCLASS_CLASSEXT_TBL(VALUE klass) +{ + if (FL_TEST_RAW(klass, RCLASS_BOXABLE)) { + struct RClass_boxable *box_klass = (struct RClass_boxable *)klass; + return box_klass->box_classext_tbl; + } + return NULL; +} + +static inline void +RCLASS_SET_CLASSEXT_TBL(VALUE klass, st_table *tbl) +{ + RUBY_ASSERT(FL_TEST_RAW(klass, RCLASS_BOXABLE)); + struct RClass_boxable *box_klass = (struct RClass_boxable *)klass; + box_klass->box_classext_tbl = tbl; +} + +/* class.c */ +rb_classext_t * rb_class_duplicate_classext(rb_classext_t *orig, VALUE obj, const rb_box_t *box); +void rb_class_ensure_writable(VALUE obj); + +void rb_class_set_box_classext(VALUE obj, const rb_box_t *box, rb_classext_t *ext); + +static inline int +RCLASS_SET_BOX_CLASSEXT(VALUE obj, const rb_box_t *box, rb_classext_t *ext) +{ + int first_set = 0; + st_table *tbl = RCLASS_CLASSEXT_TBL(obj); + VM_ASSERT(BOX_USER_P(box)); // non-prime classext is only for user box, with box_object + VM_ASSERT(box->box_object); + VM_ASSERT(RCLASSEXT_BOX(ext) == box); + if (!tbl) { + tbl = st_init_numtable_with_size(1); + RCLASS_SET_CLASSEXT_TBL(obj, tbl); + } + if (rb_st_table_size(tbl) == 0) { + first_set = 1; + } + + rb_class_set_box_classext(obj, box, ext); + + return first_set; +} + +#define VM_ASSERT_BOXABLE_TYPE(klass) \ + VM_ASSERT(RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_MODULE) || RB_TYPE_P(klass, T_ICLASS), "%s is not boxable type", rb_type_str(BUILTIN_TYPE(klass))) + +static inline bool +RCLASS_PRIME_CLASSEXT_READABLE_P(VALUE klass) +{ + VM_ASSERT(klass != 0, "klass should be a valid object"); + VM_ASSERT_BOXABLE_TYPE(klass); + // if the lookup table exists, then it means the prime classext is NOT directly readable. + return !FL_TEST_RAW(klass, RCLASS_BOXABLE) || RCLASS_CLASSEXT_TBL(klass) == NULL; +} + +static inline bool +RCLASS_PRIME_CLASSEXT_WRITABLE_P(VALUE klass) +{ + VM_ASSERT(klass != 0, "klass should be a valid object"); + VM_ASSERT_BOXABLE_TYPE(klass); + return FL_TEST(klass, RCLASS_PRIME_CLASSEXT_WRITABLE); +} + +static inline void +RCLASS_SET_PRIME_CLASSEXT_WRITABLE(VALUE klass, bool writable) +{ + VM_ASSERT(klass != 0, "klass should be a valid object"); + VM_ASSERT_BOXABLE_TYPE(klass); + if (writable) { + FL_SET(klass, RCLASS_PRIME_CLASSEXT_WRITABLE); + } + else { + FL_UNSET(klass, RCLASS_PRIME_CLASSEXT_WRITABLE); + } +} + +static inline rb_classext_t * +RCLASS_EXT_TABLE_LOOKUP_INTERNAL(VALUE obj, const rb_box_t *box) +{ + st_data_t classext_ptr; + st_table *classext_tbl = RCLASS_CLASSEXT_TBL(obj); + if (classext_tbl) { + if (rb_st_lookup(classext_tbl, (st_data_t)box->box_object, &classext_ptr)) { + return (rb_classext_t *)classext_ptr; + } + } + return NULL; +} + +static inline rb_classext_t * +RCLASS_EXT_READABLE_LOOKUP(VALUE obj, const rb_box_t *box) +{ + rb_classext_t *ext = RCLASS_EXT_TABLE_LOOKUP_INTERNAL(obj, box); + if (ext) + return ext; + // Classext for the ns not found. Refer the prime one instead. + return RCLASS_EXT_PRIME(obj); +} + +static inline rb_classext_t * +RCLASS_EXT_READABLE_IN_BOX(VALUE obj, const rb_box_t *box) +{ + if (BOX_ROOT_P(box) + || RCLASS_PRIME_CLASSEXT_READABLE_P(obj)) { + return RCLASS_EXT_PRIME(obj); + } + return RCLASS_EXT_READABLE_LOOKUP(obj, box); +} + +static inline rb_classext_t * +RCLASS_EXT_READABLE(VALUE obj) +{ + const rb_box_t *box; + if (RCLASS_PRIME_CLASSEXT_READABLE_P(obj)) { + return RCLASS_EXT_PRIME(obj); + } + // delay determining the current box to optimize for unmodified classes + box = rb_current_box(); + if (BOX_ROOT_P(box)) { + return RCLASS_EXT_PRIME(obj); + } + return RCLASS_EXT_READABLE_LOOKUP(obj, box); +} + +static inline rb_classext_t * +RCLASS_EXT_WRITABLE_LOOKUP(VALUE obj, const rb_box_t *box) +{ + rb_classext_t *ext; + int first_set = 0; + + ext = RCLASS_EXT_TABLE_LOOKUP_INTERNAL(obj, box); + if (ext) + return ext; + + RB_VM_LOCKING() { + // re-check the classext is not created to avoid the multi-thread race + ext = RCLASS_EXT_TABLE_LOOKUP_INTERNAL(obj, box); + if (!ext) { + ext = rb_class_duplicate_classext(RCLASS_EXT_PRIME(obj), obj, box); + first_set = RCLASS_SET_BOX_CLASSEXT(obj, box, ext); + if (first_set) { + // TODO: are there any case that a class/module become non-writable after its birthtime? + RCLASS_SET_PRIME_CLASSEXT_WRITABLE(obj, false); + } + } + } + return ext; +} + +static inline rb_classext_t * +RCLASS_EXT_WRITABLE_IN_BOX(VALUE obj, const rb_box_t *box) +{ + if (BOX_ROOT_P(box) + || RCLASS_PRIME_CLASSEXT_WRITABLE_P(obj)) { + return RCLASS_EXT_PRIME(obj); + } + return RCLASS_EXT_WRITABLE_LOOKUP(obj, box); +} + +static inline rb_classext_t * +RCLASS_EXT_WRITABLE(VALUE obj) +{ + const rb_box_t *box; + if (LIKELY(RCLASS_PRIME_CLASSEXT_WRITABLE_P(obj))) { + return RCLASS_EXT_PRIME(obj); + } + // delay determining the current box to optimize for unmodified classes + box = rb_current_box(); + if (BOX_ROOT_P(box)) { + return RCLASS_EXT_PRIME(obj); + } + return RCLASS_EXT_WRITABLE_LOOKUP(obj, box); +} + +static inline void +RCLASSEXT_SET_ORIGIN(rb_classext_t *ext, VALUE klass, VALUE origin) +{ + RB_OBJ_WRITE(klass, &(RCLASSEXT_ORIGIN(ext)), origin); +} + +static inline void +RCLASSEXT_SET_INCLUDER(rb_classext_t *ext, VALUE klass, VALUE includer) +{ + RUBY_ASSERT(RB_TYPE_P(klass, T_ICLASS)); + RB_OBJ_WRITE(klass, &(RCLASSEXT_INCLUDER(ext)), includer); +} + +/* class.c */ +typedef void rb_class_classext_foreach_callback_func(rb_classext_t *classext, bool is_prime, VALUE box_value, void *arg); +void rb_class_classext_foreach(VALUE klass, rb_class_classext_foreach_callback_func *func, void *arg); +void rb_class_subclass_add(VALUE super, VALUE klass); +void rb_class_classext_free_subclasses(rb_classext_t *, VALUE, bool); +void rb_class_foreach_subclass(VALUE klass, void (*f)(VALUE, VALUE), VALUE); +void rb_class_update_superclasses(VALUE); +int rb_singleton_class_internal_p(VALUE sklass); +VALUE rb_class_set_super(VALUE klass, VALUE super); +VALUE rb_class_boot(VALUE); +VALUE rb_class_s_alloc(VALUE klass); +VALUE rb_module_s_alloc(VALUE klass); +void rb_class_set_initialized(VALUE klass); +void rb_module_check_initializable(VALUE module); +VALUE rb_make_metaclass(VALUE, VALUE); +VALUE rb_include_class_new(VALUE, VALUE); +VALUE rb_define_class_id_under_no_pin(VALUE outer, ID id, VALUE super); +VALUE rb_obj_methods(int argc, const VALUE *argv, VALUE obj); +VALUE rb_obj_protected_methods(int argc, const VALUE *argv, VALUE obj); +VALUE rb_obj_private_methods(int argc, const VALUE *argv, VALUE obj); +VALUE rb_obj_public_methods(int argc, const VALUE *argv, VALUE obj); +VALUE rb_class_undefined_instance_methods(VALUE mod); +VALUE rb_special_singleton_class(VALUE); +VALUE rb_singleton_class_clone_and_attach(VALUE obj, VALUE attach); +VALUE rb_singleton_class_get(VALUE obj); +void rb_undef_methods_from(VALUE klass, VALUE super); +VALUE rb_class_inherited(VALUE, VALUE); +VALUE rb_keyword_error_new(const char *, VALUE); + +void rb_class_classext_free(VALUE klass, rb_classext_t *ext, bool is_prime); +void rb_iclass_classext_free(VALUE klass, rb_classext_t *ext, bool is_prime); + +RUBY_SYMBOL_EXPORT_BEGIN + +/* for objspace */ +VALUE rb_class_super_of(VALUE klass); +VALUE rb_class_singleton_p(VALUE klass); +unsigned char rb_class_variation_count(VALUE klass); + +RUBY_SYMBOL_EXPORT_END + +static inline bool +RCLASS_SINGLETON_P(VALUE klass) +{ + return RB_TYPE_P(klass, T_CLASS) && FL_TEST_RAW(klass, FL_SINGLETON); +} + +static inline void +RCLASS_SET_SUPER(VALUE klass, VALUE super) +{ + RB_OBJ_WRITE(klass, &RCLASSEXT_SUPER(RCLASS_EXT_PRIME(klass)), super); +} + +static inline void +RCLASS_WRITE_SUPER(VALUE klass, VALUE super) +{ + RB_OBJ_WRITE(klass, &RCLASSEXT_SUPER(RCLASS_EXT_WRITABLE(klass)), super); +} + +static inline VALUE +RCLASS_WRITABLE_ENSURE_FIELDS_OBJ(VALUE obj) +{ + RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE)); + rb_classext_t *ext = RCLASS_EXT_WRITABLE(obj); + if (!ext->fields_obj) { + RB_OBJ_WRITE(obj, &ext->fields_obj, rb_imemo_fields_new(obj, 1, true)); + } + return ext->fields_obj; +} + +static inline VALUE +RCLASS_WRITABLE_FIELDS_OBJ(VALUE obj) +{ + RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE)); + return RCLASSEXT_FIELDS_OBJ(RCLASS_EXT_WRITABLE(obj)); +} + +static inline void +RCLASSEXT_SET_FIELDS_OBJ(VALUE obj, rb_classext_t *ext, VALUE fields_obj) +{ + RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE)); + + RB_OBJ_ATOMIC_WRITE(obj, &ext->fields_obj, fields_obj); +} + +static inline void +RCLASS_WRITABLE_SET_FIELDS_OBJ(VALUE obj, VALUE fields_obj) +{ + RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE)); + + RCLASSEXT_SET_FIELDS_OBJ(obj, RCLASS_EXT_WRITABLE(obj), fields_obj); +} + +static inline uint32_t +RCLASS_FIELDS_COUNT(VALUE obj) +{ + RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE)); + + VALUE fields_obj = RCLASS_WRITABLE_FIELDS_OBJ(obj); + if (fields_obj) { + if (rb_shape_obj_too_complex_p(fields_obj)) { + return (uint32_t)rb_st_table_size(rb_imemo_fields_complex_tbl(fields_obj)); + } + else { + return RSHAPE_LEN(RBASIC_SHAPE_ID(fields_obj)); + } + } + return 0; +} + +static inline void +RCLASS_SET_M_TBL(VALUE klass, struct rb_id_table *table) +{ + RCLASSEXT_M_TBL(RCLASS_EXT_PRIME(klass)) = table; +} + +static inline void +RCLASS_WRITE_M_TBL(VALUE klass, struct rb_id_table *table) +{ + RCLASSEXT_M_TBL(RCLASS_EXT_WRITABLE(klass)) = table; +} + +static inline void +RCLASS_SET_CONST_TBL(VALUE klass, struct rb_id_table *table, bool shared) +{ + rb_classext_t *ext = RCLASS_EXT_PRIME(klass); + RCLASSEXT_CONST_TBL(ext) = table; + if (shared) + RCLASSEXT_SHARED_CONST_TBL(ext) = true; +} + +static inline void +RCLASS_WRITE_CONST_TBL(VALUE klass, struct rb_id_table *table, bool shared) +{ + rb_classext_t *ext = RCLASS_EXT_WRITABLE(klass); + RCLASSEXT_CONST_TBL(ext) = table; + if (shared) + RCLASSEXT_SHARED_CONST_TBL(ext) = true; +} + +static inline void +RCLASS_WRITE_CALLABLE_M_TBL(VALUE klass, struct rb_id_table *table) +{ + RCLASSEXT_CALLABLE_M_TBL(RCLASS_EXT_WRITABLE(klass)) = table; +} + +static inline void +RCLASS_WRITE_CC_TBL(VALUE klass, VALUE table) +{ + RB_OBJ_ATOMIC_WRITE(klass, &RCLASSEXT_CC_TBL(RCLASS_EXT_WRITABLE(klass)), table); +} + +static inline void +RCLASS_SET_CVC_TBL(VALUE klass, struct rb_id_table *table) +{ + RCLASSEXT_CVC_TBL(RCLASS_EXT_PRIME(klass)) = table; +} + +static inline void +RCLASS_WRITE_CVC_TBL(VALUE klass, struct rb_id_table *table) +{ + RCLASSEXT_CVC_TBL(RCLASS_EXT_WRITABLE(klass)) = table; +} + +static inline void +RCLASS_SET_REFINED_CLASS(VALUE klass, VALUE refined) +{ + RB_OBJ_WRITE(klass, &RCLASSEXT_REFINED_CLASS(RCLASS_EXT_PRIME(klass)), refined); +} + +static inline rb_alloc_func_t +RCLASS_ALLOCATOR(VALUE klass) +{ + RUBY_ASSERT(RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_ICLASS)); + if (RCLASS_SINGLETON_P(klass) || RB_TYPE_P(klass, T_ICLASS)) { + return 0; + } + return RCLASS_EXT_PRIME(klass)->as.class.allocator; +} + +static inline void +RCLASS_SET_ALLOCATOR(VALUE klass, rb_alloc_func_t allocator) +{ + RUBY_ASSERT(RB_TYPE_P(klass, T_CLASS)); + RUBY_ASSERT(!RCLASS_SINGLETON_P(klass)); + RCLASS_EXT_PRIME(klass)->as.class.allocator = allocator; // Allocator is set only on the initial definition +} + +static inline void +RCLASS_SET_ORIGIN(VALUE klass, VALUE origin) +{ + rb_classext_t *ext = RCLASS_EXT_PRIME(klass); + RB_OBJ_WRITE(klass, &RCLASSEXT_ORIGIN(ext), origin); + if (klass != origin) RCLASSEXT_ICLASS_IS_ORIGIN(RCLASS_EXT_WRITABLE(origin)) = true; +} + +static inline void +RCLASS_WRITE_ORIGIN(VALUE klass, VALUE origin) +{ + rb_classext_t *ext = RCLASS_EXT_WRITABLE(klass); + RB_OBJ_WRITE(klass, &RCLASSEXT_ORIGIN(ext), origin); + if (klass != origin) RCLASSEXT_ICLASS_IS_ORIGIN(RCLASS_EXT_WRITABLE(origin)) = true; +} + +static inline void +RICLASS_SET_ORIGIN_SHARED_MTBL(VALUE iclass) +{ + RCLASSEXT_ICLASS_ORIGIN_SHARED_MTBL(RCLASS_EXT_PRIME(iclass)) = true; +} + +static inline void +RICLASS_WRITE_ORIGIN_SHARED_MTBL(VALUE iclass) +{ + RCLASSEXT_ICLASS_ORIGIN_SHARED_MTBL(RCLASS_EXT_WRITABLE(iclass)) = true; +} + +static inline bool +RICLASS_OWNS_M_TBL_P(VALUE iclass) +{ + rb_classext_t *ext = RCLASS_EXT_READABLE(iclass); + return RCLASSEXT_ICLASS_IS_ORIGIN(ext) && !RCLASSEXT_ICLASS_ORIGIN_SHARED_MTBL(ext); +} + +static inline void +RCLASS_SET_INCLUDER(VALUE iclass, VALUE klass) +{ + RUBY_ASSERT(RB_TYPE_P(iclass, T_ICLASS)); + RB_OBJ_WRITE(iclass, &RCLASS_INCLUDER(iclass), klass); +} + +static inline void +RCLASS_WRITE_SUPERCLASSES(VALUE klass, size_t depth, VALUE *superclasses, bool with_self) +{ + RUBY_ASSERT(depth <= RCLASS_MAX_SUPERCLASS_DEPTH); + + rb_classext_t *ext = RCLASS_EXT_PRIME(klass); + RCLASSEXT_SUPERCLASS_DEPTH(ext) = depth; + RCLASSEXT_SUPERCLASSES(ext) = superclasses; + RCLASSEXT_SUPERCLASSES_WITH_SELF(ext) = with_self; +} + +static inline void +RCLASS_SET_SUBCLASSES(VALUE klass, struct rb_subclass_anchor *anchor) +{ + rb_classext_t *ext = RCLASS_EXT_PRIME(klass); + RCLASSEXT_SUBCLASSES(ext) = anchor; +} + +static inline void +RCLASS_WRITE_BOX_SUPER_SUBCLASSES(VALUE klass, rb_box_subclasses_t *box_subclasses) +{ + rb_classext_t *ext = RCLASS_EXT_WRITABLE(klass); + if (RCLASSEXT_BOX_SUPER_SUBCLASSES(ext)) + rb_box_subclasses_ref_dec(RCLASSEXT_BOX_SUPER_SUBCLASSES(ext)); + RCLASSEXT_BOX_SUPER_SUBCLASSES(ext) = rb_box_subclasses_ref_inc(box_subclasses); +} + +static inline void +RCLASS_WRITE_BOX_MODULE_SUBCLASSES(VALUE klass, rb_box_subclasses_t *box_subclasses) +{ + rb_classext_t *ext = RCLASS_EXT_WRITABLE(klass); + if (RCLASSEXT_BOX_MODULE_SUBCLASSES(ext)) + rb_box_subclasses_ref_dec(RCLASSEXT_BOX_MODULE_SUBCLASSES(ext)); + RCLASSEXT_BOX_MODULE_SUBCLASSES(ext) = rb_box_subclasses_ref_inc(box_subclasses); +} + +static inline void +RCLASS_SET_CLASSPATH(VALUE klass, VALUE classpath, bool permanent) +{ + rb_classext_t *ext = RCLASS_EXT_READABLE(klass); + assert(BUILTIN_TYPE(klass) == T_CLASS || BUILTIN_TYPE(klass) == T_MODULE); + assert(classpath == 0 || BUILTIN_TYPE(classpath) == T_STRING); + assert(FL_TEST_RAW(classpath, RUBY_FL_SHAREABLE)); + + RB_OBJ_WRITE(klass, &(RCLASSEXT_CLASSPATH(ext)), classpath); + RCLASSEXT_PERMANENT_CLASSPATH(ext) = permanent; +} + +static inline void +RCLASS_WRITE_CLASSPATH(VALUE klass, VALUE classpath, bool permanent) +{ + rb_classext_t *ext = RCLASS_EXT_WRITABLE(klass); + assert(BUILTIN_TYPE(klass) == T_CLASS || BUILTIN_TYPE(klass) == T_MODULE); + assert(classpath == 0 || BUILTIN_TYPE(classpath) == T_STRING); + assert(!RB_FL_ABLE(classpath) || FL_TEST_RAW(classpath, RUBY_FL_SHAREABLE)); + + RB_OBJ_WRITE(klass, &(RCLASSEXT_CLASSPATH(ext)), classpath); + RCLASSEXT_PERMANENT_CLASSPATH(ext) = permanent; +} + +static inline VALUE +RCLASS_SET_ATTACHED_OBJECT(VALUE klass, VALUE attached_object) +{ + assert(RCLASS_SINGLETON_P(klass)); + + RB_OBJ_WRITE(klass, &RCLASS_EXT_PRIME(klass)->as.singleton_class.attached_object, attached_object); + return attached_object; +} + +static inline void +RCLASS_SET_MAX_IV_COUNT(VALUE klass, attr_index_t count) +{ + RCLASS_MAX_IV_COUNT(klass) = count; +} + +static inline void +RCLASS_SET_CLONED(VALUE klass, bool cloned) +{ + RCLASSEXT_CLONED(RCLASS_EXT_PRIME(klass)) = cloned; +} + +static inline bool +RCLASS_INITIALIZED_P(VALUE klass) +{ + VM_ASSERT(RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_MODULE)); + return FL_TEST_RAW(klass, RCLASS_IS_INITIALIZED); +} + +#endif /* INTERNAL_CLASS_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/cmdlineopt.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/cmdlineopt.h new file mode 100644 index 0000000..aed209e --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/cmdlineopt.h @@ -0,0 +1,64 @@ +#ifndef INTERNAL_CMDLINEOPT_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_CMDLINEOPT_H + +#include "yjit.h" + +typedef struct { + unsigned int mask; + unsigned int set; +} ruby_features_t; + +typedef struct ruby_cmdline_options { + const char *script; + VALUE script_name; + VALUE e_script; + struct { + struct { + VALUE name; + int index; + } enc; + } src, ext, intern; + VALUE req_list; + ruby_features_t features; + ruby_features_t warn; + unsigned int dump; + long backtrace_length_limit; + + const char *crash_report; + + signed int sflag: 2; + unsigned int xflag: 1; + unsigned int warning: 1; + unsigned int verbose: 1; + unsigned int do_loop: 1; + unsigned int do_print: 1; + unsigned int do_line: 1; + unsigned int do_split: 1; + unsigned int do_search: 1; + unsigned int setids: 2; +#if USE_YJIT + unsigned int yjit: 1; +#endif +#if USE_ZJIT + unsigned int zjit: 1; +#endif +} ruby_cmdline_options_t; + +struct ruby_opt_message { + const char *str; + unsigned short namelen, secondlen; +}; + +#define RUBY_OPT_MESSAGE(shortopt, longopt, desc) { \ + shortopt " " longopt " " desc, \ + (unsigned short)sizeof(shortopt), \ + (unsigned short)sizeof(longopt), \ +} + +#define opt_match(s, l, name) \ + ((((l) > rb_strlen_lit(name)) ? (s)[rb_strlen_lit(name)] == '=' : \ + (l) == rb_strlen_lit(name)) && \ + memcmp((s), name, rb_strlen_lit(name)) == 0 && \ + (((s) += rb_strlen_lit(name)), 1)) + +#endif diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/compar.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/compar.h new file mode 100644 index 0000000..9115e4b --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/compar.h @@ -0,0 +1,29 @@ +#ifndef INTERNAL_COMPAR_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_COMPAR_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Comparable. + */ +#include "internal/basic_operators.h" + +#define STRING_P(s) (RB_TYPE_P((s), T_STRING) && CLASS_OF(s) == rb_cString) + +#define CMP_OPTIMIZABLE(type) BASIC_OP_UNREDEFINED_P(BOP_CMP, type##_REDEFINED_OP_FLAG) + +#define OPTIMIZED_CMP(a, b) \ + ((FIXNUM_P(a) && FIXNUM_P(b) && CMP_OPTIMIZABLE(INTEGER)) ? \ + (((long)a > (long)b) ? 1 : ((long)a < (long)b) ? -1 : 0) : \ + (STRING_P(a) && STRING_P(b) && CMP_OPTIMIZABLE(STRING)) ? \ + rb_str_cmp(a, b) : \ + (RB_FLOAT_TYPE_P(a) && RB_FLOAT_TYPE_P(b) && CMP_OPTIMIZABLE(FLOAT)) ? \ + rb_float_cmp(a, b) : \ + rb_cmpint(rb_funcallv(a, id_cmp, 1, &b), a, b)) + +/* compar.c */ +VALUE rb_invcmp(VALUE, VALUE); + +#endif /* INTERNAL_COMPAR_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/compile.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/compile.h new file mode 100644 index 0000000..2ece539 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/compile.h @@ -0,0 +1,34 @@ +#ifndef INTERNAL_COMPILE_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_COMPILE_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for the compiler. + */ +#include "ruby/internal/config.h" +#include /* for size_t */ +#include "ruby/ruby.h" /* for rb_event_flag_t */ + +struct rb_iseq_struct; /* in vm_core.h */ + +/* compile.c */ +int rb_dvar_defined(ID, const struct rb_iseq_struct *); +int rb_local_defined(ID, const struct rb_iseq_struct *); +int rb_insn_len(VALUE insn); +const char *rb_insns_name(int i); +VALUE rb_insns_name_array(void); +int rb_iseq_cdhash_cmp(VALUE val, VALUE lit); +st_index_t rb_iseq_cdhash_hash(VALUE a); + +/* iseq.c */ +int rb_vm_insn_addr2insn(const void *); +int rb_vm_insn_decode(const VALUE encoded); +extern bool ruby_vm_keep_script_lines; + +/* iseq.c (export) */ +rb_event_flag_t rb_iseq_event_flags(const struct rb_iseq_struct *iseq, size_t pos); + +#endif /* INTERNAL_COMPILE_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/compilers.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/compilers.h new file mode 100644 index 0000000..26c2f05 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/compilers.h @@ -0,0 +1,107 @@ +#ifndef INTERNAL_COMPILERS_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_COMPILERS_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header absorbing C compiler differences. + */ +#include "ruby/internal/compiler_since.h" +#include "ruby/internal/has/attribute.h" +#include "ruby/internal/has/builtin.h" +#include "ruby/internal/has/c_attribute.h" +#include "ruby/internal/has/declspec_attribute.h" +#include "ruby/internal/has/extension.h" +#include "ruby/internal/has/feature.h" +#include "ruby/internal/has/warning.h" +#include "ruby/backward/2/gcc_version_since.h" + +#define MSC_VERSION_SINCE(_) RBIMPL_COMPILER_SINCE(MSVC, (_) / 100, (_) % 100, 0) +#define MSC_VERSION_BEFORE(_) RBIMPL_COMPILER_BEFORE(MSVC, (_) / 100, (_) % 100, 0) + +#ifndef __has_attribute +# define __has_attribute(...) RBIMPL_HAS_ATTRIBUTE(__VA_ARGS__) +#endif + +#ifndef __has_c_attribute +# /* As of writing everything that lacks __has_c_attribute also completely +# * lacks C2x attributes as well. Might change in future? */ +# define __has_c_attribute(...) 0 +#endif + +#ifndef __has_declspec_attribute +# define __has_declspec_attribute(...) RBIMPL_HAS_DECLSPEC_ATTRIBUTE(__VA_ARGS__) +#endif + +#ifndef __has_builtin +# define __has_builtin(...) RBIMPL_HAS_BUILTIN(__VA_ARGS__) +#endif + +#ifndef __has_feature +# define __has_feature(...) RBIMPL_HAS_FEATURE(__VA_ARGS__) +#endif + +#ifndef __has_extension +# define __has_extension(...) RBIMPL_HAS_EXTENSION(__VA_ARGS__) +#endif + +#ifndef __has_warning +# define __has_warning(...) RBIMPL_HAS_WARNING(__VA_ARGS__) +#endif + +#ifndef __GNUC__ +# define __extension__ /* void */ +#endif + +#ifndef MAYBE_UNUSED +# define MAYBE_UNUSED(x) x +#endif + +#ifndef WARN_UNUSED_RESULT +# define WARN_UNUSED_RESULT(x) x +#endif + +#define RB_OBJ_BUILTIN_TYPE(obj) rb_obj_builtin_type(obj) +#define OBJ_BUILTIN_TYPE(obj) RB_OBJ_BUILTIN_TYPE(obj) +#ifdef __GNUC__ +#define rb_obj_builtin_type(obj) \ +__extension__({ \ + VALUE arg_obj = (obj); \ + RB_SPECIAL_CONST_P(arg_obj) ? -1 : \ + (int)RB_BUILTIN_TYPE(arg_obj); \ + }) +#else +# include "ruby/ruby.h" +static inline int +rb_obj_builtin_type(VALUE obj) +{ + return RB_SPECIAL_CONST_P(obj) ? -1 : + (int)RB_BUILTIN_TYPE(obj); +} +#endif + +/* A macro for defining a flexible array, like: VALUE ary[FLEX_ARY_LEN]; */ +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +# define FLEX_ARY_LEN /* VALUE ary[]; */ +#elif defined(__GNUC__) && !defined(__STRICT_ANSI__) +# define FLEX_ARY_LEN 0 /* VALUE ary[0]; */ +#else +# define FLEX_ARY_LEN 1 /* VALUE ary[1]; */ +#endif + +/* + * For declaring bitfields out of non-unsigned int types: + * struct date { + * BITFIELD(enum months, month, 4); + * ... + * }; + */ +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +# define BITFIELD(type, name, size) type name : size +#else +# define BITFIELD(type, name, size) unsigned int name : size +#endif + +#endif /* INTERNAL_COMPILERS_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/complex.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/complex.h new file mode 100644 index 0000000..4215165 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/complex.h @@ -0,0 +1,29 @@ +#ifndef INTERNAL_COMPLEX_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_COMPLEX_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Complex. + */ +#include "ruby/internal/value.h" /* for struct RBasic */ + +struct RComplex { + struct RBasic basic; + VALUE real; + VALUE imag; +}; + +#define RCOMPLEX(obj) ((struct RComplex *)(obj)) + +/* shortcut macro for internal only */ +#define RCOMPLEX_SET_REAL(cmp, r) RB_OBJ_WRITE((cmp), &RCOMPLEX(cmp)->real, (r)) +#define RCOMPLEX_SET_IMAG(cmp, i) RB_OBJ_WRITE((cmp), &RCOMPLEX(cmp)->imag, (i)) + +/* complex.c */ +VALUE rb_dbl_complex_new_polar_pi(double abs, double ang); +st_index_t rb_complex_hash(VALUE comp); + +#endif /* INTERNAL_COMPLEX_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/concurrent_set.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/concurrent_set.h new file mode 100644 index 0000000..76cbefa --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/concurrent_set.h @@ -0,0 +1,21 @@ +#ifndef RUBY_RACTOR_SAFE_TABLE_H +#define RUBY_RACTOR_SAFE_TABLE_H + +#include "ruby/atomic.h" +#include "ruby/ruby.h" + +struct rb_concurrent_set_funcs { + VALUE (*hash)(VALUE key); + bool (*cmp)(VALUE a, VALUE b); + VALUE (*create)(VALUE key, void *data); + void (*free)(VALUE key); +}; + +VALUE rb_concurrent_set_new(const struct rb_concurrent_set_funcs *funcs, int capacity); +rb_atomic_t rb_concurrent_set_size(VALUE set_obj); +VALUE rb_concurrent_set_find(VALUE *set_obj_ptr, VALUE key); +VALUE rb_concurrent_set_find_or_insert(VALUE *set_obj_ptr, VALUE key, void *data); +VALUE rb_concurrent_set_delete_by_identity(VALUE set_obj, VALUE key); +void rb_concurrent_set_foreach_with_replace(VALUE set_obj, int (*callback)(VALUE *key, void *data), void *data); + +#endif diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/cont.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/cont.h new file mode 100644 index 0000000..3c2528a --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/cont.h @@ -0,0 +1,35 @@ +#ifndef INTERNAL_CONT_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_CONT_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Fiber. + */ +#include "ruby/ruby.h" /* for VALUE */ +#include "iseq.h" + +struct rb_thread_struct; /* in vm_core.h */ +struct rb_fiber_struct; /* in cont.c */ +struct rb_execution_context_struct; /* in vm_core.c */ + +/* cont.c */ +void rb_fiber_reset_root_local_storage(struct rb_thread_struct *); +void ruby_register_rollback_func_for_ensure(VALUE (*ensure_func)(VALUE), VALUE (*rollback_func)(VALUE)); +void rb_jit_cont_init(void); +void rb_jit_cont_each_iseq(rb_iseq_callback callback, void *data); +void rb_jit_cont_finish(void); + +/* vm.c */ +void rb_free_shared_fiber_pool(void); + +// Copy locals from the current execution to the specified fiber. +VALUE rb_fiber_inherit_storage(struct rb_execution_context_struct *ec, struct rb_fiber_struct *fiber); + +VALUE rb_fiberptr_self(struct rb_fiber_struct *fiber); +unsigned int rb_fiberptr_blocking(struct rb_fiber_struct *fiber); +struct rb_execution_context_struct * rb_fiberptr_get_ec(struct rb_fiber_struct *fiber); + +#endif /* INTERNAL_CONT_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/dir.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/dir.h new file mode 100644 index 0000000..0a4dc90 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/dir.h @@ -0,0 +1,16 @@ +#ifndef INTERNAL_DIR_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_DIR_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Dir. + */ +#include "ruby/ruby.h" /* for VALUE */ + +/* dir.c */ +VALUE rb_dir_getwd_ospath(void); + +#endif /* INTERNAL_DIR_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/enc.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/enc.h new file mode 100644 index 0000000..a005dc8 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/enc.h @@ -0,0 +1,19 @@ +#ifndef INTERNAL_ENC_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_ENC_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Encoding. + */ +#include "ruby/encoding.h" /* for rb_encoding */ + +/* us_ascii.c */ +extern rb_encoding OnigEncodingUS_ASCII; + +/* utf_8.c */ +extern rb_encoding OnigEncodingUTF_8; + +#endif /* INTERNAL_ENC_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/encoding.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/encoding.h new file mode 100644 index 0000000..38bf8fc --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/encoding.h @@ -0,0 +1,39 @@ +#ifndef INTERNAL_ENCODING_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_ENCODING_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Encoding. + */ +#include "ruby/ruby.h" /* for ID */ +#include "ruby/encoding.h" /* for rb_encoding */ + +#define rb_is_usascii_enc(enc) ((enc) == rb_usascii_encoding()) +#define rb_is_ascii8bit_enc(enc) ((enc) == rb_ascii8bit_encoding()) +#define rb_is_locale_enc(enc) ((enc) == rb_locale_encoding()) + +/* encoding.c */ +ID rb_id_encoding(void); +const char * rb_enc_inspect_name(rb_encoding *enc); +rb_encoding *rb_enc_get_from_index(int index); +rb_encoding *rb_enc_check_str(VALUE str1, VALUE str2); +int rb_encdb_replicate(const char *alias, const char *orig); +int rb_encdb_alias(const char *alias, const char *orig); +int rb_enc_autoload(rb_encoding *enc); +bool rb_enc_autoload_p(rb_encoding *enc); +int rb_encdb_dummy(const char *name); +void rb_encdb_declare(const char *name); +void rb_enc_set_base(const char *name, const char *orig); +int rb_enc_set_dummy(int index); +void rb_enc_raw_set(VALUE obj, rb_encoding *enc); +int rb_enc_registered(const char *name); + +PUREFUNC(int rb_data_is_encoding(VALUE obj)); + +/* vm.c */ +void rb_free_global_enc_table(void); + +#endif /* INTERNAL_ENCODING_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/enum.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/enum.h new file mode 100644 index 0000000..2824644 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/enum.h @@ -0,0 +1,18 @@ +#ifndef INTERNAL_ENUM_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_ENUM_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Enumerable. + */ +#include "ruby/ruby.h" /* for VALUE */ + +/* enum.c */ +extern VALUE rb_cArithSeq; +VALUE rb_f_send(int argc, VALUE *argv, VALUE recv); +VALUE rb_nmin_run(VALUE obj, VALUE num, int by, int rev, int ary); + +#endif /* INTERNAL_ENUM_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/enumerator.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/enumerator.h new file mode 100644 index 0000000..e11a684 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/enumerator.h @@ -0,0 +1,21 @@ +#ifndef INTERNAL_ENUMERATOR_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_ENUMERATOR_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Enumerator. + */ +#include "ruby/ruby.h" /* for VALUE */ +#include "ruby/intern.h" /* for rb_enumerator_size_func */ + +RUBY_SYMBOL_EXPORT_BEGIN +/* enumerator.c (export) */ +VALUE rb_arith_seq_new(VALUE obj, VALUE meth, int argc, VALUE const *argv, + rb_enumerator_size_func *size_fn, + VALUE beg, VALUE end, VALUE step, int excl); +RUBY_SYMBOL_EXPORT_END + +#endif /* INTERNAL_ENUMERATOR_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/error.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/error.h new file mode 100644 index 0000000..de18969 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/error.h @@ -0,0 +1,251 @@ +#ifndef INTERNAL_ERROR_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_ERROR_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Exception. + */ +#include "ruby/internal/config.h" +#include /* for va_list */ +#include "internal/string.h" /* for rb_fstring_cstr */ +#include "ruby/internal/stdbool.h" /* for bool */ +#include "ruby/encoding.h" /* for rb_encoding */ +#include "ruby/intern.h" /* for rb_exc_raise */ +#include "ruby/ruby.h" /* for enum ruby_value_type */ + +#ifdef Check_Type +# undef Check_Type /* in ruby/ruby.h */ +#endif + +#ifdef rb_raise_static +# undef rb_raise_static +# undef rb_sys_fail_path +# undef rb_syserr_fail_path +#endif + +#define rb_raise_static(e, m) \ + rb_raise_cstr_i((e), rb_str_new_static((m), rb_strlen_lit(m))) +#ifdef RUBY_FUNCTION_NAME_STRING +# define rb_syserr_fail_path(err, path) rb_syserr_fail_path_in(RUBY_FUNCTION_NAME_STRING, (err), (path)) +# define rb_syserr_new_path(err, path) rb_syserr_new_path_in(RUBY_FUNCTION_NAME_STRING, (err), (path)) +#else +# define rb_syserr_fail_path(err, path) rb_syserr_fail_str((err), (path)) +# define rb_syserr_new_path(err, path) rb_syserr_new_str((err), (path)) +#endif + +#define rb_sys_fail(mesg) \ +do { \ + int errno_to_fail = errno; \ + rb_syserr_fail(errno_to_fail, (mesg)); \ +} while (0) + +#define rb_sys_fail_str(mesg) \ +do { \ + int errno_to_fail = errno; \ + rb_syserr_fail_str(errno_to_fail, (mesg)); \ +} while (0) + +#define rb_sys_fail_path(path) \ +do { \ + int errno_to_fail = errno; \ + rb_syserr_fail_path(errno_to_fail, (path)); \ +} while (0) + +#define rb_sys_fail_sprintf(...) \ +do { \ + int errno_to_fail = errno; \ + rb_syserr_fail_str(errno_to_fail, rb_sprintf("" __VA_ARGS__)); \ +} while (0) + +/* error.c */ +extern long rb_backtrace_length_limit; +extern VALUE rb_eEAGAIN; +extern VALUE rb_eEWOULDBLOCK; +extern VALUE rb_eEINPROGRESS; +RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 3, 0) +void rb_report_bug_valist(VALUE file, int line, const char *fmt, va_list args); +NORETURN(void rb_async_bug_errno(const char *,int)); +const char *rb_builtin_type_name(int t); +const char *rb_builtin_class_name(VALUE x); +PRINTF_ARGS(void rb_warn_deprecated(const char *fmt, const char *suggest, ...), 1, 3); +PRINTF_ARGS(void rb_warn_deprecated_to_remove(const char *removal, const char *fmt, const char *suggest, ...), 2, 4); +PRINTF_ARGS(void rb_warn_reserved_name(const char *removal, const char *fmt, ...), 2, 3); +#if RUBY_DEBUG +# include "ruby/version.h" +# define RUBY_VERSION_SINCE(major, minor) (RUBY_API_VERSION_CODE >= (major * 10000) + (minor) * 100) +# define RUBY_VERSION_BEFORE(major, minor) (RUBY_API_VERSION_CODE < (major * 10000) + (minor) * 100) +# if defined(RBIMPL_WARNING_PRAGMA0) +# define RBIMPL_TODO0(x) RBIMPL_WARNING_PRAGMA0(message(x)) +# elif RBIMPL_COMPILER_SINCE(MSVC, 12, 0, 0) +# define RBIMPL_TODO0(x) __pragma(message(x)) +# endif + +# if RBIMPL_HAS_ATTRIBUTE(diagnose_if) || defined(__OPTIMIZE__) + +#define RUBY_VERSION_isdigit(c) ('0'<=(c)&&(c)<='9') +// upto 99 +#define RUBY_VERSION__number_len(v, ofs) \ + (!RUBY_VERSION_isdigit((v)[ofs]) ? \ + 0 : !RUBY_VERSION_isdigit((v)[(ofs) + 1]) ? 1 : 2) +#define RUBY_VERSION__to_number(v, ofs) \ + (!RUBY_VERSION_isdigit((v)[ofs]) ? \ + 0 : !RUBY_VERSION_isdigit((v)[(ofs) + 1]) ? \ + ((v)[ofs]-'0') : \ + (((v)[ofs]-'0')*10+(v)[(ofs)+1]-'0')) + +#define RUBY_VERSION_CODE_FROM_MAJOR_MINOR_STRING(v) \ + (RUBY_VERSION__to_number(v, 0) * 10000 + \ + ((v)[RUBY_VERSION__number_len(v, 0)] == '.' ? \ + RUBY_VERSION__to_number(v, RUBY_VERSION__number_len(v, 0)+1) * 100 : 0)) +#define RUBY_VERSION_STRING_SINCE(v) (RUBY_API_VERSION_CODE >= RUBY_VERSION_CODE_FROM_MAJOR_MINOR_STRING(v)) +#define RUBY_VERSION_STRING_BEFORE(v) (RUBY_API_VERSION_CODE < RUBY_VERSION_CODE_FROM_MAJOR_MINOR_STRING(v)) + +# if RBIMPL_HAS_ATTRIBUTE(diagnose_if) +RBIMPL_ATTR_FORCEINLINE() +static void +rb_deprecated_method_to_be_removed(const char *removal) + RBIMPL_ATTR_DIAGNOSE_IF(!RUBY_VERSION_isdigit(removal[0]), "malformed version number", "error") + RBIMPL_ATTR_DIAGNOSE_IF(RUBY_VERSION_STRING_SINCE(removal), "deprecated method to be removed", "error") +{ +} + +RBIMPL_ATTR_FORCEINLINE() +static void +rb_diagnose_reserved_name_at(const char *coming) + RBIMPL_ATTR_DIAGNOSE_IF(!RUBY_VERSION_isdigit(coming[0]), "malformed version number", "error") + RBIMPL_ATTR_DIAGNOSE_IF(RUBY_VERSION_STRING_SINCE(coming), "reserved name already in use", "error") +{ +} +# else +RBIMPL_ATTR_ERROR(("deprecated")) +void rb_deprecated_method_to_be_removed(const char *); +# define rb_deprecated_method_to_be_removed(removal) \ + (sizeof(char[1-2*(!RUBY_VERSION_isdigit(removal[0]) || RUBY_VERSION_STRING_SINCE(removal))])!=1 ? \ + rb_deprecated_method_to_be_removed(removal) : \ + RBIMPL_ASSERT_NOTHING) + +RBIMPL_ATTR_ERROR(("deprecated")) +void rb_diagnose_reserved_name_at(const char *); +# define rb_diagnose_reserved_name_at(coming) \ + (sizeof(char[1-2*(!RUBY_VERSION_isdigit(coming[0]) || RUBY_VERSION_STRING_SINCE(coming))])!=1 ? \ + rb_diagnose_reserved_name_at(coming) : \ + RBIMPL_ASSERT_NOTHING) + +# endif +# define rb_warn_deprecated_to_remove_at(removal, ...) \ + (rb_deprecated_method_to_be_removed(#removal), \ + rb_warn_deprecated_to_remove(#removal, __VA_ARGS__)) + +# define rb_warn_reserved_name_at(coming, ...) \ + (rb_diagnose_reserved_name_at(#coming), \ + rb_warn_reserved_name(#coming, __VA_ARGS__)) +# endif +#endif +#ifndef rb_warn_deprecated_to_remove_at +# define rb_warn_deprecated_to_remove_at(removal, ...) \ + rb_warn_deprecated_to_remove(#removal, __VA_ARGS__) +#endif +#ifndef rb_warn_reserved_name_at +# define rb_warn_reserved_name_at(removal, ...) \ + rb_warn_reserved_name(#removal, __VA_ARGS__) +#endif +#ifndef RUBY_VERSION_SINCE +# define RUBY_VERSION_SINCE(major, minor) 0 +#endif +#ifndef RUBY_VERSION_BEFORE +# define RUBY_VERSION_BEFORE(major, minor) 0 +#endif +#ifndef RBIMPL_TODO0 +# define RBIMPL_TODO0(x) +#endif +#define RBIMPL_TODO(message) RBIMPL_TODO0("TODO: " message) +RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 6, 0) +VALUE rb_syntax_error_append(VALUE, VALUE, int, int, rb_encoding*, const char*, va_list); +PRINTF_ARGS(void rb_enc_warn(rb_encoding *enc, const char *fmt, ...), 2, 3); +PRINTF_ARGS(void rb_sys_enc_warning(rb_encoding *enc, const char *fmt, ...), 2, 3); +PRINTF_ARGS(void rb_syserr_enc_warning(int err, rb_encoding *enc, const char *fmt, ...), 3, 4); +PRINTF_ARGS(void rb_enc_compile_warning(rb_encoding *enc, const char *file, int line, const char *fmt, ...), 4, 5); +PRINTF_ARGS(void rb_enc_compile_warn(rb_encoding *enc, const char *file, int line, const char *fmt, ...), 4, 5); +rb_warning_category_t rb_warning_category_from_name(VALUE category); +bool rb_warning_category_enabled_p(rb_warning_category_t category); +VALUE rb_name_err_new(VALUE mesg, VALUE recv, VALUE method); +VALUE rb_nomethod_err_new(VALUE mesg, VALUE recv, VALUE method, VALUE args, int priv); +VALUE rb_key_err_new(VALUE mesg, VALUE recv, VALUE name); +PRINTF_ARGS(VALUE rb_warning_string(const char *fmt, ...), 1, 2); +RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 2, 0) +NORETURN(void rb_vraise(VALUE, const char *, va_list)); +NORETURN(static inline void rb_raise_cstr(VALUE etype, const char *mesg)); +NORETURN(static inline void rb_raise_cstr_i(VALUE etype, VALUE mesg)); +NORETURN(static inline void rb_name_err_raise_str(VALUE mesg, VALUE recv, VALUE name)); +NORETURN(static inline void rb_name_err_raise(const char *mesg, VALUE recv, VALUE name)); +NORETURN(static inline void rb_key_err_raise(VALUE mesg, VALUE recv, VALUE name)); +static inline void Check_Type(VALUE v, enum ruby_value_type t); +static inline bool rb_typeddata_is_instance_of_inline(VALUE obj, const rb_data_type_t *data_type); +#define rb_typeddata_is_instance_of rb_typeddata_is_instance_of_inline +void rb_bug_without_die(const char *fmt, ...); + +RUBY_SYMBOL_EXPORT_BEGIN +/* error.c (export) */ +int rb_bug_reporter_add(void (*func)(FILE *, void *), void *data); +#ifdef RUBY_FUNCTION_NAME_STRING +NORETURN(void rb_sys_fail_path_in(const char *func_name, VALUE path)); +NORETURN(void rb_syserr_fail_path_in(const char *func_name, int err, VALUE path)); +VALUE rb_syserr_new_path_in(const char *func_name, int n, VALUE path); +#endif +RUBY_SYMBOL_EXPORT_END + +/* vm.c */ +void rb_free_warning(void); + +static inline void +rb_raise_cstr_i(VALUE etype, VALUE mesg) +{ + VALUE exc = rb_exc_new_str(etype, mesg); + rb_exc_raise(exc); +} + +static inline void +rb_raise_cstr(VALUE etype, const char *mesg) +{ + VALUE str = rb_str_new_cstr(mesg); + rb_raise_cstr_i(etype, str); +} + +static inline void +rb_name_err_raise_str(VALUE mesg, VALUE recv, VALUE name) +{ + VALUE exc = rb_name_err_new(mesg, recv, name); + rb_exc_raise(exc); +} + +static inline void +rb_name_err_raise(const char *mesg, VALUE recv, VALUE name) +{ + VALUE str = rb_fstring_cstr(mesg); + rb_name_err_raise_str(str, recv, name); +} + +static inline void +rb_key_err_raise(VALUE mesg, VALUE recv, VALUE name) +{ + VALUE exc = rb_key_err_new(mesg, recv, name); + rb_exc_raise(exc); +} + +static inline bool +rb_typeddata_is_instance_of_inline(VALUE obj, const rb_data_type_t *data_type) +{ + return RB_TYPE_P(obj, T_DATA) && RTYPEDDATA_P(obj) && (RTYPEDDATA_TYPE(obj) == data_type); +} + +typedef enum { + rb_stack_overflow_prevention = 0, // VM stack overflow or about to machine stack overflow + rb_stack_overflow_signal = 1, // machine stack overflow but may be recoverable + rb_stack_overflow_fatal = 2, // fatal machine stack overflow +} ruby_stack_overflow_critical_level; +NORETURN(void rb_ec_stack_overflow(struct rb_execution_context_struct *ec, ruby_stack_overflow_critical_level crit)); + +#endif /* INTERNAL_ERROR_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/eval.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/eval.h new file mode 100644 index 0000000..4c1c045 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/eval.h @@ -0,0 +1,41 @@ +#ifndef INTERNAL_EVAL_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_EVAL_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for the evaluator. + * @note There also is eval_intern.h, which is evaluator's internal + * header (related to this file, but not the same role). + */ +#include "ruby/ruby.h" /* for ID */ + +#define id_signo ruby_static_id_signo +#define id_status ruby_static_id_status + +/* eval.c */ +struct rb_refinements_data { + VALUE refinement; + VALUE refinements; +}; + +extern ID ruby_static_id_signo; +extern ID ruby_static_id_status; +VALUE rb_refinement_module_get_refined_class(VALUE module); +void rb_class_modify_check(VALUE); +NORETURN(VALUE rb_f_raise(int argc, VALUE *argv)); +VALUE rb_exception_setup(int argc, VALUE *argv); +void rb_refinement_setup(struct rb_refinements_data *data, VALUE module, VALUE klass); +void rb_vm_using_module(VALUE module); +VALUE rb_top_main_class(const char *method); + +/* eval_error.c */ +VALUE rb_get_backtrace(VALUE info); + +/* eval_jump.c */ +void rb_call_end_proc(VALUE data); +void rb_mark_end_proc(void); + +#endif /* INTERNAL_EVAL_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/file.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/file.h new file mode 100644 index 0000000..9c192ff --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/file.h @@ -0,0 +1,38 @@ +#ifndef INTERNAL_FILE_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_FILE_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for File. + */ +#include "ruby/ruby.h" /* for VALUE */ +#include "ruby/encoding.h" /* for rb_encodinng */ + +/* file.c */ +extern const char ruby_null_device[]; +VALUE rb_home_dir_of(VALUE user, VALUE result); +VALUE rb_default_home_dir(VALUE result); +VALUE rb_realpath_internal(VALUE basedir, VALUE path, int strict); +VALUE rb_check_realpath(VALUE basedir, VALUE path, rb_encoding *origenc); +void rb_file_const(const char*, VALUE); +int rb_file_load_ok(const char *); +VALUE rb_file_expand_path_fast(VALUE, VALUE); +VALUE rb_file_expand_path_internal(VALUE, VALUE, int, int, VALUE); +VALUE rb_get_path_check_to_string(VALUE); +VALUE rb_get_path_check_convert(VALUE); +int ruby_is_fd_loadable(int fd); + +RUBY_SYMBOL_EXPORT_BEGIN +/* file.c (export) */ +#ifdef HAVE_READLINK +VALUE rb_readlink(VALUE path, rb_encoding *enc); +#endif +#ifdef __APPLE__ +VALUE rb_str_normalize_ospath(const char *ptr, long len); +#endif +RUBY_SYMBOL_EXPORT_END + +#endif /* INTERNAL_FILE_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/fixnum.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/fixnum.h new file mode 100644 index 0000000..b78e314 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/fixnum.h @@ -0,0 +1,185 @@ +#ifndef INTERNAL_FIXNUM_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_FIXNUM_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Fixnums. + */ +#include "ruby/internal/config.h" /* for HAVE_LONG_LONG */ +#include /* for CHAR_BIT */ +#include "internal/bits.h" /* for MUL_OVERFLOW_FIXNUM_P */ +#include "internal/compilers.h" /* for __has_builtin */ +#include "ruby/internal/stdbool.h" /* for bool */ +#include "ruby/intern.h" /* for rb_big_mul */ +#include "ruby/ruby.h" /* for RB_FIXABLE */ + +#if HAVE_LONG_LONG && SIZEOF_LONG * 2 <= SIZEOF_LONG_LONG +# define DLONG LONG_LONG +# define DL2NUM(x) LL2NUM(x) +#elif defined(HAVE_INT128_T) && !(defined(__OpenBSD__) && defined(__mips64__)) +# define DLONG int128_t +# define DL2NUM(x) (RB_FIXABLE(x) ? LONG2FIX(x) : rb_int128t2big(x)) +VALUE rb_int128t2big(int128_t n); /* in bignum.c */ +#endif + +static inline long rb_overflowed_fix_to_int(long x); +static inline VALUE rb_fix_plus_fix(VALUE x, VALUE y); +static inline VALUE rb_fix_minus_fix(VALUE x, VALUE y); +static inline VALUE rb_fix_mul_fix(VALUE x, VALUE y); +static inline void rb_fix_divmod_fix(VALUE x, VALUE y, VALUE *divp, VALUE *modp); +static inline VALUE rb_fix_div_fix(VALUE x, VALUE y); +static inline VALUE rb_fix_mod_fix(VALUE x, VALUE y); +static inline bool FIXNUM_POSITIVE_P(VALUE num); +static inline bool FIXNUM_NEGATIVE_P(VALUE num); +static inline bool FIXNUM_ZERO_P(VALUE num); + +static inline long +rb_overflowed_fix_to_int(long x) +{ + return (long)((unsigned long)(x >> 1) ^ (1LU << (SIZEOF_LONG * CHAR_BIT - 1))); +} + +static inline VALUE +rb_fix_plus_fix(VALUE x, VALUE y) +{ +#if !__has_builtin(__builtin_add_overflow) + long lz = FIX2LONG(x) + FIX2LONG(y); + return LONG2NUM(lz); +#else + long lz; + /* NOTE + * (1) `LONG2FIX(FIX2LONG(x)+FIX2LONG(y))` + + = `((lx*2+1)/2 + (ly*2+1)/2)*2+1` + + = `lx*2 + ly*2 + 1` + + = `(lx*2+1) + (ly*2+1) - 1` + + = `x + y - 1` + * (2) Fixnum's LSB is always 1. + * It means you can always run `x - 1` without overflow. + * (3) Of course `z = x + (y-1)` may overflow. + * At that time true value is + * * positive: 0b0 1xxx...1, and z = 0b1xxx...1 + * * negative: 0b1 0xxx...1, and z = 0b0xxx...1 + * To convert this true value to long, + * (a) Use arithmetic shift + * * positive: 0b11xxx... + * * negative: 0b00xxx... + * (b) invert MSB + * * positive: 0b01xxx... + * * negative: 0b10xxx... + */ + if (__builtin_add_overflow((long)x, (long)y-1, &lz)) { + return rb_int2big(rb_overflowed_fix_to_int(lz)); + } + else { + return (VALUE)lz; + } +#endif +} + +static inline VALUE +rb_fix_minus_fix(VALUE x, VALUE y) +{ +#if !__has_builtin(__builtin_sub_overflow) + long lz = FIX2LONG(x) - FIX2LONG(y); + return LONG2NUM(lz); +#else + long lz; + if (__builtin_sub_overflow((long)x, (long)y-1, &lz)) { + return rb_int2big(rb_overflowed_fix_to_int(lz)); + } + else { + return (VALUE)lz; + } +#endif +} + +/* arguments must be Fixnum */ +static inline VALUE +rb_fix_mul_fix(VALUE x, VALUE y) +{ + long lx = FIX2LONG(x); + long ly = FIX2LONG(y); +#ifdef DLONG + return DL2NUM((DLONG)lx * (DLONG)ly); +#else + if (MUL_OVERFLOW_FIXNUM_P(lx, ly)) { + return rb_big_mul(rb_int2big(lx), rb_int2big(ly)); + } + else { + return LONG2FIX(lx * ly); + } +#endif +} + +/* + * This behaves different from C99 for negative arguments. + * Note that div may overflow fixnum. + */ +static inline void +rb_fix_divmod_fix(VALUE a, VALUE b, VALUE *divp, VALUE *modp) +{ + /* assume / and % comply C99. + * ldiv(3) won't be inlined by GCC and clang. + * I expect / and % are compiled as single idiv. + */ + long x = FIX2LONG(a); + long y = FIX2LONG(b); + long div, mod; + if (x == FIXNUM_MIN && y == -1) { + if (divp) *divp = LONG2NUM(-FIXNUM_MIN); + if (modp) *modp = LONG2FIX(0); + return; + } + div = x / y; + mod = x % y; + if (y > 0 ? mod < 0 : mod > 0) { + mod += y; + div -= 1; + } + if (divp) *divp = LONG2FIX(div); + if (modp) *modp = LONG2FIX(mod); +} + +/* div() for Ruby + * This behaves different from C99 for negative arguments. + */ +static inline VALUE +rb_fix_div_fix(VALUE x, VALUE y) +{ + VALUE div; + rb_fix_divmod_fix(x, y, &div, NULL); + return div; +} + +/* mod() for Ruby + * This behaves different from C99 for negative arguments. + */ +static inline VALUE +rb_fix_mod_fix(VALUE x, VALUE y) +{ + VALUE mod; + rb_fix_divmod_fix(x, y, NULL, &mod); + return mod; +} + +static inline bool +FIXNUM_POSITIVE_P(VALUE num) +{ + return (SIGNED_VALUE)num > (SIGNED_VALUE)INT2FIX(0); +} + +static inline bool +FIXNUM_NEGATIVE_P(VALUE num) +{ + return (SIGNED_VALUE)num < 0; +} + +static inline bool +FIXNUM_ZERO_P(VALUE num) +{ + return num == INT2FIX(0); +} +#endif /* INTERNAL_FIXNUM_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/gc.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/gc.h new file mode 100644 index 0000000..ec408d7 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/gc.h @@ -0,0 +1,358 @@ +#ifndef INTERNAL_GC_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_GC_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for GC. + */ +#include "ruby/internal/config.h" + +#include /* for size_t */ + +#include "internal/compilers.h" /* for __has_attribute */ +#include "ruby/ruby.h" /* for rb_event_flag_t */ +#include "vm_core.h" /* for GET_EC() */ + +#ifndef USE_MODULAR_GC +# define USE_MODULAR_GC 0 +#endif + +#if defined(__x86_64__) && !defined(_ILP32) && defined(__GNUC__) +#define SET_MACHINE_STACK_END(p) __asm__ __volatile__ ("movq\t%%rsp, %0" : "=r" (*(p))) +#elif defined(__i386) && defined(__GNUC__) +#define SET_MACHINE_STACK_END(p) __asm__ __volatile__ ("movl\t%%esp, %0" : "=r" (*(p))) +#elif (defined(__powerpc__) || defined(__powerpc64__)) && defined(__GNUC__) && !defined(_AIX) && !defined(__APPLE__) // Not Apple is NEEDED to unbreak ppc64 build on Darwin. Don't ask. +#define SET_MACHINE_STACK_END(p) __asm__ __volatile__ ("mr\t%0, %%r1" : "=r" (*(p))) +#elif (defined(__powerpc__) || defined(__powerpc64__)) && defined(__GNUC__) && defined(_AIX) +#define SET_MACHINE_STACK_END(p) __asm__ __volatile__ ("mr %0,1" : "=r" (*(p))) +#elif defined(__POWERPC__) && defined(__APPLE__) // Darwin ppc and ppc64 +#define SET_MACHINE_STACK_END(p) __asm__ volatile("mr %0, r1" : "=r" (*(p))) +#elif defined(__aarch64__) && defined(__GNUC__) +#define SET_MACHINE_STACK_END(p) __asm__ __volatile__ ("mov\t%0, sp" : "=r" (*(p))) +#else +NOINLINE(void rb_gc_set_stack_end(VALUE **stack_end_p)); +#define SET_MACHINE_STACK_END(p) rb_gc_set_stack_end(p) +#define USE_CONSERVATIVE_STACK_END +#endif + +/* for GC debug */ + +#ifndef RUBY_MARK_FREE_DEBUG +#define RUBY_MARK_FREE_DEBUG 0 +#endif + +#if RUBY_MARK_FREE_DEBUG +extern int ruby_gc_debug_indent; + +static inline void +rb_gc_debug_indent(void) +{ + ruby_debug_printf("%*s", ruby_gc_debug_indent, ""); +} + +static inline void +rb_gc_debug_body(const char *mode, const char *msg, int st, void *ptr) +{ + if (st == 0) { + ruby_gc_debug_indent--; + } + rb_gc_debug_indent(); + ruby_debug_printf("%s: %s %s (%p)\n", mode, st ? "->" : "<-", msg, ptr); + + if (st) { + ruby_gc_debug_indent++; + } + + fflush(stdout); +} + +#define RUBY_MARK_ENTER(msg) rb_gc_debug_body("mark", (msg), 1, ptr) +#define RUBY_MARK_LEAVE(msg) rb_gc_debug_body("mark", (msg), 0, ptr) +#define RUBY_FREE_ENTER(msg) rb_gc_debug_body("free", (msg), 1, ptr) +#define RUBY_FREE_LEAVE(msg) rb_gc_debug_body("free", (msg), 0, ptr) +#define RUBY_GC_INFO rb_gc_debug_indent(), ruby_debug_printf + +#else +#define RUBY_MARK_ENTER(msg) +#define RUBY_MARK_LEAVE(msg) +#define RUBY_FREE_ENTER(msg) +#define RUBY_FREE_LEAVE(msg) +#define RUBY_GC_INFO if(0)printf +#endif + +#define RUBY_FREE_UNLESS_NULL(ptr) if(ptr){ruby_xfree(ptr);(ptr)=NULL;} + +#if STACK_GROW_DIRECTION > 0 +# define STACK_UPPER(x, a, b) (a) +#elif STACK_GROW_DIRECTION < 0 +# define STACK_UPPER(x, a, b) (b) +#else +RUBY_EXTERN int ruby_stack_grow_direction; +int ruby_get_stack_grow_direction(volatile VALUE *addr); +# define stack_growup_p(x) ( \ + (ruby_stack_grow_direction ? \ + ruby_stack_grow_direction : \ + ruby_get_stack_grow_direction(x)) > 0) +# define STACK_UPPER(x, a, b) (stack_growup_p(x) ? (a) : (b)) +#endif + +/* + STACK_GROW_DIR_DETECTION is used with STACK_DIR_UPPER. + + On most normal systems, stacks grow from high address to lower address. In + this case, STACK_DIR_UPPER(a, b) will return (b), but on exotic systems where + the stack grows UP (from low address to high address), it will return (a). +*/ + +#if STACK_GROW_DIRECTION +#define STACK_GROW_DIR_DETECTION +#define STACK_DIR_UPPER(a,b) STACK_UPPER(0, (a), (b)) +#else +#define STACK_GROW_DIR_DETECTION VALUE stack_grow_dir_detection +#define STACK_DIR_UPPER(a,b) STACK_UPPER(&stack_grow_dir_detection, (a), (b)) +#endif +#define IS_STACK_DIR_UPPER() STACK_DIR_UPPER(1,0) + +const char *rb_obj_info(VALUE obj); +const char *rb_raw_obj_info(char *const buff, const size_t buff_size, VALUE obj); + +struct rb_execution_context_struct; /* in vm_core.h */ +struct rb_objspace; /* in vm_core.h */ + +#define NEWOBJ_OF(var, T, c, f, s, ec) \ + T *(var) = (T *)(((f) & FL_WB_PROTECTED) ? \ + rb_wb_protected_newobj_of((ec ? ec : GET_EC()), (c), (f) & ~FL_WB_PROTECTED, s) : \ + rb_wb_unprotected_newobj_of((c), (f), s)) + +#ifndef RB_GC_OBJECT_METADATA_ENTRY_DEFINED +# define RB_GC_OBJECT_METADATA_ENTRY_DEFINED +struct rb_gc_object_metadata_entry { + ID name; + VALUE val; +}; +#endif + +#ifndef USE_UNALIGNED_MEMBER_ACCESS +# define UNALIGNED_MEMBER_ACCESS(expr) (expr) +#elif ! USE_UNALIGNED_MEMBER_ACCESS +# define UNALIGNED_MEMBER_ACCESS(expr) (expr) +#elif ! (__has_warning("-Waddress-of-packed-member") || GCC_VERSION_SINCE(9, 0, 0)) +# define UNALIGNED_MEMBER_ACCESS(expr) (expr) +#else +# include "internal/warnings.h" +# define UNALIGNED_MEMBER_ACCESS(expr) __extension__({ \ + COMPILER_WARNING_PUSH; \ + COMPILER_WARNING_IGNORED(-Waddress-of-packed-member); \ + __typeof__(expr) unaligned_member_access_result = (expr); \ + COMPILER_WARNING_POP; \ + unaligned_member_access_result; \ +}) + +# define UNALIGNED_MEMBER_PTR(ptr, mem) __extension__({ \ + COMPILER_WARNING_PUSH; \ + COMPILER_WARNING_IGNORED(-Waddress-of-packed-member); \ + const volatile void *unaligned_member_ptr_result = &(ptr)->mem; \ + COMPILER_WARNING_POP; \ + (__typeof__((ptr)->mem) *)unaligned_member_ptr_result; \ +}) +#endif + +#ifndef UNALIGNED_MEMBER_PTR +# define UNALIGNED_MEMBER_PTR(ptr, mem) UNALIGNED_MEMBER_ACCESS(&(ptr)->mem) +#endif + +#define RB_OBJ_WRITE_UNALIGNED(old, slot, young) do { \ + VALUE *_slot = UNALIGNED_MEMBER_ACCESS(slot); \ + RB_OBJ_WRITE(old, _slot, young); \ +} while (0) + +/* Used in places that could malloc during, which can cause the GC to run. We + * need to temporarily disable the GC to allow the malloc to happen. + * Allocating memory during GC is a bad idea, so use this only when absolutely + * necessary. */ +#define DURING_GC_COULD_MALLOC_REGION_START() \ + assert(rb_during_gc()); \ + VALUE _already_disabled = rb_gc_disable_no_rest() + +#define DURING_GC_COULD_MALLOC_REGION_END() \ + if (_already_disabled == Qfalse) rb_gc_enable() + +/* gc.c */ +RUBY_ATTR_MALLOC void *ruby_mimmalloc(size_t size); +RUBY_ATTR_MALLOC void *ruby_mimcalloc(size_t num, size_t size); +void ruby_mimfree(void *ptr); +void rb_gc_prepare_heap(void); +void rb_objspace_set_event_hook(const rb_event_flag_t event); +VALUE rb_objspace_gc_enable(void *objspace); +VALUE rb_objspace_gc_disable(void *objspace); +void ruby_gc_set_params(void); +void rb_gc_copy_attributes(VALUE dest, VALUE obj); +size_t rb_size_mul_or_raise(size_t, size_t, VALUE); /* used in compile.c */ +size_t rb_size_mul_add_or_raise(size_t, size_t, size_t, VALUE); /* used in iseq.h */ +size_t rb_malloc_grow_capa(size_t current_capacity, size_t type_size); +RUBY_ATTR_MALLOC void *rb_xmalloc_mul_add(size_t, size_t, size_t); +RUBY_ATTR_MALLOC void *rb_xcalloc_mul_add(size_t, size_t, size_t); +void *rb_xrealloc_mul_add(const void *, size_t, size_t, size_t); +RUBY_ATTR_MALLOC void *rb_xmalloc_mul_add_mul(size_t, size_t, size_t, size_t); +RUBY_ATTR_MALLOC void *rb_xcalloc_mul_add_mul(size_t, size_t, size_t, size_t); +static inline void *ruby_sized_xrealloc_inlined(void *ptr, size_t new_size, size_t old_size) RUBY_ATTR_RETURNS_NONNULL RUBY_ATTR_ALLOC_SIZE((2)); +static inline void *ruby_sized_xrealloc2_inlined(void *ptr, size_t new_count, size_t elemsiz, size_t old_count) RUBY_ATTR_RETURNS_NONNULL RUBY_ATTR_ALLOC_SIZE((2, 3)); +static inline void ruby_sized_xfree_inlined(void *ptr, size_t size); +void rb_gc_obj_id_moved(VALUE obj); + +void *rb_gc_ractor_cache_alloc(rb_ractor_t *ractor); +void rb_gc_ractor_cache_free(void *cache); + +bool rb_gc_size_allocatable_p(size_t size); +size_t *rb_gc_heap_sizes(void); +size_t rb_gc_heap_id_for_size(size_t size); + +void rb_gc_mark_and_move(VALUE *ptr); + +void rb_gc_mark_weak(VALUE *ptr); +void rb_gc_remove_weak(VALUE parent_obj, VALUE *ptr); + +void rb_gc_ref_update_table_values_only(st_table *tbl); + +void rb_gc_initial_stress_set(VALUE flag); + +void rb_gc_before_fork(void); +void rb_gc_after_fork(rb_pid_t pid); + +#define rb_gc_mark_and_move_ptr(ptr) do { \ + VALUE _obj = (VALUE)*(ptr); \ + rb_gc_mark_and_move(&_obj); \ + if (_obj != (VALUE)*(ptr)) *(ptr) = (void *)_obj; \ +} while (0) + +RUBY_SYMBOL_EXPORT_BEGIN +/* exports for objspace module */ +void rb_objspace_reachable_objects_from(VALUE obj, void (func)(VALUE, void *), void *data); +void rb_objspace_reachable_objects_from_root(void (func)(const char *category, VALUE, void *), void *data); +int rb_objspace_internal_object_p(VALUE obj); +int rb_objspace_garbage_object_p(VALUE obj); +bool rb_gc_pointer_to_heap_p(VALUE obj); + +void rb_objspace_each_objects( + int (*callback)(void *start, void *end, size_t stride, void *data), + void *data); + +size_t rb_gc_obj_slot_size(VALUE obj); + +VALUE rb_gc_disable_no_rest(void); + +#define RB_GC_MAX_NAME_LEN 20 + +/* gc.c (export) */ +const char *rb_objspace_data_type_name(VALUE obj); +VALUE rb_wb_protected_newobj_of(struct rb_execution_context_struct *, VALUE, VALUE, size_t); +VALUE rb_wb_unprotected_newobj_of(VALUE, VALUE, size_t); +size_t rb_obj_memsize_of(VALUE); +struct rb_gc_object_metadata_entry *rb_gc_object_metadata(VALUE obj); +void rb_gc_mark_values(long n, const VALUE *values); +void rb_gc_mark_vm_stack_values(long n, const VALUE *values); +void rb_gc_update_values(long n, VALUE *values); +void *ruby_sized_xrealloc(void *ptr, size_t new_size, size_t old_size) RUBY_ATTR_RETURNS_NONNULL RUBY_ATTR_ALLOC_SIZE((2)); +void *ruby_sized_xrealloc2(void *ptr, size_t new_count, size_t element_size, size_t old_count) RUBY_ATTR_RETURNS_NONNULL RUBY_ATTR_ALLOC_SIZE((2, 3)); +void ruby_sized_xfree(void *x, size_t size); + +const char *rb_gc_active_gc_name(void); +int rb_gc_modular_gc_loaded_p(void); + +RUBY_SYMBOL_EXPORT_END + +static inline VALUE +rb_obj_atomic_write( + VALUE a, VALUE *slot, VALUE b, + RBIMPL_ATTR_MAYBE_UNUSED() + const char *filename, + RBIMPL_ATTR_MAYBE_UNUSED() + int line) +{ +#ifdef RGENGC_LOGGING_WRITE + RGENGC_LOGGING_WRITE(a, slot, b, filename, line); +#endif + + RUBY_ATOMIC_VALUE_SET(*slot, b); + + rb_obj_written(a, RUBY_Qundef /* ignore `oldv' now */, b, filename, line); + return a; +} +#define RB_OBJ_ATOMIC_WRITE(old, slot, young) \ + RBIMPL_CAST(rb_obj_atomic_write((VALUE)(old), (VALUE *)(slot), (VALUE)(young), __FILE__, __LINE__)) + +int rb_ec_stack_check(struct rb_execution_context_struct *ec); +void rb_gc_writebarrier_remember(VALUE obj); +const char *rb_obj_info(VALUE obj); +void ruby_annotate_mmap(const void *addr, unsigned long size, const char *name); + +#if defined(HAVE_MALLOC_USABLE_SIZE) || defined(HAVE_MALLOC_SIZE) || defined(_WIN32) + +static inline void * +ruby_sized_xrealloc_inlined(void *ptr, size_t new_size, size_t old_size) +{ + return ruby_xrealloc(ptr, new_size); +} + +static inline void * +ruby_sized_xrealloc2_inlined(void *ptr, size_t new_count, size_t elemsiz, size_t old_count) +{ + return ruby_xrealloc2(ptr, new_count, elemsiz); +} + +static inline void +ruby_sized_xfree_inlined(void *ptr, size_t size) +{ + ruby_xfree(ptr); +} + +# define SIZED_REALLOC_N(x, y, z, w) REALLOC_N(x, y, z) + +static inline void * +ruby_sized_realloc_n(void *ptr, size_t new_count, size_t element_size, size_t old_count) +{ + return ruby_xrealloc2(ptr, new_count, element_size); +} + +#else + +static inline void * +ruby_sized_xrealloc_inlined(void *ptr, size_t new_size, size_t old_size) +{ + return ruby_sized_xrealloc(ptr, new_size, old_size); +} + +static inline void * +ruby_sized_xrealloc2_inlined(void *ptr, size_t new_count, size_t elemsiz, size_t old_count) +{ + return ruby_sized_xrealloc2(ptr, new_count, elemsiz, old_count); +} + +static inline void +ruby_sized_xfree_inlined(void *ptr, size_t size) +{ + ruby_sized_xfree(ptr, size); +} + +# define SIZED_REALLOC_N(v, T, m, n) \ + ((v) = (T *)ruby_sized_xrealloc2((void *)(v), (m), sizeof(T), (n))) + +static inline void * +ruby_sized_realloc_n(void *ptr, size_t new_count, size_t element_size, size_t old_count) +{ + return ruby_sized_xrealloc2(ptr, new_count, element_size, old_count); +} + +#endif /* HAVE_MALLOC_USABLE_SIZE */ + +#define ruby_sized_xrealloc ruby_sized_xrealloc_inlined +#define ruby_sized_xrealloc2 ruby_sized_xrealloc2_inlined +#define ruby_sized_xfree ruby_sized_xfree_inlined + +void rb_gc_verify_shareable(VALUE); +bool rb_gc_checking_shareable(void); + +#endif /* INTERNAL_GC_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/hash.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/hash.h new file mode 100644 index 0000000..03cd830 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/hash.h @@ -0,0 +1,194 @@ +#ifndef INTERNAL_HASH_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_HASH_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Hash. + */ +#include "ruby/internal/config.h" +#include /* for size_t */ +#include "ruby/internal/stdbool.h" /* for bool */ +#include "ruby/ruby.h" /* for struct RBasic */ +#include "ruby/st.h" /* for struct st_table */ + +#define RHASH_AR_TABLE_MAX_SIZE SIZEOF_VALUE + +struct ar_table_struct; +typedef unsigned char ar_hint_t; + +enum ruby_rhash_flags { + RHASH_PASS_AS_KEYWORDS = FL_USER1, /* FL 1 */ + RHASH_PROC_DEFAULT = FL_USER2, /* FL 2 */ + RHASH_ST_TABLE_FLAG = FL_USER3, /* FL 3 */ + RHASH_AR_TABLE_SIZE_MASK = (FL_USER4|FL_USER5|FL_USER6|FL_USER7), /* FL 4..7 */ + RHASH_AR_TABLE_SIZE_SHIFT = (FL_USHIFT+4), + RHASH_AR_TABLE_BOUND_MASK = (FL_USER8|FL_USER9|FL_USER10|FL_USER11), /* FL 8..11 */ + RHASH_AR_TABLE_BOUND_SHIFT = (FL_USHIFT+8), + + // we can not put it in "enum" because it can exceed "int" range. +#define RHASH_LEV_MASK (FL_USER13 | FL_USER14 | FL_USER15 | /* FL 13..19 */ \ + FL_USER16 | FL_USER17 | FL_USER18 | FL_USER19) + + RHASH_LEV_SHIFT = (FL_USHIFT + 13), + RHASH_LEV_MAX = 127, /* 7 bits */ +}; + +typedef struct ar_table_pair_struct { + VALUE key; + VALUE val; +} ar_table_pair; + +typedef struct ar_table_struct { + union { + ar_hint_t ary[RHASH_AR_TABLE_MAX_SIZE]; + VALUE word; + } ar_hint; + /* 64bit CPU: 8B * 2 * 8 = 128B */ + ar_table_pair pairs[RHASH_AR_TABLE_MAX_SIZE]; +} ar_table; + +struct RHash { + struct RBasic basic; + const VALUE ifnone; +}; + +#define RHASH(obj) ((struct RHash *)(obj)) + +#ifdef RHASH_IFNONE +# undef RHASH_IFNONE +#endif + +#ifdef RHASH_SIZE +# undef RHASH_SIZE +#endif + +#ifdef RHASH_EMPTY_P +# undef RHASH_EMPTY_P +#endif + +/* hash.c */ +void rb_hash_st_table_set(VALUE hash, st_table *st); +VALUE rb_hash_default_value(VALUE hash, VALUE key); +VALUE rb_hash_set_default(VALUE hash, VALUE ifnone); +VALUE rb_hash_set_default_proc(VALUE hash, VALUE proc); +long rb_dbl_long_hash(double d); +st_table *rb_init_identtable(void); +st_index_t rb_any_hash(VALUE a); +int rb_any_cmp(VALUE a, VALUE b); +VALUE rb_to_hash_type(VALUE obj); +VALUE rb_hash_key_str(VALUE); +VALUE rb_hash_values(VALUE hash); +VALUE rb_hash_rehash(VALUE hash); +int rb_hash_add_new_element(VALUE hash, VALUE key, VALUE val); +VALUE rb_hash_set_pair(VALUE hash, VALUE pair); +int rb_hash_stlike_delete(VALUE hash, st_data_t *pkey, st_data_t *pval); +int rb_hash_stlike_foreach_with_replace(VALUE hash, st_foreach_check_callback_func *func, st_update_callback_func *replace, st_data_t arg); +int rb_hash_stlike_update(VALUE hash, st_data_t key, st_update_callback_func *func, st_data_t arg); +bool rb_hash_default_unredefined(VALUE hash); +VALUE rb_ident_hash_new_with_size(st_index_t size); +void rb_hash_free(VALUE hash); +RUBY_EXTERN VALUE rb_cHash_empty_frozen; + +static inline unsigned RHASH_AR_TABLE_SIZE_RAW(VALUE h); +static inline VALUE RHASH_IFNONE(VALUE h); +static inline size_t RHASH_SIZE(VALUE h); +static inline bool RHASH_EMPTY_P(VALUE h); +static inline bool RHASH_AR_TABLE_P(VALUE h); +static inline bool RHASH_ST_TABLE_P(VALUE h); +static inline struct ar_table_struct *RHASH_AR_TABLE(VALUE h); +static inline st_table *RHASH_ST_TABLE(VALUE h); +static inline size_t RHASH_ST_SIZE(VALUE h); +static inline void RHASH_ST_CLEAR(VALUE h); + +RUBY_SYMBOL_EXPORT_BEGIN +/* hash.c (export) */ +VALUE rb_hash_delete_entry(VALUE hash, VALUE key); +VALUE rb_ident_hash_new(void); +int rb_hash_stlike_foreach(VALUE hash, st_foreach_callback_func *func, st_data_t arg); +RUBY_SYMBOL_EXPORT_END + +VALUE rb_hash_new_with_size(st_index_t size); +VALUE rb_hash_resurrect(VALUE hash); +int rb_hash_stlike_lookup(VALUE hash, st_data_t key, st_data_t *pval); +VALUE rb_hash_keys(VALUE hash); +VALUE rb_hash_has_key(VALUE hash, VALUE key); +VALUE rb_hash_compare_by_id_p(VALUE hash); + +st_table *rb_hash_tbl_raw(VALUE hash, const char *file, int line); +#define RHASH_TBL_RAW(h) rb_hash_tbl_raw(h, __FILE__, __LINE__) + +VALUE rb_hash_compare_by_id(VALUE hash); + +static inline bool +RHASH_AR_TABLE_P(VALUE h) +{ + return ! FL_TEST_RAW(h, RHASH_ST_TABLE_FLAG); +} + +RBIMPL_ATTR_RETURNS_NONNULL() +static inline struct ar_table_struct * +RHASH_AR_TABLE(VALUE h) +{ + return (struct ar_table_struct *)((uintptr_t)h + sizeof(struct RHash)); +} + +RBIMPL_ATTR_RETURNS_NONNULL() +static inline st_table * +RHASH_ST_TABLE(VALUE h) +{ + return (st_table *)((uintptr_t)h + sizeof(struct RHash)); +} + +static inline VALUE +RHASH_IFNONE(VALUE h) +{ + return RHASH(h)->ifnone; +} + +static inline size_t +RHASH_SIZE(VALUE h) +{ + if (RHASH_AR_TABLE_P(h)) { + return RHASH_AR_TABLE_SIZE_RAW(h); + } + else { + return RHASH_ST_SIZE(h); + } +} + +static inline bool +RHASH_EMPTY_P(VALUE h) +{ + return RHASH_SIZE(h) == 0; +} + +static inline bool +RHASH_ST_TABLE_P(VALUE h) +{ + return ! RHASH_AR_TABLE_P(h); +} + +static inline size_t +RHASH_ST_SIZE(VALUE h) +{ + return RHASH_ST_TABLE(h)->num_entries; +} + +static inline void +RHASH_ST_CLEAR(VALUE h) +{ + memset(RHASH_ST_TABLE(h), 0, sizeof(st_table)); +} + +static inline unsigned +RHASH_AR_TABLE_SIZE_RAW(VALUE h) +{ + VALUE ret = FL_TEST_RAW(h, RHASH_AR_TABLE_SIZE_MASK); + ret >>= RHASH_AR_TABLE_SIZE_SHIFT; + return (unsigned)ret; +} + +#endif /* INTERNAL_HASH_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/imemo.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/imemo.h new file mode 100644 index 0000000..f8bda26 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/imemo.h @@ -0,0 +1,322 @@ +#ifndef INTERNAL_IMEMO_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_IMEMO_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief IMEMO: Internal memo object. + */ +#include "ruby/internal/config.h" +#include /* for size_t */ +#include "id_table.h" +#include "internal/array.h" /* for rb_ary_hidden_new_fill */ +#include "ruby/internal/stdbool.h" /* for bool */ +#include "ruby/ruby.h" /* for rb_block_call_func_t */ + +#define IMEMO_MASK 0x0f + +/* FL_USER0 to FL_USER3 is for type */ +#define IMEMO_FL_USHIFT (FL_USHIFT + 4) +#define IMEMO_FL_USER0 FL_USER4 +#define IMEMO_FL_USER1 FL_USER5 +#define IMEMO_FL_USER2 FL_USER6 +#define IMEMO_FL_USER3 FL_USER7 +#define IMEMO_FL_USER4 FL_USER8 +#define IMEMO_FL_USER5 FL_USER9 +#define IMEMO_FL_USER6 FL_USER10 + +enum imemo_type { + imemo_env = 0, + imemo_cref = 1, /*!< class reference */ + imemo_svar = 2, /*!< special variable */ + imemo_throw_data = 3, + imemo_ifunc = 4, /*!< iterator function */ + imemo_memo = 5, + imemo_ment = 6, + imemo_iseq = 7, + imemo_tmpbuf = 8, + imemo_callinfo = 10, + imemo_callcache = 11, + imemo_constcache = 12, + imemo_fields = 13, +}; + +/* CREF (Class REFerence) is defined in method.h */ + +/*! SVAR (Special VARiable) */ +struct vm_svar { + VALUE flags; + const VALUE cref_or_me; /*!< class reference or rb_method_entry_t */ + const VALUE lastline; + const VALUE backref; + const VALUE others; +}; + +/*! THROW_DATA */ +struct vm_throw_data { + VALUE flags; + VALUE reserved; + const VALUE throw_obj; + const struct rb_control_frame_struct *catch_frame; + int throw_state; +}; + +#define THROW_DATA_CONSUMED IMEMO_FL_USER0 + +/* IFUNC (Internal FUNCtion) */ + +struct vm_ifunc_argc { +#if SIZEOF_INT * 2 > SIZEOF_VALUE + signed int min: (SIZEOF_VALUE * CHAR_BIT) / 2; + signed int max: (SIZEOF_VALUE * CHAR_BIT) / 2; +#else + int min, max; +#endif +}; + +/*! IFUNC (Internal FUNCtion) + * + * Bookkeeping for converting a C function and some closed-over data into a + * block passable to methods. Like Ruby Proc, but not directly accessible at + * Ruby level since this is an imemo. See rb_block_call() and friends. + */ +struct vm_ifunc { + VALUE flags; + VALUE *svar_lep; + rb_block_call_func_t func; + const void *data; + struct vm_ifunc_argc argc; +}; +#define IFUNC_YIELD_OPTIMIZABLE IMEMO_FL_USER0 + +struct rb_imemo_tmpbuf_struct { + VALUE flags; + VALUE *ptr; /* malloc'ed buffer */ + size_t cnt; /* buffer size in VALUE */ +}; + +/*! MEMO + * + * @see imemo_type + * */ +struct MEMO { + VALUE flags; + VALUE reserved; + const VALUE v1; + const VALUE v2; + union { + long cnt; + long state; + const VALUE value; + void (*func)(void); + } u3; +}; + +#define IMEMO_NEW(T, type, v0) ((T *)rb_imemo_new((type), (v0), sizeof(T), false)) +#define SHAREABLE_IMEMO_NEW(T, type, v0) ((T *)rb_imemo_new((type), (v0), sizeof(T), true)) + +/* ment is in method.h */ + +#define THROW_DATA_P(err) imemo_throw_data_p((VALUE)err) +#define MEMO_CAST(m) ((struct MEMO *)(m)) +#define MEMO_FOR(type, value) ((type *)RARRAY_PTR(value)) +#define NEW_MEMO_FOR(type, value) \ + ((value) = rb_ary_hidden_new_fill(type_roomof(type, VALUE)), MEMO_FOR(type, value)) +#define NEW_PARTIAL_MEMO_FOR(type, value, member) \ + ((value) = rb_ary_hidden_new_fill(type_roomof(type, VALUE)), \ + rb_ary_set_len((value), offsetof(type, member) / sizeof(VALUE)), \ + MEMO_FOR(type, value)) + +#ifndef RUBY_RUBYPARSER_H +typedef struct rb_imemo_tmpbuf_struct rb_imemo_tmpbuf_t; +#endif +VALUE rb_imemo_new(enum imemo_type type, VALUE v0, size_t size, bool is_shareable); +VALUE rb_imemo_tmpbuf_new(void); +struct vm_ifunc *rb_vm_ifunc_new(rb_block_call_func_t func, const void *data, int min_argc, int max_argc); +static inline enum imemo_type imemo_type(VALUE imemo); +static inline int imemo_type_p(VALUE imemo, enum imemo_type imemo_type); +static inline bool imemo_throw_data_p(VALUE imemo); +static inline struct vm_ifunc *rb_vm_ifunc_proc_new(rb_block_call_func_t func, const void *data); +static inline void *RB_IMEMO_TMPBUF_PTR(VALUE v); +static inline void *rb_imemo_tmpbuf_set_ptr(VALUE v, void *ptr); +static inline void MEMO_V1_SET(struct MEMO *m, VALUE v); +static inline void MEMO_V2_SET(struct MEMO *m, VALUE v); + +size_t rb_imemo_memsize(VALUE obj); +void rb_imemo_mark_and_move(VALUE obj, bool reference_updating); +void rb_imemo_free(VALUE obj); + +RUBY_SYMBOL_EXPORT_BEGIN +const char *rb_imemo_name(enum imemo_type type); +RUBY_SYMBOL_EXPORT_END + +static inline struct MEMO * +MEMO_NEW(VALUE a, VALUE b, VALUE c) +{ + struct MEMO *memo = IMEMO_NEW(struct MEMO, imemo_memo, 0); + *((VALUE *)&memo->v1) = a; + *((VALUE *)&memo->v2) = b; + *((VALUE *)&memo->u3.value) = c; + + return memo; +} + +static inline enum imemo_type +imemo_type(VALUE imemo) +{ + return (RBASIC(imemo)->flags >> FL_USHIFT) & IMEMO_MASK; +} + +static inline int +imemo_type_p(VALUE imemo, enum imemo_type imemo_type) +{ + if (LIKELY(!RB_SPECIAL_CONST_P(imemo))) { + /* fixed at compile time if imemo_type is given. */ + const VALUE mask = (IMEMO_MASK << FL_USHIFT) | RUBY_T_MASK; + const VALUE expected_type = (imemo_type << FL_USHIFT) | T_IMEMO; + /* fixed at runtime. */ + return expected_type == (RBASIC(imemo)->flags & mask); + } + else { + return 0; + } +} + +#define IMEMO_TYPE_P(v, t) imemo_type_p((VALUE)(v), t) + +static inline bool +imemo_throw_data_p(VALUE imemo) +{ + return RB_TYPE_P(imemo, T_IMEMO); +} + +static inline struct vm_ifunc * +rb_vm_ifunc_proc_new(rb_block_call_func_t func, const void *data) +{ + return rb_vm_ifunc_new(func, data, 0, UNLIMITED_ARGUMENTS); +} + +static inline void * +RB_IMEMO_TMPBUF_PTR(VALUE v) +{ + const struct rb_imemo_tmpbuf_struct *p = (const void *)v; + return p->ptr; +} + +static inline void * +rb_imemo_tmpbuf_set_ptr(VALUE v, void *ptr) +{ + return ((rb_imemo_tmpbuf_t *)v)->ptr = ptr; +} + +static inline VALUE +rb_imemo_tmpbuf_new_from_an_RString(VALUE str) +{ + const void *src; + VALUE imemo; + rb_imemo_tmpbuf_t *tmpbuf; + void *dst; + size_t len; + + StringValue(str); + /* create tmpbuf to keep the pointer before xmalloc */ + imemo = rb_imemo_tmpbuf_new(); + tmpbuf = (rb_imemo_tmpbuf_t *)imemo; + len = RSTRING_LEN(str); + src = RSTRING_PTR(str); + dst = ruby_xmalloc(len); + memcpy(dst, src, len); + tmpbuf->ptr = dst; + return imemo; +} + +static inline void +MEMO_V1_SET(struct MEMO *m, VALUE v) +{ + RB_OBJ_WRITE(m, &m->v1, v); +} + +static inline void +MEMO_V2_SET(struct MEMO *m, VALUE v) +{ + RB_OBJ_WRITE(m, &m->v2, v); +} + +struct rb_fields { + struct RBasic basic; + union { + struct { + VALUE fields[1]; + } embed; + struct { + VALUE *ptr; + } external; + struct { + // Note: the st_table could be embedded, but complex T_CLASS should be rare to + // non-existent, so not really worth the trouble. + st_table *table; + } complex; + } as; +}; + +// IMEMO/fields and T_OBJECT have exactly the same layout. +// This is useful for JIT and common codepaths. +#define OBJ_FIELD_HEAP ROBJECT_HEAP +STATIC_ASSERT(imemo_fields_flags, OBJ_FIELD_HEAP == IMEMO_FL_USER0); +STATIC_ASSERT(imemo_fields_embed_offset, offsetof(struct RObject, as.ary) == offsetof(struct rb_fields, as.embed.fields)); +STATIC_ASSERT(imemo_fields_embed_offset, offsetof(struct RObject, as.heap.fields) == offsetof(struct rb_fields, as.external.ptr)); +STATIC_ASSERT(imemo_fields_embed_offset, offsetof(struct RObject, as.heap.fields) == offsetof(struct rb_fields, as.complex.table)); + +#define IMEMO_OBJ_FIELDS(fields) ((struct rb_fields *)fields) + +VALUE rb_imemo_fields_new(VALUE owner, size_t capa, bool shareable); +VALUE rb_imemo_fields_new_complex(VALUE owner, size_t capa, bool shareable); +VALUE rb_imemo_fields_new_complex_tbl(VALUE owner, st_table *tbl, bool shareable); +VALUE rb_imemo_fields_clone(VALUE fields_obj); +void rb_imemo_fields_clear(VALUE fields_obj); + +static inline VALUE +rb_imemo_fields_owner(VALUE fields_obj) +{ + RUBY_ASSERT(IMEMO_TYPE_P(fields_obj, imemo_fields)); + + return CLASS_OF(fields_obj); +} + +static inline VALUE * +rb_imemo_fields_ptr(VALUE fields_obj) +{ + if (!fields_obj) { + return NULL; + } + + RUBY_ASSERT(IMEMO_TYPE_P(fields_obj, imemo_fields) || RB_TYPE_P(fields_obj, T_OBJECT)); + + if (UNLIKELY(FL_TEST_RAW(fields_obj, OBJ_FIELD_HEAP))) { + return IMEMO_OBJ_FIELDS(fields_obj)->as.external.ptr; + } + else { + return IMEMO_OBJ_FIELDS(fields_obj)->as.embed.fields; + } +} + +static inline st_table * +rb_imemo_fields_complex_tbl(VALUE fields_obj) +{ + if (!fields_obj) { + return NULL; + } + + RUBY_ASSERT(IMEMO_TYPE_P(fields_obj, imemo_fields) || RB_TYPE_P(fields_obj, T_OBJECT)); + RUBY_ASSERT(FL_TEST_RAW(fields_obj, OBJ_FIELD_HEAP)); + + // Some codepaths unconditionally access the fields_ptr, and assume it can be used as st_table if the + // shape is too_complex. + RUBY_ASSERT((st_table *)rb_imemo_fields_ptr(fields_obj) == IMEMO_OBJ_FIELDS(fields_obj)->as.complex.table); + + return IMEMO_OBJ_FIELDS(fields_obj)->as.complex.table; +} + +#endif /* INTERNAL_IMEMO_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/inits.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/inits.h new file mode 100644 index 0000000..dee8182 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/inits.h @@ -0,0 +1,51 @@ +#ifndef INTERNAL_INITS_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_INITS_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header aggregating init functions. + */ + +/* box.c */ +void Init_enable_box(void); +void Init_root_box(void); + +/* class.c */ +void Init_class_hierarchy(void); + +/* dmyext.c */ +void Init_enc(void); +void Init_ext(void); + +/* file.c */ +void Init_File(void); + +/* localeinit.c */ +int Init_enc_set_filesystem_encoding(void); + +/* newline.c */ +void Init_newline(void); + +/* vm.c */ +void Init_BareVM(void); +void Init_vm_objects(void); + +/* vm_backtrace.c */ +void Init_vm_backtrace(void); + +/* vm_eval.c */ +void Init_vm_eval(void); + +/* vm_insnhelper.c */ +void Init_vm_stack_canary(void); + +/* vm_method.c */ +void Init_eval_method(void); + +/* inits.c */ +void rb_call_inits(void); + +#endif /* INTERNAL_INITS_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/io.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/io.h new file mode 100644 index 0000000..b81774e --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/io.h @@ -0,0 +1,163 @@ +#ifndef INTERNAL_IO_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_IO_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for IO. + */ +#include "ruby/ruby.h" /* for VALUE */ + +#define HAVE_RB_IO_T +struct rb_io; + +#include "ruby/io.h" /* for rb_io_t */ +#include "ccan/list/list.h" +#include "serial.h" + +#define IO_WITHOUT_GVL(func, arg) rb_nogvl(func, arg, RUBY_UBF_IO, 0, RB_NOGVL_OFFLOAD_SAFE) +#define IO_WITHOUT_GVL_INT(func, arg) (int)(VALUE)IO_WITHOUT_GVL(func, arg) + +// Represents an in-flight blocking operation: +struct rb_io_blocking_operation { + // The linked list data structure. + struct ccan_list_node list; + + // The execution context of the blocking operation. + struct rb_execution_context_struct *ec; +}; + +/** Ruby's IO, metadata and buffers. */ +struct rb_io { + + /** The IO's Ruby level counterpart. */ + VALUE self; + + /** stdio ptr for read/write, if available. */ + FILE *stdio_file; + + /** file descriptor. */ + int fd; + + /** mode flags: FMODE_XXXs */ + enum rb_io_mode mode; + + /** child's pid (for pipes) */ + rb_pid_t pid; + + /** number of lines read */ + int lineno; + + /** pathname for file */ + VALUE pathv; + + /** finalize proc */ + void (*finalize)(struct rb_io*,int); + + /** Write buffer. */ + rb_io_buffer_t wbuf; + + /** + * (Byte) read buffer. Note also that there is a field called + * ::rb_io_t::cbuf, which also concerns read IO. + */ + rb_io_buffer_t rbuf; + + /** + * Duplex IO object, if set. + * + * @see rb_io_set_write_io() + */ + VALUE tied_io_for_writing; + + struct rb_io_encoding encs; /**< Decomposed encoding flags. */ + + /** Encoding converter used when reading from this IO. */ + rb_econv_t *readconv; + + /** + * rb_io_ungetc() destination. This buffer is read before checking + * ::rb_io_t::rbuf + */ + rb_io_buffer_t cbuf; + + /** Encoding converter used when writing to this IO. */ + rb_econv_t *writeconv; + + /** + * This is, when set, an instance of ::rb_cString which holds the "common" + * encoding. Write conversion can convert strings twice... In case + * conversion from encoding X to encoding Y does not exist, Ruby finds an + * encoding Z that bridges the two, so that X to Z to Y conversion happens. + */ + VALUE writeconv_asciicompat; + + /** Whether ::rb_io_t::writeconv is already set up. */ + int writeconv_initialized; + + /** + * Value of ::rb_io_t::rb_io_enc_t::ecflags stored right before + * initialising ::rb_io_t::writeconv. + */ + int writeconv_pre_ecflags; + + /** + * Value of ::rb_io_t::rb_io_enc_t::ecopts stored right before initialising + * ::rb_io_t::writeconv. + */ + VALUE writeconv_pre_ecopts; + + /** + * This is a Ruby level mutex. It avoids multiple threads to write to an + * IO at once; helps for instance rb_io_puts() to ensure newlines right + * next to its arguments. + * + * This of course doesn't help inter-process IO interleaves, though. + */ + VALUE write_lock; + + /** + * The timeout associated with this IO when performing blocking operations. + */ + VALUE timeout; + + /** + * Threads that are performing a blocking operation without the GVL using + * this IO. On calling IO#close, these threads will be interrupted so that + * the operation can be cancelled. + */ + struct ccan_list_head blocking_operations; + struct rb_execution_context_struct *closing_ec; + VALUE wakeup_mutex; + + // The fork generation of the blocking operations list. + rb_serial_t fork_generation; +}; + +/* io.c */ +void ruby_set_inplace_mode(const char *); +void rb_stdio_set_default_encoding(void); +VALUE rb_io_flush_raw(VALUE, int); +size_t rb_io_memsize(const rb_io_t *); +int rb_stderr_tty_p(void); +VALUE rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt); + +VALUE rb_io_prep_stdin(void); +VALUE rb_io_prep_stdout(void); +VALUE rb_io_prep_stderr(void); + +int rb_io_notify_close(struct rb_io *fptr); + +RUBY_SYMBOL_EXPORT_BEGIN +/* io.c (export) */ +void rb_maygvl_fd_fix_cloexec(int fd); +int rb_gc_for_fd(int err); +void rb_write_error_str(VALUE mesg); + +VALUE rb_io_blocking_region_wait(struct rb_io *io, rb_blocking_function_t *function, void *argument, enum rb_io_event events); +VALUE rb_io_blocking_region(struct rb_io *io, rb_blocking_function_t *function, void *argument); +RUBY_SYMBOL_EXPORT_END + +#endif /* INTERNAL_IO_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/load.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/load.h new file mode 100644 index 0000000..fb880a4 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/load.h @@ -0,0 +1,20 @@ +#ifndef INTERNAL_LOAD_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_LOAD_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for require. + */ +#include "ruby/ruby.h" /* for VALUE */ + +/* load.c */ +VALUE rb_get_expanded_load_path(void); +VALUE rb_load_entrypoint(VALUE args); +VALUE rb_require_relative_entrypoint(VALUE fname); +int rb_require_internal(VALUE fname); +NORETURN(void rb_load_fail(VALUE, const char*)); + +#endif /* INTERNAL_LOAD_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/loadpath.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/loadpath.h new file mode 100644 index 0000000..b3a85e7 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/loadpath.h @@ -0,0 +1,16 @@ +#ifndef INTERNAL_LOADPATH_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_LOADPATH_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for $LOAD_PATH. + */ + +/* loadpath.c */ +extern const char ruby_exec_prefix[]; +extern const char ruby_initial_load_paths[]; + +#endif /* INTERNAL_LOADPATH_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/math.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/math.h new file mode 100644 index 0000000..08f852f --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/math.h @@ -0,0 +1,23 @@ +#ifndef INTERNAL_MATH_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_MATH_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Math. + */ +#include "ruby/ruby.h" /* for VALUE */ + +/* math.c */ +VALUE rb_math_atan2(VALUE, VALUE); +VALUE rb_math_cos(VALUE); +VALUE rb_math_cosh(VALUE); +VALUE rb_math_exp(VALUE); +VALUE rb_math_hypot(VALUE, VALUE); +VALUE rb_math_log(int argc, const VALUE *argv); +VALUE rb_math_sin(VALUE); +VALUE rb_math_sinh(VALUE); + +#endif /* INTERNAL_MATH_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/missing.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/missing.h new file mode 100644 index 0000000..6ca508c --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/missing.h @@ -0,0 +1,19 @@ +#ifndef INTERNAL_MISSING_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_MISSING_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header corresponding missing. + */ +#include "ruby/internal/config.h" /* for HAVE_SETPROCTITLE */ + +/* missing/setproctitle.c */ +#ifndef HAVE_SETPROCTITLE +extern void ruby_init_setproctitle(int argc, char *argv[]); +extern void ruby_free_proctitle(void); +#endif + +#endif /* INTERNAL_MISSING_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/numeric.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/numeric.h new file mode 100644 index 0000000..58f42f4 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/numeric.h @@ -0,0 +1,275 @@ +#ifndef INTERNAL_NUMERIC_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_NUMERIC_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Numeric. + */ +#include "internal/bignum.h" /* for BIGNUM_POSITIVE_P */ +#include "internal/bits.h" /* for RUBY_BIT_ROTL */ +#include "internal/fixnum.h" /* for FIXNUM_POSITIVE_P */ +#include "internal/vm.h" /* for rb_method_basic_definition_p */ +#include "ruby/intern.h" /* for rb_cmperr */ +#include "ruby/ruby.h" /* for USE_FLONUM */ + +#define ROUND_TO(mode, even, up, down) \ + ((mode) == RUBY_NUM_ROUND_HALF_EVEN ? even : \ + (mode) == RUBY_NUM_ROUND_HALF_UP ? up : down) +#define ROUND_FUNC(mode, name) \ + ROUND_TO(mode, name##_half_even, name##_half_up, name##_half_down) +#define ROUND_CALL(mode, name, args) \ + ROUND_TO(mode, name##_half_even args, \ + name##_half_up args, name##_half_down args) + +#ifndef ROUND_DEFAULT +# define ROUND_DEFAULT RUBY_NUM_ROUND_HALF_UP +#endif + +enum ruby_num_rounding_mode { + RUBY_NUM_ROUND_HALF_UP, + RUBY_NUM_ROUND_HALF_EVEN, + RUBY_NUM_ROUND_HALF_DOWN, + RUBY_NUM_ROUND_DEFAULT = ROUND_DEFAULT, +}; + +/* same as internal.h */ +#define numberof(array) ((int)(sizeof(array) / sizeof((array)[0]))) +#define roomof(x, y) (((x) + (y) - 1) / (y)) +#define type_roomof(x, y) roomof(sizeof(x), sizeof(y)) + +#if SIZEOF_DOUBLE <= SIZEOF_VALUE +typedef double rb_float_value_type; +#else +typedef struct { + VALUE values[roomof(SIZEOF_DOUBLE, SIZEOF_VALUE)]; +} rb_float_value_type; +#endif + +struct RFloat { + struct RBasic basic; + rb_float_value_type float_value; +}; + +#define RFLOAT(obj) ((struct RFloat *)(obj)) + +/* numeric.c */ +int rb_num_to_uint(VALUE val, unsigned int *ret); +VALUE ruby_num_interval_step_size(VALUE from, VALUE to, VALUE step, int excl); +double ruby_float_step_size(double beg, double end, double unit, int excl); +int ruby_float_step(VALUE from, VALUE to, VALUE step, int excl, int allow_endless); +int rb_num_negative_p(VALUE); +VALUE rb_int_succ(VALUE num); +VALUE rb_float_uminus(VALUE num); +VALUE rb_int_plus(VALUE x, VALUE y); +VALUE rb_float_plus(VALUE x, VALUE y); +VALUE rb_int_minus(VALUE x, VALUE y); +VALUE rb_float_minus(VALUE x, VALUE y); +VALUE rb_int_mul(VALUE x, VALUE y); +VALUE rb_float_mul(VALUE x, VALUE y); +VALUE rb_float_div(VALUE x, VALUE y); +VALUE rb_int_idiv(VALUE x, VALUE y); +VALUE rb_int_modulo(VALUE x, VALUE y); +VALUE rb_int2str(VALUE num, int base); +VALUE rb_fix_plus(VALUE x, VALUE y); +VALUE rb_int_gt(VALUE x, VALUE y); +VALUE rb_float_gt(VALUE x, VALUE y); +VALUE rb_int_ge(VALUE x, VALUE y); +enum ruby_num_rounding_mode rb_num_get_rounding_option(VALUE opts); +double rb_int_fdiv_double(VALUE x, VALUE y); +VALUE rb_int_pow(VALUE x, VALUE y); +VALUE rb_float_pow(VALUE x, VALUE y); +VALUE rb_int_cmp(VALUE x, VALUE y); +VALUE rb_int_equal(VALUE x, VALUE y); +VALUE rb_int_divmod(VALUE x, VALUE y); +VALUE rb_int_and(VALUE x, VALUE y); +VALUE rb_int_xor(VALUE x, VALUE y); +VALUE rb_int_lshift(VALUE x, VALUE y); +VALUE rb_int_rshift(VALUE x, VALUE y); +VALUE rb_int_div(VALUE x, VALUE y); +int rb_int_positive_p(VALUE num); +int rb_int_negative_p(VALUE num); +VALUE rb_check_integer_type(VALUE); +VALUE rb_num_pow(VALUE x, VALUE y); +VALUE rb_float_ceil(VALUE num, int ndigits); +VALUE rb_float_floor(VALUE x, int ndigits); +VALUE rb_float_abs(VALUE flt); +static inline VALUE rb_num_compare_with_zero(VALUE num, ID mid); +static inline int rb_num_positive_int_p(VALUE num); +static inline int rb_num_negative_int_p(VALUE num); +static inline double rb_float_flonum_value(VALUE v); +static inline double rb_float_noflonum_value(VALUE v); +static inline double rb_float_value_inline(VALUE v); +static inline VALUE rb_float_new_inline(double d); +static inline bool INT_POSITIVE_P(VALUE num); +static inline bool INT_NEGATIVE_P(VALUE num); +static inline bool FLOAT_ZERO_P(VALUE num); +#define rb_float_value rb_float_value_inline +#define rb_float_new rb_float_new_inline + +RUBY_SYMBOL_EXPORT_BEGIN +/* numeric.c (export) */ +RUBY_SYMBOL_EXPORT_END + +VALUE rb_flo_div_flo(VALUE x, VALUE y); +double ruby_float_mod(double x, double y); +VALUE rb_float_equal(VALUE x, VALUE y); +int rb_float_cmp(VALUE x, VALUE y); +VALUE rb_float_eql(VALUE x, VALUE y); +VALUE rb_fix_aref(VALUE fix, VALUE idx); +VALUE rb_int_zero_p(VALUE num); +VALUE rb_int_even_p(VALUE num); +VALUE rb_int_odd_p(VALUE num); +VALUE rb_int_abs(VALUE num); +VALUE rb_int_bit_length(VALUE num); +VALUE rb_int_uminus(VALUE num); +VALUE rb_int_comp(VALUE num); + +static inline bool +INT_POSITIVE_P(VALUE num) +{ + if (FIXNUM_P(num)) { + return FIXNUM_POSITIVE_P(num); + } + else { + return BIGNUM_POSITIVE_P(num); + } +} + +static inline bool +INT_NEGATIVE_P(VALUE num) +{ + if (FIXNUM_P(num)) { + return FIXNUM_NEGATIVE_P(num); + } + else { + return BIGNUM_NEGATIVE_P(num); + } +} + +static inline bool +FLOAT_ZERO_P(VALUE num) +{ + return RFLOAT_VALUE(num) == 0.0; +} + +static inline VALUE +rb_num_compare_with_zero(VALUE num, ID mid) +{ + VALUE zero = INT2FIX(0); + VALUE r = rb_check_funcall(num, mid, 1, &zero); + if (RB_UNDEF_P(r)) { + rb_cmperr(num, zero); + } + return r; +} + +static inline int +rb_num_positive_int_p(VALUE num) +{ + const ID mid = '>'; + + if (FIXNUM_P(num)) { + if (rb_method_basic_definition_p(rb_cInteger, mid)) + return FIXNUM_POSITIVE_P(num); + } + else if (RB_TYPE_P(num, T_BIGNUM)) { + if (rb_method_basic_definition_p(rb_cInteger, mid)) + return BIGNUM_POSITIVE_P(num); + } + return RTEST(rb_num_compare_with_zero(num, mid)); +} + +static inline int +rb_num_negative_int_p(VALUE num) +{ + const ID mid = '<'; + + if (FIXNUM_P(num)) { + if (rb_method_basic_definition_p(rb_cInteger, mid)) + return FIXNUM_NEGATIVE_P(num); + } + else if (RB_TYPE_P(num, T_BIGNUM)) { + if (rb_method_basic_definition_p(rb_cInteger, mid)) + return BIGNUM_NEGATIVE_P(num); + } + return RTEST(rb_num_compare_with_zero(num, mid)); +} + +static inline double +rb_float_flonum_value(VALUE v) +{ +#if USE_FLONUM + if (v != (VALUE)0x8000000000000002) { /* LIKELY */ + union { + double d; + VALUE v; + } t; + + VALUE b63 = (v >> 63); + /* e: xx1... -> 011... */ + /* xx0... -> 100... */ + /* ^b63 */ + t.v = RUBY_BIT_ROTR((2 - b63) | (v & ~(VALUE)0x03), 3); + return t.d; + } +#endif + return 0.0; +} + +static inline double +rb_float_noflonum_value(VALUE v) +{ +#if SIZEOF_DOUBLE <= SIZEOF_VALUE + return RFLOAT(v)->float_value; +#else + union { + rb_float_value_type v; + double d; + } u = {RFLOAT(v)->float_value}; + return u.d; +#endif +} + +static inline double +rb_float_value_inline(VALUE v) +{ + if (FLONUM_P(v)) { + return rb_float_flonum_value(v); + } + return rb_float_noflonum_value(v); +} + +static inline VALUE +rb_float_new_inline(double d) +{ +#if USE_FLONUM + union { + double d; + VALUE v; + } t; + int bits; + + t.d = d; + bits = (int)((VALUE)(t.v >> 60) & 0x7); + /* bits contains 3 bits of b62..b60. */ + /* bits - 3 = */ + /* b011 -> b000 */ + /* b100 -> b001 */ + + if (t.v != 0x3000000000000000 /* 1.72723e-77 */ && + !((bits-3) & ~0x01)) { + return (RUBY_BIT_ROTL(t.v, 3) & ~(VALUE)0x01) | 0x02; + } + else if (t.v == (VALUE)0) { + /* +0.0 */ + return 0x8000000000000002; + } + /* out of range */ +#endif + return rb_float_new_in_heap(d); +} + +#endif /* INTERNAL_NUMERIC_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/object.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/object.h new file mode 100644 index 0000000..3bde53c --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/object.h @@ -0,0 +1,63 @@ +#ifndef INTERNAL_OBJECT_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_OBJECT_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Object. + */ +#include "ruby/ruby.h" /* for VALUE */ + +/* object.c */ +size_t rb_obj_embedded_size(uint32_t fields_count); +VALUE rb_class_allocate_instance(VALUE klass); +VALUE rb_class_search_ancestor(VALUE klass, VALUE super); +NORETURN(void rb_undefined_alloc(VALUE klass)); +double rb_num_to_dbl(VALUE val); +VALUE rb_obj_dig(int argc, VALUE *argv, VALUE self, VALUE notfound); +VALUE rb_obj_clone_setup(VALUE obj, VALUE clone, VALUE kwfreeze); +VALUE rb_obj_dup_setup(VALUE obj, VALUE dup); +VALUE rb_immutable_obj_clone(int, VALUE *, VALUE); +VALUE rb_check_convert_type_with_id(VALUE,int,const char*,ID); +int rb_bool_expected(VALUE, const char *, int raise); +static inline void RBASIC_CLEAR_CLASS(VALUE obj); +static inline void RBASIC_SET_CLASS_RAW(VALUE obj, VALUE klass); +static inline void RBASIC_SET_CLASS(VALUE obj, VALUE klass); + +RUBY_SYMBOL_EXPORT_BEGIN +/* object.c (export) */ +int rb_opts_exception_p(VALUE opts, int default_value); +RUBY_SYMBOL_EXPORT_END + +CONSTFUNC(VALUE rb_obj_equal(VALUE obj1, VALUE obj2)); +CONSTFUNC(VALUE rb_obj_not(VALUE obj)); +VALUE rb_obj_not_equal(VALUE obj1, VALUE obj2); +void rb_obj_copy_ivar(VALUE dest, VALUE obj); +VALUE rb_false(VALUE obj); +VALUE rb_convert_type_with_id(VALUE v, int t, const char* nam, ID mid); +VALUE rb_obj_size(VALUE self, VALUE args, VALUE obj); +VALUE rb_get_freeze_opt(int argc, VALUE *argv); + +static inline void +RBASIC_SET_CLASS_RAW(VALUE obj, VALUE klass) +{ + const VALUE *ptr = &RBASIC(obj)->klass; + *(VALUE *)ptr = klass; +} + +static inline void +RBASIC_CLEAR_CLASS(VALUE obj) +{ + RBASIC_SET_CLASS_RAW(obj, 0); +} + +static inline void +RBASIC_SET_CLASS(VALUE obj, VALUE klass) +{ + VALUE oldv = RBASIC_CLASS(obj); + RBASIC_SET_CLASS_RAW(obj, klass); + RB_OBJ_WRITTEN(obj, oldv, klass); +} +#endif /* INTERNAL_OBJECT_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/parse.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/parse.h new file mode 100644 index 0000000..8e04664 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/parse.h @@ -0,0 +1,131 @@ +#ifndef INTERNAL_PARSE_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_PARSE_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for the parser. + */ +#include +#include "rubyparser.h" +#include "internal/static_assert.h" + +// The default parser to use for Ruby code. +typedef enum { + RB_DEFAULT_PARSER_PARSE_Y, + RB_DEFAULT_PARSER_PRISM, +} ruby_default_parser_enum; + +ruby_default_parser_enum rb_ruby_default_parser(void); +void rb_ruby_default_parser_set(ruby_default_parser_enum parser); + +#define rb_ruby_prism_p() (rb_ruby_default_parser() == RB_DEFAULT_PARSER_PRISM) + +#ifdef UNIVERSAL_PARSER +#define rb_encoding const void +#endif + +struct rb_iseq_struct; /* in vm_core.h */ + +/* structs for managing terminator of string literal and heredocment */ +typedef struct rb_strterm_literal_struct { + long nest; + int func; /* STR_FUNC_* (e.g., STR_FUNC_ESCAPE and STR_FUNC_EXPAND) */ + int paren; /* '(' of `%q(...)` */ + int term; /* ')' of `%q(...)` */ +} rb_strterm_literal_t; + +typedef struct rb_strterm_heredoc_struct { + rb_parser_string_t *lastline; /* the string of line that contains `<<"END"` */ + long offset; /* the column of END in `<<"END"` */ + int sourceline; /* lineno of the line that contains `<<"END"` */ + unsigned length; /* the length of END in `<<"END"` */ + uint8_t quote; + uint8_t func; +} rb_strterm_heredoc_t; + +#define HERETERM_LENGTH_MAX UINT_MAX + +typedef struct rb_strterm_struct { + bool heredoc; + union { + rb_strterm_literal_t literal; + rb_strterm_heredoc_t heredoc; + } u; +} rb_strterm_t; + +/* parse.y */ +void rb_ruby_parser_mark(void *ptr); +size_t rb_ruby_parser_memsize(const void *ptr); + +void rb_ruby_parser_set_options(rb_parser_t *p, int print, int loop, int chomp, int split); +rb_parser_t *rb_ruby_parser_set_context(rb_parser_t *p, const struct rb_iseq_struct *base, int main); +void rb_ruby_parser_set_script_lines(rb_parser_t *p); +void rb_ruby_parser_error_tolerant(rb_parser_t *p); +void rb_ruby_parser_keep_tokens(rb_parser_t *p); +typedef rb_parser_string_t*(rb_parser_lex_gets_func)(struct parser_params*, rb_parser_input_data, int); +rb_ast_t *rb_parser_compile(rb_parser_t *p, rb_parser_lex_gets_func *gets, VALUE fname, rb_parser_input_data input, int line); + +RUBY_SYMBOL_EXPORT_BEGIN + +rb_encoding *rb_ruby_parser_encoding(rb_parser_t *p); +int rb_ruby_parser_end_seen_p(rb_parser_t *p); +int rb_ruby_parser_set_yydebug(rb_parser_t *p, int flag); +rb_parser_string_t *rb_str_to_parser_string(rb_parser_t *p, VALUE str); +void rb_parser_string_free(rb_parser_t *p, rb_parser_string_t *str); + +int rb_parser_dvar_defined_ref(struct parser_params*, ID, ID**); +ID rb_parser_internal_id(struct parser_params*); +typedef void (*rb_parser_reg_fragment_error_func)(struct parser_params *, VALUE); +int rb_parser_reg_fragment_check(struct parser_params*, rb_parser_string_t*, int, rb_parser_reg_fragment_error_func); +int rb_reg_named_capture_assign_iter_impl(struct parser_params *p, const char *s, long len, rb_encoding *enc, NODE **succ_block, const rb_code_location_t *loc, rb_parser_assignable_func assignable); +int rb_parser_local_defined(struct parser_params *p, ID id, const struct rb_iseq_struct *iseq); +NODE *rb_parser_assignable(struct parser_params *p, ID id, NODE *val, const YYLTYPE *loc); + +RUBY_SYMBOL_EXPORT_END + +#ifndef UNIVERSAL_PARSER +rb_parser_t *rb_ruby_parser_allocate(void); +rb_parser_t *rb_ruby_parser_new(void); +#endif + +#ifdef RIPPER +void ripper_parser_mark(void *ptr); +void ripper_parser_free(void *ptr); +size_t ripper_parser_memsize(const void *ptr); +void ripper_error(struct parser_params *p); +VALUE ripper_value(struct parser_params *p); +int rb_ruby_parser_get_yydebug(rb_parser_t *p); +void rb_ruby_parser_set_value(rb_parser_t *p, VALUE value); +int rb_ruby_parser_error_p(rb_parser_t *p); +VALUE rb_ruby_parser_debug_output(rb_parser_t *p); +void rb_ruby_parser_set_debug_output(rb_parser_t *p, VALUE output); +VALUE rb_ruby_parser_parsing_thread(rb_parser_t *p); +void rb_ruby_parser_set_parsing_thread(rb_parser_t *p, VALUE parsing_thread); +void rb_ruby_parser_ripper_initialize(rb_parser_t *p, rb_parser_lex_gets_func *gets, rb_parser_input_data input, VALUE sourcefile_string, const char *sourcefile, int sourceline); +VALUE rb_ruby_parser_result(rb_parser_t *p); +rb_encoding *rb_ruby_parser_enc(rb_parser_t *p); +VALUE rb_ruby_parser_ruby_sourcefile_string(rb_parser_t *p); +int rb_ruby_parser_ruby_sourceline(rb_parser_t *p); +int rb_ruby_parser_lex_state(rb_parser_t *p); +void rb_ruby_ripper_parse0(rb_parser_t *p); +int rb_ruby_ripper_dedent_string(rb_parser_t *p, rb_parser_string_t *string, int width); +int rb_ruby_ripper_initialized_p(rb_parser_t *p); +void rb_ruby_ripper_parser_initialize(rb_parser_t *p); +long rb_ruby_ripper_column(rb_parser_t *p); +long rb_ruby_ripper_token_len(rb_parser_t *p); +rb_parser_string_t *rb_ruby_ripper_lex_lastline(rb_parser_t *p); +VALUE rb_ruby_ripper_lex_state_name(struct parser_params *p, int state); +#ifdef UNIVERSAL_PARSER +rb_parser_t *rb_ripper_parser_params_allocate(const rb_parser_config_t *config); +#endif +struct parser_params *rb_ruby_ripper_parser_allocate(void); +#endif + +#ifdef UNIVERSAL_PARSER +#undef rb_encoding +#endif + +#endif /* INTERNAL_PARSE_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/proc.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/proc.h new file mode 100644 index 0000000..24a077c --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/proc.h @@ -0,0 +1,30 @@ +#ifndef INTERNAL_PROC_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_PROC_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Proc. + */ +#include "ruby/ruby.h" /* for rb_block_call_func_t */ +#include "ruby/st.h" /* for st_index_t */ +struct rb_block; /* in vm_core.h */ +struct rb_iseq_struct; /* in vm_core.h */ + +/* proc.c */ +VALUE rb_proc_location(VALUE self); +st_index_t rb_hash_proc(st_index_t hash, VALUE proc); +int rb_block_pair_yield_optimizable(void); +int rb_block_arity(void); +int rb_block_min_max_arity(int *max); +VALUE rb_block_to_s(VALUE self, const struct rb_block *block, const char *additional_info); +VALUE rb_callable_receiver(VALUE); + +VALUE rb_func_proc_dup(VALUE src_obj); +VALUE rb_func_lambda_new(rb_block_call_func_t func, VALUE val, int min_argc, int max_argc); +VALUE rb_iseq_location(const struct rb_iseq_struct *iseq); +VALUE rb_sym_to_proc(VALUE sym); + +#endif /* INTERNAL_PROC_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/process.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/process.h new file mode 100644 index 0000000..fd4994c --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/process.h @@ -0,0 +1,124 @@ +#ifndef INTERNAL_PROCESS_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_PROCESS_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Process. + */ +#include "ruby/internal/config.h" /* for rb_pid_t */ +#include /* for size_t */ + +#ifdef HAVE_SYS_TYPES_H +# include /* for mode_t */ +#endif + +#ifdef _WIN32 +# include "ruby/win32.h" /* for mode_t */ +#endif + +#include "ruby/ruby.h" /* for VALUE */ +#include "internal/compilers.h" /* for __has_warning */ +#include "internal/imemo.h" /* for RB_IMEMO_TMPBUF_PTR */ + +#define RB_MAX_GROUPS (65536) + +struct waitpid_state; +struct rb_process_status; +struct rb_execarg { + union { + struct { + VALUE shell_script; + } sh; + struct { + VALUE command_name; + VALUE command_abspath; /* full path string or nil */ + VALUE argv_str; + VALUE argv_buf; + } cmd; + } invoke; + VALUE redirect_fds; + VALUE envp_str; + VALUE envp_buf; + VALUE dup2_tmpbuf; + unsigned use_shell : 1; + unsigned pgroup_given : 1; + unsigned umask_given : 1; + unsigned unsetenv_others_given : 1; + unsigned unsetenv_others_do : 1; + unsigned close_others_given : 1; + unsigned close_others_do : 1; + unsigned chdir_given : 1; + unsigned new_pgroup_given : 1; + unsigned new_pgroup_flag : 1; + unsigned uid_given : 1; + unsigned gid_given : 1; + unsigned exception : 1; + unsigned exception_given : 1; + struct rb_process_status *status; + struct waitpid_state *waitpid_state; /* for async process management */ + rb_pid_t pgroup_pgid; /* asis(-1), new pgroup(0), specified pgroup (0 + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Random. + */ +#include /* for size_t */ + +/* random.c */ +int ruby_fill_random_bytes(void *, size_t, int); +void rb_free_default_rand_key(void); + +#endif /* INTERNAL_RANDOM_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/range.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/range.h new file mode 100644 index 0000000..2394937 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/range.h @@ -0,0 +1,40 @@ +#ifndef INTERNAL_RANGE_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_RANGE_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Range. + */ +#include "internal/struct.h" /* for RSTRUCT */ + +/* range.c */ +static inline VALUE RANGE_BEG(VALUE r); +static inline VALUE RANGE_END(VALUE r); +static inline VALUE RANGE_EXCL(VALUE r); + +static inline VALUE +RANGE_BEG(VALUE r) +{ + return RSTRUCT(r)->as.ary[0]; +} + +static inline VALUE +RANGE_END(VALUE r) +{ + return RSTRUCT_GET(r, 1); +} + +static inline VALUE +RANGE_EXCL(VALUE r) +{ + return RSTRUCT_GET(r, 2); +} + +VALUE +rb_range_component_beg_len(VALUE b, VALUE e, int excl, + long *begp, long *lenp, long len, int err); + +#endif /* INTERNAL_RANGE_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/rational.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/rational.h new file mode 100644 index 0000000..f11fab4 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/rational.h @@ -0,0 +1,71 @@ +#ifndef INTERNAL_RATIONAL_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_RATIONAL_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Rational. + */ +#include "ruby/internal/config.h" /* for HAVE_LIBGMP */ +#include "ruby/ruby.h" /* for struct RBasic */ +#include "internal/numeric.h" /* for INT_POSITIVE_P */ +#include "ruby_assert.h" /* for assert */ + +struct RRational { + struct RBasic basic; + VALUE num; + VALUE den; +}; + +#define RRATIONAL(obj) ((struct RRational *)(obj)) + +/* rational.c */ +VALUE rb_rational_canonicalize(VALUE x); +VALUE rb_rational_uminus(VALUE self); +VALUE rb_rational_plus(VALUE self, VALUE other); +VALUE rb_rational_minus(VALUE self, VALUE other); +VALUE rb_rational_mul(VALUE self, VALUE other); +VALUE rb_rational_div(VALUE self, VALUE other); +VALUE rb_lcm(VALUE x, VALUE y); +VALUE rb_rational_reciprocal(VALUE x); +VALUE rb_cstr_to_rat(const char *, int); +VALUE rb_rational_hash(VALUE self); +VALUE rb_rational_abs(VALUE self); +VALUE rb_rational_cmp(VALUE self, VALUE other); +VALUE rb_rational_pow(VALUE self, VALUE other); +VALUE rb_rational_floor(VALUE self, int ndigits); +VALUE rb_numeric_quo(VALUE x, VALUE y); +VALUE rb_flo_round_by_rational(int argc, VALUE *argv, VALUE num); +VALUE rb_float_numerator(VALUE x); +VALUE rb_float_denominator(VALUE x); + +static inline void RATIONAL_SET_NUM(VALUE r, VALUE n); +static inline void RATIONAL_SET_DEN(VALUE r, VALUE d); + +RUBY_SYMBOL_EXPORT_BEGIN +/* rational.c (export) */ +VALUE rb_gcd(VALUE x, VALUE y); +VALUE rb_gcd_normal(VALUE self, VALUE other); +#if defined(HAVE_LIBGMP) && defined(HAVE_GMP_H) +VALUE rb_gcd_gmp(VALUE x, VALUE y); +#endif +RUBY_SYMBOL_EXPORT_END + +static inline void +RATIONAL_SET_NUM(VALUE r, VALUE n) +{ + assert(RB_INTEGER_TYPE_P(n)); + RB_OBJ_WRITE(r, &RRATIONAL(r)->num, n); +} + +static inline void +RATIONAL_SET_DEN(VALUE r, VALUE d) +{ + assert(RB_INTEGER_TYPE_P(d)); + assert(INT_POSITIVE_P(d)); + RB_OBJ_WRITE(r, &RRATIONAL(r)->den, d); +} + +#endif /* INTERNAL_RATIONAL_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/re.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/re.h new file mode 100644 index 0000000..593e5c4 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/re.h @@ -0,0 +1,33 @@ +#ifndef INTERNAL_RE_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_RE_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Regexp. + */ +#include "ruby/internal/stdbool.h" /* for bool */ +#include "ruby/ruby.h" /* for VALUE */ + +/* re.c */ +VALUE rb_reg_compile(VALUE str, int options, const char *sourcefile, int sourceline); +VALUE rb_reg_check_preprocess(VALUE); +long rb_reg_search0(VALUE, VALUE, long, int, int, VALUE *); +VALUE rb_reg_match_p(VALUE re, VALUE str, long pos); +bool rb_reg_start_with_p(VALUE re, VALUE str); +VALUE rb_reg_hash(VALUE re); +VALUE rb_reg_equal(VALUE re1, VALUE re2); +VALUE rb_backref_set_string(VALUE string, long pos, long len); +void rb_match_unbusy(VALUE); +int rb_match_count(VALUE match); +VALUE rb_reg_new_ary(VALUE ary, int options); +VALUE rb_reg_last_defined(VALUE match); + +#define ARG_REG_OPTION_MASK \ + (ONIG_OPTION_IGNORECASE|ONIG_OPTION_MULTILINE|ONIG_OPTION_EXTEND) +#define ARG_ENCODING_FIXED 16 +#define ARG_ENCODING_NONE 32 + +#endif /* INTERNAL_RE_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/ruby_parser.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/ruby_parser.h new file mode 100644 index 0000000..8e306d1 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/ruby_parser.h @@ -0,0 +1,102 @@ +#ifndef INTERNAL_RUBY_PARSE_H +#define INTERNAL_RUBY_PARSE_H + +#include "internal.h" +#include "internal/bignum.h" +#include "internal/compilers.h" +#include "internal/complex.h" +#include "internal/parse.h" +#include "internal/rational.h" +#include "rubyparser.h" +#include "vm.h" + +struct lex_pointer_string { + VALUE str; + long ptr; +}; + +RUBY_SYMBOL_EXPORT_BEGIN +#ifdef UNIVERSAL_PARSER +const rb_parser_config_t *rb_ruby_parser_config(void); +rb_parser_t *rb_parser_params_new(void); +#endif +VALUE rb_parser_set_context(VALUE, const struct rb_iseq_struct *, int); +VALUE rb_parser_new(void); +VALUE rb_parser_compile_string_path(VALUE vparser, VALUE fname, VALUE src, int line); +VALUE rb_str_new_parser_string(rb_parser_string_t *str); +VALUE rb_str_new_mutable_parser_string(rb_parser_string_t *str); +rb_parser_string_t *rb_parser_lex_get_str(struct parser_params *p, struct lex_pointer_string *ptr_str); + +VALUE rb_node_str_string_val(const NODE *); +VALUE rb_node_sym_string_val(const NODE *); +VALUE rb_node_dstr_string_val(const NODE *); +VALUE rb_node_regx_string_val(const NODE *); +VALUE rb_node_dregx_string_val(const NODE *); +VALUE rb_node_line_lineno_val(const NODE *); +VALUE rb_node_file_path_val(const NODE *); +VALUE rb_node_encoding_val(const NODE *); + +VALUE rb_node_integer_literal_val(const NODE *); +VALUE rb_node_float_literal_val(const NODE *); +VALUE rb_node_rational_literal_val(const NODE *); +VALUE rb_node_imaginary_literal_val(const NODE *); +RUBY_SYMBOL_EXPORT_END + +VALUE rb_parser_end_seen_p(VALUE); +VALUE rb_parser_encoding(VALUE); +VALUE rb_parser_set_yydebug(VALUE, VALUE); +VALUE rb_parser_build_script_lines_from(rb_parser_ary_t *script_lines); +void rb_parser_set_options(VALUE, int, int, int, int); +VALUE rb_parser_load_file(VALUE parser, VALUE name); +void rb_parser_set_script_lines(VALUE vparser); +void rb_parser_error_tolerant(VALUE vparser); +void rb_parser_keep_tokens(VALUE vparser); + +VALUE rb_parser_compile_string(VALUE, const char*, VALUE, int); +VALUE rb_parser_compile_file_path(VALUE vparser, VALUE fname, VALUE input, int line); +VALUE rb_parser_compile_generic(VALUE vparser, rb_parser_lex_gets_func *lex_gets, VALUE fname, VALUE input, int line); +VALUE rb_parser_compile_array(VALUE vparser, VALUE fname, VALUE array, int start); + +enum lex_state_bits { + EXPR_BEG_bit, /* ignore newline, +/- is a sign. */ + EXPR_END_bit, /* newline significant, +/- is an operator. */ + EXPR_ENDARG_bit, /* ditto, and unbound braces. */ + EXPR_ENDFN_bit, /* ditto, and unbound braces. */ + EXPR_ARG_bit, /* newline significant, +/- is an operator. */ + EXPR_CMDARG_bit, /* newline significant, +/- is an operator. */ + EXPR_MID_bit, /* newline significant, +/- is an operator. */ + EXPR_FNAME_bit, /* ignore newline, no reserved words. */ + EXPR_DOT_bit, /* right after `.', `&.' or `::', no reserved words. */ + EXPR_CLASS_bit, /* immediate after `class', no here document. */ + EXPR_LABEL_bit, /* flag bit, label is allowed. */ + EXPR_LABELED_bit, /* flag bit, just after a label. */ + EXPR_FITEM_bit, /* symbol literal as FNAME. */ + EXPR_MAX_STATE +}; +/* examine combinations */ +enum lex_state_e { +#define DEF_EXPR(n) EXPR_##n = (1 << EXPR_##n##_bit) + DEF_EXPR(BEG), + DEF_EXPR(END), + DEF_EXPR(ENDARG), + DEF_EXPR(ENDFN), + DEF_EXPR(ARG), + DEF_EXPR(CMDARG), + DEF_EXPR(MID), + DEF_EXPR(FNAME), + DEF_EXPR(DOT), + DEF_EXPR(CLASS), + DEF_EXPR(LABEL), + DEF_EXPR(LABELED), + DEF_EXPR(FITEM), + EXPR_VALUE = EXPR_BEG, + EXPR_BEG_ANY = (EXPR_BEG | EXPR_MID | EXPR_CLASS), + EXPR_ARG_ANY = (EXPR_ARG | EXPR_CMDARG), + EXPR_END_ANY = (EXPR_END | EXPR_ENDARG | EXPR_ENDFN), + EXPR_NONE = 0 +}; + +VALUE rb_ruby_ast_new(const NODE *const root); +rb_ast_t *rb_ruby_ast_data_get(VALUE ast_value); + +#endif /* INTERNAL_RUBY_PARSE_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/sanitizers.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/sanitizers.h new file mode 100644 index 0000000..feafb4e --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/sanitizers.h @@ -0,0 +1,346 @@ +#ifndef INTERNAL_SANITIZERS_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_SANITIZERS_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for ASAN / MSAN / etc. + */ +#include "ruby/internal/config.h" +#include "internal/compilers.h" /* for __has_feature */ + +#ifdef HAVE_VALGRIND_MEMCHECK_H +# include +#endif + +#ifdef HAVE_SANITIZER_ASAN_INTERFACE_H +# if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) +# define RUBY_ASAN_ENABLED +# include +# endif +#endif + +#ifdef HAVE_SANITIZER_MSAN_INTERFACE_H +# if __has_feature(memory_sanitizer) +# define RUBY_MSAN_ENABLED +# include +# endif +#endif + +#ifdef HAVE_SANITIZER_TSAN_INTERFACE_H +# if __has_feature(thread_sanitizer) || defined(__SANITIZE_THREAD__) +# define RUBY_TSAN_ENABLED +# include +# endif +#endif + +#include "ruby/internal/stdbool.h" /* for bool */ +#include "ruby/ruby.h" /* for VALUE */ + +#if 0 +#elif defined(RUBY_ASAN_ENABLED) && defined(RUBY_MSAN_ENABLED) +# define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(x) \ + __attribute__((__no_sanitize__("memory, address"), __noinline__)) x +#elif defined(RUBY_ASAN_ENABLED) +# define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(x) \ + __attribute__((__no_sanitize__("address"), __noinline__)) x +#elif defined(RUBY_MSAN_ENABLED) + # define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(x) \ + __attribute__((__no_sanitize__("memory"), __noinline__)) x +#elif defined(RUBY_TSAN_ENABLED) +# define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(x) \ + __attribute__((__no_sanitize__("thread"), __noinline__)) x +#elif defined(NO_SANITIZE_ADDRESS) +# define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(x) \ + NO_SANITIZE_ADDRESS(NOINLINE(x)) +#elif defined(NO_ADDRESS_SAFETY_ANALYSIS) +# define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(x) \ + NO_ADDRESS_SAFETY_ANALYSIS(NOINLINE(x)) +#else +# define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(x) x +#endif + +#if defined(NO_SANITIZE) && RBIMPL_COMPILER_IS(GCC) +/* GCC warns about unknown sanitizer, which is annoying. */ +# include "internal/warnings.h" +# undef NO_SANITIZE +# define NO_SANITIZE(x, y) \ + COMPILER_WARNING_PUSH \ + COMPILER_WARNING_IGNORED(-Wattributes) \ + __attribute__((__no_sanitize__(x))) y; \ + COMPILER_WARNING_POP \ + y +#endif + +#ifndef NO_SANITIZE +# define NO_SANITIZE(x, y) y +#endif + +#ifndef RUBY_ASAN_ENABLED +# define __asan_poison_memory_region(x, y) +# define __asan_unpoison_memory_region(x, y) +# define __asan_region_is_poisoned(x, y) 0 +# define __asan_get_current_fake_stack() NULL +# define __asan_addr_is_in_fake_stack(fake_stack, slot, start, end) NULL +#endif + +#ifndef RUBY_MSAN_ENABLED +# define __msan_allocated_memory(x, y) ((void)(x), (void)(y)) +# define __msan_poison(x, y) ((void)(x), (void)(y)) +# define __msan_unpoison(x, y) ((void)(x), (void)(y)) +# define __msan_unpoison_string(x) ((void)(x)) +#endif + +#ifdef VALGRIND_MAKE_READABLE +# define VALGRIND_MAKE_MEM_DEFINED(p, n) VALGRIND_MAKE_READABLE((p), (n)) +#endif + +#ifdef VALGRIND_MAKE_WRITABLE +# define VALGRIND_MAKE_MEM_UNDEFINED(p, n) VALGRIND_MAKE_WRITABLE((p), (n)) +#endif + +#ifndef VALGRIND_MAKE_MEM_DEFINED +# define VALGRIND_MAKE_MEM_DEFINED(p, n) 0 +#endif + +#ifndef VALGRIND_MAKE_MEM_UNDEFINED +# define VALGRIND_MAKE_MEM_UNDEFINED(p, n) 0 +#endif + +/** + * This function asserts that a (continuous) memory region from ptr to size + * being "poisoned". Both read / write access to such memory region are + * prohibited until properly unpoisoned. The region must be previously + * allocated (do not pass a freed pointer here), but not necessarily be an + * entire object that the malloc returns. You can punch hole a part of a + * gigantic heap arena. This is handy when you do not free an allocated memory + * region to reuse later: poison when you keep it unused, and unpoison when you + * reuse. + * + * @param[in] ptr pointer to the beginning of the memory region to poison. + * @param[in] size the length of the memory region to poison. + */ +static inline void +asan_poison_memory_region(const volatile void *ptr, size_t size) +{ + __msan_poison(ptr, size); + __asan_poison_memory_region(ptr, size); +} + +#ifdef RUBY_ASAN_ENABLED +#define asan_poison_object_if(ptr, obj) do { \ + if (ptr) rb_asan_poison_object(obj); \ + } while (0) +#else +#define asan_poison_object_if(ptr, obj) ((void)(ptr), (void)(obj)) +#endif + +#ifdef RUBY_ASAN_ENABLED +RUBY_SYMBOL_EXPORT_BEGIN +/** + * This is a variant of asan_poison_memory_region that takes a VALUE. + * + * @param[in] obj target object. + */ +void rb_asan_poison_object(VALUE obj); + +/** + * This function predicates if the given object is fully addressable or not. + * + * @param[in] obj target object. + * @retval 0 the given object is fully addressable. + * @retval otherwise pointer to first such byte who is poisoned. + */ +void *rb_asan_poisoned_object_p(VALUE obj); + +/** + * This is a variant of asan_unpoison_memory_region that takes a VALUE. + * + * @param[in] obj target object. + * @param[in] malloc_p if the memory region is like a malloc's return value or not. + */ +void rb_asan_unpoison_object(VALUE obj, bool newobj_p); + +RUBY_SYMBOL_EXPORT_END +#else +# define rb_asan_poison_object(obj) ((void)obj) +# define rb_asan_poisoned_object_p(obj) ((void)obj, NULL) +# define rb_asan_unpoison_object(obj, newobj_p) ((void)obj, (void)newobj_p) +#endif + +/** + * This function asserts that a (formally poisoned) memory region from ptr to + * size is now addressable. Write access to such memory region gets allowed. + * However read access might or might not be possible depending on situations, + * because the region can have contents of previous usages. That information + * should be passed by the malloc_p flag. If that is true, the contents of the + * region is _not_ fully defined (like the return value of malloc behaves). + * Reading from there is NG; write something first. If malloc_p is false on + * the other hand, that memory region is fully defined and can be read + * immediately. + * + * @param[in] ptr pointer to the beginning of the memory region to unpoison. + * @param[in] size the length of the memory region. + * @param[in] malloc_p if the memory region is like a malloc's return value or not. + */ +static inline void +asan_unpoison_memory_region(const volatile void *ptr, size_t size, bool malloc_p) +{ + __asan_unpoison_memory_region(ptr, size); + if (malloc_p) { + __msan_allocated_memory(ptr, size); + } + else { + __msan_unpoison(ptr, size); + } +} + +static inline void * +asan_unpoison_object_temporary(VALUE obj) +{ + void *ptr = rb_asan_poisoned_object_p(obj); + rb_asan_unpoison_object(obj, false); + return ptr; +} + +static inline void * +asan_poison_object_restore(VALUE obj, void *ptr) +{ + if (ptr) { + rb_asan_poison_object(obj); + } + return NULL; +} + +#define asan_unpoisoning_object(obj) \ + for (void *poisoned = asan_unpoison_object_temporary(obj), \ + *unpoisoning = &poisoned; /* flag to loop just once */ \ + unpoisoning; \ + unpoisoning = asan_poison_object_restore(obj, poisoned)) + + +static inline void * +asan_unpoison_memory_region_temporary(void *ptr, size_t len) +{ + void *poisoned_ptr = __asan_region_is_poisoned(ptr, len); + asan_unpoison_memory_region(ptr, len, false); + return poisoned_ptr; +} + +static inline void * +asan_poison_memory_region_restore(void *ptr, size_t len, void *poisoned_ptr) +{ + if (poisoned_ptr) { + asan_poison_memory_region(ptr, len); + } + return NULL; +} + +#define asan_unpoisoning_memory_region(ptr, len) \ + for (void *poisoned = asan_unpoison_memory_region_temporary(ptr, len), \ + *unpoisoning = &poisoned; /* flag to loop just once */ \ + unpoisoning; \ + unpoisoning = asan_poison_memory_region_restore(ptr, len, poisoned)) + +/** + * Checks if the given pointer is on an ASAN fake stack. If so, it returns the + * address this variable has on the real frame; if not, it returns the origin + * address unmodified. + * + * n.b. - _dereferencing_ the returned address is meaningless and should not + * be done; even though ASAN reserves space for the variable in both the real and + * fake stacks, the _value_ of that variable is only in the fake stack. + * + * n.b. - this only works for addresses passed in from local variables on the same + * thread, because the ASAN fake stacks are threadlocal. + * + * @param[in] slot the address of some local variable + * @retval a pointer to something from that frame on the _real_ machine stack + */ +static inline void * +asan_get_real_stack_addr(void* slot) +{ + VALUE *addr; + addr = __asan_addr_is_in_fake_stack(__asan_get_current_fake_stack(), slot, NULL, NULL); + return addr ? addr : slot; +} + +/** + * Gets the current thread's fake stack handle, which can be passed into get_fake_stack_extents + * + * @retval An opaque value which can be passed to asan_get_fake_stack_extents + */ +static inline void * +asan_get_thread_fake_stack_handle(void) +{ + return __asan_get_current_fake_stack(); +} + +/** + * Checks if the given VALUE _actually_ represents a pointer to an ASAN fake stack. + * + * If the given slot _is_ actually a reference to an ASAN fake stack, and that fake stack + * contains the real values for the passed-in range of machine stack addresses, returns true + * and the range of the fake stack through the outparams. + * + * Otherwise, returns false, and sets the outparams to NULL. + * + * Note that this function expects "start" to be > "end" on downward-growing stack architectures; + * + * @param[in] thread_fake_stack_handle The asan fake stack reference for the thread we're scanning + * @param[in] slot The value on the machine stack we want to inspect + * @param[in] machine_stack_start The extents of the real machine stack on which slot lives + * @param[in] machine_stack_end The extents of the real machine stack on which slot lives + * @param[out] fake_stack_start_out The extents of the fake stack which contains real VALUEs + * @param[out] fake_stack_end_out The extents of the fake stack which contains real VALUEs + * @return Whether slot is a pointer to a fake stack for the given machine stack range +*/ + +static inline bool +asan_get_fake_stack_extents(void *thread_fake_stack_handle, VALUE slot, + void *machine_stack_start, void *machine_stack_end, + void **fake_stack_start_out, void **fake_stack_end_out) +{ + /* the ifdef is needed here to suppress a warning about fake_frame_{start/end} being + uninitialized if __asan_addr_is_in_fake_stack is an empty macro */ +#ifdef RUBY_ASAN_ENABLED + void *fake_frame_start; + void *fake_frame_end; + void *real_stack_frame = __asan_addr_is_in_fake_stack( + thread_fake_stack_handle, (void *)slot, &fake_frame_start, &fake_frame_end + ); + if (real_stack_frame) { + bool in_range; +#if STACK_GROW_DIRECTION < 0 + in_range = machine_stack_start >= real_stack_frame && real_stack_frame >= machine_stack_end; +#else + in_range = machine_stack_start <= real_stack_frame && real_stack_frame <= machine_stack_end; +#endif + if (in_range) { + *fake_stack_start_out = fake_frame_start; + *fake_stack_end_out = fake_frame_end; + return true; + } + } +#endif + *fake_stack_start_out = 0; + *fake_stack_end_out = 0; + return false; +} + +extern const char ruby_asan_default_options[]; + +#ifdef RUBY_ASAN_ENABLED +/* Compile in the ASAN options Ruby needs, rather than relying on environment variables, so + * that even tests which fork ruby with a clean environment will run ASAN with the right + * settings */ +# undef RUBY__ASAN_DEFAULT_OPTIONS +# define RUBY__ASAN_DEFAULT_OPTIONS \ + RBIMPL_SYMBOL_EXPORT_BEGIN() \ + const char * __asan_default_options(void) {return ruby_asan_default_options;} \ + RBIMPL_SYMBOL_EXPORT_END() +#endif + +#endif /* INTERNAL_SANITIZERS_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/serial.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/serial.h new file mode 100644 index 0000000..df9e9a4 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/serial.h @@ -0,0 +1,23 @@ +#ifndef INTERNAL_SERIAL_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_SERIAL_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for rb_serial_t. + */ +#include "ruby/internal/config.h" /* for HAVE_LONG_LONG */ +#include "ruby/defines.h" /* for LONG_LONG */ + +#ifndef HAVE_LONG_LONG +# error need C99+ +#endif + +typedef unsigned LONG_LONG rb_serial_t; +#define SERIALT2NUM ULL2NUM +#define PRI_SERIALT_PREFIX PRI_LL_PREFIX +#define SIZEOF_SERIAL_T SIZEOF_LONG_LONG + +#endif /* INTERNAL_SERIAL_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/set_table.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/set_table.h new file mode 100644 index 0000000..3c29abb --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/set_table.h @@ -0,0 +1,70 @@ +#ifndef INTERNAL_SET_TABLE_H +#define INTERNAL_SET_TABLE_H + +#include "ruby/st.h" + +struct set_table_entry; + +typedef struct set_table_entry set_table_entry; + +struct set_table { + /* Cached features of the table -- see st.c for more details. */ + unsigned char entry_power, bin_power, size_ind; + /* How many times the table was rebuilt. */ + unsigned int rebuilds_num; + const struct st_hash_type *type; + /* Number of entries currently in the table. */ + st_index_t num_entries; + + /* Start and bound index of entries in array entries. + entries_starts and entries_bound are in interval + [0,allocated_entries]. */ + st_index_t entries_start, entries_bound; + + /** + * Array of size 2^entry_power. + * Followed by st_index_t *bins, Array of bins used for access by keys. + */ + set_table_entry *entries; +}; + +typedef struct set_table set_table; + +typedef int set_foreach_callback_func(st_data_t, st_data_t); +typedef int set_foreach_check_callback_func(st_data_t, st_data_t, int); +typedef int set_update_callback_func(st_data_t *key, st_data_t arg, int existing); + +#define set_table_size rb_set_table_size +size_t rb_set_table_size(const struct set_table *tbl); +#define set_init_table_with_size rb_set_init_table_with_size +set_table *rb_set_init_table_with_size(set_table *tab, const struct st_hash_type *, st_index_t); +#define set_init_numtable rb_set_init_numtable +set_table *rb_set_init_numtable(void); +#define set_init_numtable_with_size rb_set_init_numtable_with_size +set_table *rb_set_init_numtable_with_size(st_index_t size); +#define set_table_delete rb_set_table_delete +int rb_set_table_delete(set_table *, st_data_t *); /* returns 0:notfound 1:deleted */ +#define set_insert rb_set_insert +int rb_set_insert(set_table *, st_data_t); +#define set_table_lookup rb_set_table_lookup +int rb_set_table_lookup(set_table *, st_data_t); +#define set_foreach_with_replace rb_set_foreach_with_replace +int rb_set_foreach_with_replace(set_table *tab, set_foreach_check_callback_func *func, set_update_callback_func *replace, st_data_t arg); +#define set_table_foreach rb_set_table_foreach +int rb_set_table_foreach(set_table *, set_foreach_callback_func *, st_data_t); +#define set_foreach_check rb_set_foreach_check +int rb_set_foreach_check(set_table *, set_foreach_check_callback_func *, st_data_t, st_data_t); +#define set_keys rb_set_keys +st_index_t rb_set_keys(set_table *table, st_data_t *keys, st_index_t size); +#define set_free_table rb_set_free_table +void rb_set_free_table(set_table *); +#define set_table_clear rb_set_table_clear +void rb_set_table_clear(set_table *); +#define set_copy rb_set_copy +set_table *rb_set_copy(set_table *new_table, set_table *old_table); +#define set_memsize rb_set_memsize +PUREFUNC(size_t rb_set_memsize(const set_table *)); +#define set_compact_table rb_set_compact_table +void set_compact_table(set_table *tab); + +#endif diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/signal.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/signal.h new file mode 100644 index 0000000..904747e --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/signal.h @@ -0,0 +1,25 @@ +#ifndef INTERNAL_SIGNAL_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_SIGNAL_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for SignalException. + */ + +/* signal.c */ +extern int ruby_enable_coredump; +int rb_get_next_signal(void); + +#ifdef POSIX_SIGNAL +void (*ruby_posix_signal(int, void (*)(int)))(int); +#endif + +RUBY_SYMBOL_EXPORT_BEGIN +/* signal.c (export) */ +void rb_signal_atfork(void); +RUBY_SYMBOL_EXPORT_END + +#endif /* INTERNAL_SIGNAL_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/st.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/st.h new file mode 100644 index 0000000..c220edd --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/st.h @@ -0,0 +1,11 @@ +#ifndef INTERNAL_ST_H +#define INTERNAL_ST_H + +#include "ruby/st.h" + +st_table *rb_st_replace(st_table *new_tab, st_table *old_tab); +#define st_replace rb_st_replace +st_table *rb_st_init_existing_table_with_size(st_table *tab, const struct st_hash_type *type, st_index_t size); +#define st_init_existing_table_with_size rb_st_init_existing_table_with_size + +#endif diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/static_assert.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/static_assert.h new file mode 100644 index 0000000..70dd0b7 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/static_assert.h @@ -0,0 +1,16 @@ +#ifndef INTERNAL_STATIC_ASSERT_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_STATIC_ASSERT_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief C11 shim for _Static_assert. + */ +#include "ruby/internal/static_assert.h" +#ifndef STATIC_ASSERT +# define STATIC_ASSERT RBIMPL_STATIC_ASSERT +#endif + +#endif /* INTERNAL_STATIC_ASSERT_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/string.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/string.h new file mode 100644 index 0000000..d6fea62 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/string.h @@ -0,0 +1,203 @@ +#ifndef INTERNAL_STRING_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_STRING_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for String. + */ +#include "ruby/internal/config.h" +#include /* for size_t */ +#include "internal/compilers.h" /* for __has_builtin */ +#include "ruby/internal/stdbool.h" /* for bool */ +#include "ruby/encoding.h" /* for rb_encoding */ +#include "ruby/ruby.h" /* for VALUE */ + +#define STR_SHARED FL_USER0 /* = ELTS_SHARED */ +#define STR_NOEMBED FL_USER1 +#define STR_CHILLED (FL_USER2 | FL_USER3) +#define STR_CHILLED_LITERAL FL_USER2 +#define STR_CHILLED_SYMBOL_TO_S FL_USER3 + +enum ruby_rstring_private_flags { + RSTRING_CHILLED = STR_CHILLED, +}; + +#ifdef rb_fstring_cstr +# undef rb_fstring_cstr +#endif + +/* string.c */ +VALUE rb_str_dup_m(VALUE str); +VALUE rb_fstring(VALUE); +VALUE rb_fstring_cstr(const char *str); +VALUE rb_fstring_enc_new(const char *ptr, long len, rb_encoding *enc); +int rb_str_buf_cat_escaped_char(VALUE result, unsigned int c, int unicode_p); +int rb_str_symname_p(VALUE); +VALUE rb_str_quote_unprintable(VALUE); +char *rb_str_fill_terminator(VALUE str, const int termlen); +void rb_str_change_terminator_length(VALUE str, const int oldtermlen, const int termlen); +VALUE rb_str_locktmp_ensure(VALUE str, VALUE (*func)(VALUE), VALUE arg); +VALUE rb_str_chomp_string(VALUE str, VALUE chomp); +VALUE rb_external_str_with_enc(VALUE str, rb_encoding *eenc); +VALUE rb_str_cat_conv_enc_opts(VALUE newstr, long ofs, const char *ptr, long len, + rb_encoding *from, int ecflags, VALUE ecopts); +VALUE rb_enc_str_scrub(rb_encoding *enc, VALUE str, VALUE repl); +VALUE rb_str_escape(VALUE str); +size_t rb_str_memsize(VALUE); +char *rb_str_to_cstr(VALUE str); +const char *ruby_escaped_char(int c); +void rb_str_make_independent(VALUE str); +int rb_enc_str_coderange_scan(VALUE str, rb_encoding *enc); +int rb_ascii8bit_appendable_encoding_index(rb_encoding *enc, unsigned int code); +VALUE rb_str_include(VALUE str, VALUE arg); +VALUE rb_str_byte_substr(VALUE str, VALUE beg, VALUE len); +VALUE rb_str_substr_two_fixnums(VALUE str, VALUE beg, VALUE len, int empty); +VALUE rb_str_tmp_frozen_no_embed_acquire(VALUE str); +void rb_str_make_embedded(VALUE); +VALUE rb_str_upto_each(VALUE, VALUE, int, int (*each)(VALUE, VALUE), VALUE); +size_t rb_str_size_as_embedded(VALUE); +bool rb_str_reembeddable_p(VALUE); +VALUE rb_str_upto_endless_each(VALUE, int (*each)(VALUE, VALUE), VALUE); +VALUE rb_str_with_debug_created_info(VALUE, VALUE, int); +VALUE rb_str_frozen_bare_string(VALUE); + +/* error.c */ +void rb_warn_unchilled_literal(VALUE str); +void rb_warn_unchilled_symbol_to_s(VALUE str); + +static inline bool STR_EMBED_P(VALUE str); +static inline bool STR_SHARED_P(VALUE str); +static inline VALUE QUOTE(VALUE v); +static inline VALUE QUOTE_ID(ID v); +static inline bool is_ascii_string(VALUE str); +static inline bool is_broken_string(VALUE str); +static inline VALUE rb_str_eql_internal(const VALUE str1, const VALUE str2); + +RUBY_SYMBOL_EXPORT_BEGIN +/* string.c (export) */ +VALUE rb_str_tmp_frozen_acquire(VALUE str); +void rb_str_tmp_frozen_release(VALUE str, VALUE tmp); +VALUE rb_setup_fake_str(struct RString *fake_str, const char *name, long len, rb_encoding *enc); +RUBY_SYMBOL_EXPORT_END + +VALUE rb_fstring_new(const char *ptr, long len); +void rb_gc_free_fstring(VALUE obj); +bool rb_obj_is_fstring_table(VALUE obj); +void Init_fstring_table(); +VALUE rb_obj_as_string_result(VALUE str, VALUE obj); +VALUE rb_str_opt_plus(VALUE x, VALUE y); +VALUE rb_str_concat_literals(size_t num, const VALUE *strary); +VALUE rb_str_eql(VALUE str1, VALUE str2); +VALUE rb_id_quote_unprintable(ID); +VALUE rb_sym_proc_call(ID mid, int argc, const VALUE *argv, int kw_splat, VALUE passed_proc); +VALUE rb_enc_literal_str(const char *ptr, long len, rb_encoding *enc); + +struct rb_execution_context_struct; +VALUE rb_ec_str_resurrect(struct rb_execution_context_struct *ec, VALUE str, bool chilled); + +#define rb_fstring_lit(str) rb_fstring_new((str), rb_strlen_lit(str)) +#define rb_fstring_literal(str) rb_fstring_lit(str) +#define rb_fstring_enc_lit(str, enc) rb_fstring_enc_new((str), rb_strlen_lit(str), (enc)) +#define rb_fstring_enc_literal(str, enc) rb_fstring_enc_lit(str, enc) + +static inline VALUE +QUOTE(VALUE v) +{ + return rb_str_quote_unprintable(v); +} + +static inline VALUE +QUOTE_ID(ID i) +{ + return rb_id_quote_unprintable(i); +} + +static inline bool +STR_EMBED_P(VALUE str) +{ + return ! FL_TEST_RAW(str, STR_NOEMBED); +} + +static inline bool +STR_SHARED_P(VALUE str) +{ + return FL_ALL_RAW(str, STR_NOEMBED | STR_SHARED); +} + +static inline bool +CHILLED_STRING_P(VALUE obj) +{ + return RB_TYPE_P(obj, T_STRING) && FL_TEST_RAW(obj, STR_CHILLED); +} + +static inline void +CHILLED_STRING_MUTATED(VALUE str) +{ + VALUE chilled_reason = RB_FL_TEST_RAW(str, STR_CHILLED); + FL_UNSET_RAW(str, STR_CHILLED); + switch (chilled_reason) { + case STR_CHILLED_SYMBOL_TO_S: + rb_warn_unchilled_symbol_to_s(str); + break; + case STR_CHILLED_LITERAL: + rb_warn_unchilled_literal(str); + break; + default: + rb_bug("RString was chilled for multiple reasons"); + } +} + +static inline bool +is_ascii_string(VALUE str) +{ + return rb_enc_str_coderange(str) == ENC_CODERANGE_7BIT; +} + +static inline bool +is_broken_string(VALUE str) +{ + return rb_enc_str_coderange(str) == ENC_CODERANGE_BROKEN; +} + +static inline bool +at_char_boundary(const char *s, const char *p, const char *e, rb_encoding *enc) +{ + return rb_enc_left_char_head(s, p, e, enc) == p; +} + +static inline bool +at_char_right_boundary(const char *s, const char *p, const char *e, rb_encoding *enc) +{ + RUBY_ASSERT(s <= p); + RUBY_ASSERT(p <= e); + + return rb_enc_right_char_head(s, p, e, enc) == p; +} + +/* expect tail call optimization */ +// YJIT needs this function to never allocate and never raise +static inline VALUE +rb_str_eql_internal(const VALUE str1, const VALUE str2) +{ + const long len = RSTRING_LEN(str1); + const char *ptr1, *ptr2; + + if (len != RSTRING_LEN(str2)) return Qfalse; + if (!rb_str_comparable(str1, str2)) return Qfalse; + if ((ptr1 = RSTRING_PTR(str1)) == (ptr2 = RSTRING_PTR(str2))) + return Qtrue; + if (memcmp(ptr1, ptr2, len) == 0) + return Qtrue; + return Qfalse; +} + +#if __has_builtin(__builtin_constant_p) +# define rb_fstring_cstr(str) \ + (__builtin_constant_p(str) ? \ + rb_fstring_new((str), (long)strlen(str)) : \ + (rb_fstring_cstr)(str)) +#endif +#endif /* INTERNAL_STRING_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/struct.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/struct.h new file mode 100644 index 0000000..337f96a --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/struct.h @@ -0,0 +1,160 @@ +#ifndef INTERNAL_STRUCT_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_STRUCT_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Struct. + */ +#include "ruby/internal/stdbool.h" /* for bool */ +#include "ruby/ruby.h" /* for struct RBasic */ + +/* Flags of RStruct + * + * 1-7: RSTRUCT_EMBED_LEN + * If non-zero, the struct is embedded (its contents follow the + * header, rather than being on a separately allocated buffer) and + * these bits are the length of the Struct. + * 8: RSTRUCT_GEN_FIELDS + * The struct is embedded and has no space left to store the + * IMEMO/fields reference. Any ivar this struct may have will be in + * the generic_fields_tbl. This flag doesn't imply the struct has + * ivars. + */ +enum { + RSTRUCT_EMBED_LEN_MASK = RUBY_FL_USER7 | RUBY_FL_USER6 | RUBY_FL_USER5 | RUBY_FL_USER4 | + RUBY_FL_USER3 | RUBY_FL_USER2 | RUBY_FL_USER1, + RSTRUCT_EMBED_LEN_SHIFT = (RUBY_FL_USHIFT+1), + RSTRUCT_GEN_FIELDS = RUBY_FL_USER8, +}; + +struct RStruct { + struct RBasic basic; + union { + struct { + long len; + const VALUE *ptr; + VALUE fields_obj; + } heap; + /* This is a length 1 array because: + * 1. GCC has a bug that does not optimize C flexible array members + * (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102452) + * 2. Zero length arrays are not supported by all compilers + */ + const VALUE ary[1]; + } as; +}; + +#define RSTRUCT(obj) ((struct RStruct *)(obj)) + +#ifdef RSTRUCT_LEN +# undef RSTRUCT_LEN +#endif + +#ifdef RSTRUCT_PTR +# undef RSTRUCT_PTR +#endif + +#ifdef RSTRUCT_SET +# undef RSTRUCT_SET +#endif + +#ifdef RSTRUCT_GET +# undef RSTRUCT_GET +#endif + +#define RSTRUCT_LEN internal_RSTRUCT_LEN +#define RSTRUCT_SET internal_RSTRUCT_SET +#define RSTRUCT_GET internal_RSTRUCT_GET + +/* struct.c */ +VALUE rb_struct_init_copy(VALUE copy, VALUE s); +VALUE rb_struct_lookup(VALUE s, VALUE idx); +VALUE rb_struct_s_keyword_init(VALUE klass); +static inline long RSTRUCT_EMBED_LEN(VALUE st); +static inline long RSTRUCT_LEN(VALUE st); +static inline int RSTRUCT_LENINT(VALUE st); +static inline const VALUE *RSTRUCT_CONST_PTR(VALUE st); +static inline void RSTRUCT_SET(VALUE st, long k, VALUE v); +static inline VALUE RSTRUCT_GET(VALUE st, long k); + +static inline long +RSTRUCT_EMBED_LEN(VALUE st) +{ + long ret = FL_TEST_RAW(st, RSTRUCT_EMBED_LEN_MASK); + ret >>= RSTRUCT_EMBED_LEN_SHIFT; + return ret; +} + +static inline long +RSTRUCT_LEN(VALUE st) +{ + if (FL_TEST_RAW(st, RSTRUCT_EMBED_LEN_MASK)) { + return RSTRUCT_EMBED_LEN(st); + } + else { + return RSTRUCT(st)->as.heap.len; + } +} + +static inline int +RSTRUCT_LENINT(VALUE st) +{ + return rb_long2int(RSTRUCT_LEN(st)); +} + +static inline const VALUE * +RSTRUCT_CONST_PTR(VALUE st) +{ + const struct RStruct *p = RSTRUCT(st); + + if (FL_TEST_RAW(st, RSTRUCT_EMBED_LEN_MASK)) { + return p->as.ary; + } + else { + return p->as.heap.ptr; + } +} + +static inline void +RSTRUCT_SET(VALUE st, long k, VALUE v) +{ + RB_OBJ_WRITE(st, &RSTRUCT_CONST_PTR(st)[k], v); +} + +static inline VALUE +RSTRUCT_GET(VALUE st, long k) +{ + return RSTRUCT_CONST_PTR(st)[k]; +} + +static inline VALUE +RSTRUCT_FIELDS_OBJ(VALUE st) +{ + const long embed_len = RSTRUCT_EMBED_LEN(st); + VALUE fields_obj; + if (embed_len) { + RUBY_ASSERT(!FL_TEST_RAW(st, RSTRUCT_GEN_FIELDS)); + fields_obj = RSTRUCT_GET(st, embed_len); + } + else { + fields_obj = RSTRUCT(st)->as.heap.fields_obj; + } + return fields_obj; +} + +static inline void +RSTRUCT_SET_FIELDS_OBJ(VALUE st, VALUE fields_obj) +{ + const long embed_len = RSTRUCT_EMBED_LEN(st); + if (embed_len) { + RUBY_ASSERT(!FL_TEST_RAW(st, RSTRUCT_GEN_FIELDS)); + RSTRUCT_SET(st, embed_len, fields_obj); + } + else { + RB_OBJ_WRITE(st, &RSTRUCT(st)->as.heap.fields_obj, fields_obj); + } +} +#endif /* INTERNAL_STRUCT_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/symbol.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/symbol.h new file mode 100644 index 0000000..b9109b1 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/symbol.h @@ -0,0 +1,46 @@ +#ifndef INTERNAL_SYMBOL_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_SYMBOL_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Symbol. + */ +#include "ruby/ruby.h" /* for VALUE */ +#include "ruby/encoding.h" /* for rb_encoding */ +#include "internal/compilers.h" /* for __has_builtin */ + +#ifdef rb_sym_intern_ascii_cstr +# undef rb_sym_intern_ascii_cstr +#endif + +/* symbol.c */ +void rb_sym_global_symbols_mark_and_move(void); +VALUE rb_to_symbol_type(VALUE obj); +VALUE rb_sym_intern(const char *ptr, long len, rb_encoding *enc); +VALUE rb_sym_intern_ascii(const char *ptr, long len); +VALUE rb_sym_intern_ascii_cstr(const char *ptr); +int rb_is_const_name(VALUE name); +int rb_is_class_name(VALUE name); +int rb_is_instance_name(VALUE name); +int rb_is_local_name(VALUE name); +PUREFUNC(int rb_is_const_sym(VALUE sym)); +PUREFUNC(int rb_is_attrset_sym(VALUE sym)); +ID rb_make_internal_id(void); +ID rb_make_temporary_id(size_t n); +bool rb_obj_is_symbol_table(VALUE obj); +void rb_sym_global_symbol_table_foreach_weak_reference(int (*callback)(VALUE *key, void *data), void *data); +void rb_gc_free_dsymbol(VALUE); +int rb_static_id_valid_p(ID id); +void rb_free_global_symbol_table(void); + +#if __has_builtin(__builtin_constant_p) +#define rb_sym_intern_ascii_cstr(ptr) \ + (__builtin_constant_p(ptr) ? \ + rb_sym_intern_ascii((ptr), (long)strlen(ptr)) : \ + rb_sym_intern_ascii_cstr(ptr)) +#endif + +#endif /* INTERNAL_SYMBOL_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/thread.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/thread.h new file mode 100644 index 0000000..21efeee --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/thread.h @@ -0,0 +1,112 @@ +#ifndef INTERNAL_THREAD_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_THREAD_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Thread. + */ +#include "ruby/ruby.h" /* for VALUE */ +#include "ruby/intern.h" /* for rb_blocking_function_t */ +#include "ccan/list/list.h" /* for list in rb_io_close_wait_list */ + +struct rb_thread_struct; /* in vm_core.h */ +struct rb_io; + +#define RB_VM_SAVE_MACHINE_CONTEXT(th) \ + do { \ + FLUSH_REGISTER_WINDOWS; \ + setjmp((th)->ec->machine.regs); \ + SET_MACHINE_STACK_END(&(th)->ec->machine.stack_end); \ + } while (0) + +/* thread.c */ +#define COVERAGE_INDEX_LINES 0 +#define COVERAGE_INDEX_BRANCHES 1 +#define COVERAGE_TARGET_LINES 1 +#define COVERAGE_TARGET_BRANCHES 2 +#define COVERAGE_TARGET_METHODS 4 +#define COVERAGE_TARGET_ONESHOT_LINES 8 +#define COVERAGE_TARGET_EVAL 16 + +#define RUBY_FATAL_THREAD_KILLED INT2FIX(0) +#define RUBY_FATAL_THREAD_TERMINATED INT2FIX(1) +#define RUBY_FATAL_FIBER_KILLED RB_INT2FIX(2) + +VALUE rb_obj_is_mutex(VALUE obj); +VALUE rb_suppress_tracing(VALUE (*func)(VALUE), VALUE arg); +void rb_thread_execute_interrupts(VALUE th); +VALUE rb_get_coverages(void); +int rb_get_coverage_mode(void); +VALUE rb_default_coverage(int); +VALUE rb_thread_shield_new(void); +bool rb_thread_shield_owned(VALUE self); +VALUE rb_thread_shield_wait(VALUE self); +VALUE rb_thread_shield_release(VALUE self); +VALUE rb_thread_shield_destroy(VALUE self); +int rb_thread_to_be_killed(VALUE thread); +void rb_thread_acquire_fork_lock(void); +void rb_thread_release_fork_lock(void); +void rb_thread_reset_fork_lock(void); +void rb_mutex_allow_trap(VALUE self, int val); +VALUE rb_uninterruptible(VALUE (*b_proc)(VALUE), VALUE data); +VALUE rb_mutex_owned_p(VALUE self); +VALUE rb_exec_recursive_outer_mid(VALUE (*f)(VALUE g, VALUE h, int r), VALUE g, VALUE h, ID mid); +void ruby_mn_threads_params(void); + +int rb_thread_io_wait(struct rb_io *io, int events, struct timeval * timeout); +int rb_thread_wait_for_single_fd(int fd, int events, struct timeval * timeout); + +size_t rb_thread_io_close_interrupt(struct rb_io *); +void rb_thread_io_close_wait(struct rb_io *); + +void rb_ec_check_ints(struct rb_execution_context_struct *ec); + +void rb_thread_free_native_thread(void *th_ptr); + +RUBY_SYMBOL_EXPORT_BEGIN + +void *rb_thread_prevent_fork(void *(*func)(void *), void *data); /* for ext/socket/raddrinfo.c */ + +/* Temporary. This API will be removed (renamed). */ +VALUE rb_thread_io_blocking_region(struct rb_io *io, rb_blocking_function_t *func, void *data1); +VALUE rb_thread_io_blocking_call(struct rb_io *io, rb_blocking_function_t *func, void *data1, int events); + +// Invoke the given function, with the specified argument, in a way that `IO#close` from another execution context can interrupt it. +VALUE rb_thread_io_blocking_operation(VALUE self, VALUE(*function)(VALUE), VALUE argument); + +/* thread.c (export) */ +int ruby_thread_has_gvl_p(void); /* for ext/fiddle/closure.c */ + +RUBY_SYMBOL_EXPORT_END + +int rb_threadptr_execute_interrupts(struct rb_thread_struct *th, int blocking_timing); +bool rb_thread_mn_schedulable(VALUE thread); + +bool rb_thread_resolve_unblock_function(rb_unblock_function_t **unblock_function, void **data2, struct rb_thread_struct *thread); + +// interrupt exec + +typedef VALUE (rb_interrupt_exec_func_t)(void *data); + +enum rb_interrupt_exec_flag { + rb_interrupt_exec_flag_none = 0x00, + rb_interrupt_exec_flag_value_data = 0x01, + rb_interrupt_exec_flag_new_thread = 0x02, +}; + +// interrupt the target_th and run func. +struct rb_ractor_struct; + +void rb_threadptr_interrupt_exec(struct rb_thread_struct *target_th, + rb_interrupt_exec_func_t *func, void *data, enum rb_interrupt_exec_flag flags); + +// create a thread in the target_r and run func on the created thread. +void rb_ractor_interrupt_exec(struct rb_ractor_struct *target_r, + rb_interrupt_exec_func_t *func, void *data, enum rb_interrupt_exec_flag flags); + +void rb_threadptr_interrupt_exec_task_mark(struct rb_thread_struct *th); + +#endif /* INTERNAL_THREAD_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/time.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/time.h new file mode 100644 index 0000000..e21b357 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/time.h @@ -0,0 +1,37 @@ +#ifndef INTERNAL_TIME_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_TIME_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Time. + */ +#include "ruby/internal/config.h" /* for SIGNEDNESS_OF_TIME_T */ +#include "internal/bits.h" /* for SIGNED_INTEGER_MAX */ +#include "ruby/ruby.h" /* for VALUE */ + +#if SIGNEDNESS_OF_TIME_T < 0 /* signed */ +# define TIMET_MAX SIGNED_INTEGER_MAX(time_t) +# define TIMET_MIN SIGNED_INTEGER_MIN(time_t) +#elif SIGNEDNESS_OF_TIME_T > 0 /* unsigned */ +# define TIMET_MAX UNSIGNED_INTEGER_MAX(time_t) +# define TIMET_MIN ((time_t)0) +#endif + +struct timeval; /* <- in or */ + +/* time.c */ +struct timeval rb_time_timeval(VALUE); + +RUBY_SYMBOL_EXPORT_BEGIN +/* time.c (export) */ +void ruby_reset_leap_second_info(void); +#ifdef RBIMPL_ATTR_DEPRECATED_INTERNAL_ONLY +RBIMPL_ATTR_DEPRECATED_INTERNAL_ONLY() +#endif +void ruby_reset_timezone(const char *); +RUBY_SYMBOL_EXPORT_END + +#endif /* INTERNAL_TIME_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/transcode.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/transcode.h new file mode 100644 index 0000000..ce4f234 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/transcode.h @@ -0,0 +1,23 @@ +#ifndef INTERNAL_TRANSCODE_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_TRANSCODE_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Encoding::Converter. + */ +#include "ruby/internal/config.h" +#include /* for size_t */ +#include "ruby/ruby.h" /* for VALUE */ +#include "ruby/encoding.h" /* for rb_econv_t */ + +/* transcode.c */ +extern VALUE rb_cEncodingConverter; +size_t rb_econv_memsize(rb_econv_t *); + +/* vm.c */ +void rb_free_transcoder_table(void); + +#endif /* INTERNAL_TRANSCODE_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/util.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/util.h new file mode 100644 index 0000000..6eadbb9 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/util.h @@ -0,0 +1,27 @@ +#ifndef INTERNAL_UTIL_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_UTIL_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header corresponding util.c. + * @warning DO NOT ADD RANDOM GARBAGE HERE THIS FILE IS FOR util.c + */ +#include "ruby/internal/config.h" +#include /* for size_t */ + +#ifdef HAVE_SYS_TYPES_H +# include /* for ssize_t (note: on Windows ssize_t is */ +#endif /* `#define`d in ruby/config.h) */ + +/* util.c */ +char *ruby_dtoa(double d_, int mode, int ndigits, int *decpt, int *sign, char **rve); +char *ruby_hdtoa(double d, const char *xdigs, int ndigits, int *decpt, int *sign, char **rve); + +RUBY_SYMBOL_EXPORT_BEGIN +/* util.c (export) */ +RUBY_SYMBOL_EXPORT_END + +#endif /* INTERNAL_UTIL_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/variable.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/variable.h new file mode 100644 index 0000000..ca5e189 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/variable.h @@ -0,0 +1,74 @@ +#ifndef INTERNAL_VARIABLE_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_VARIABLE_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for variables. + */ +#include "ruby/internal/config.h" +#include /* for size_t */ +#include "constant.h" /* for rb_const_entry_t */ +#include "ruby/internal/stdbool.h" /* for bool */ +#include "ruby/ruby.h" /* for VALUE */ +#include "shape.h" /* for shape_id_t */ + +/* variable.c */ +void rb_gc_mark_global_tbl(void); +void rb_gc_update_global_tbl(void); +VALUE rb_search_class_path(VALUE); +VALUE rb_attr_delete(VALUE, ID); +void rb_autoload_str(VALUE mod, ID id, VALUE file); +VALUE rb_autoload_at_p(VALUE, ID, int); +void rb_autoload_copy_table_for_box(st_table *, const rb_box_t *); +NORETURN(VALUE rb_mod_const_missing(VALUE,VALUE)); +rb_gvar_getter_t *rb_gvar_getter_function_of(ID); +rb_gvar_setter_t *rb_gvar_setter_function_of(ID); +void rb_gvar_readonly_setter(VALUE v, ID id, VALUE *_); +void rb_gvar_ractor_local(const char *name); +void rb_gvar_box_ready(const char *name); + +/** + * Sets the name of a module. + * + * Non-permanently named classes can have a temporary name assigned (or + * cleared). In that case the name will be used for `#inspect` and `#to_s`, and + * nested classes/modules will be named with the temporary name as a prefix. + * + * After the module is assigned to a constant, the temporary name will be + * discarded, and the name will be computed based on the nesting. + * + * @param[in] mod An instance of ::rb_cModule. + * @param[in] name An instance of ::rb_cString. + * @retval mod + */ +VALUE rb_mod_set_temporary_name(VALUE, VALUE); + +void rb_obj_copy_ivs_to_hash_table(VALUE obj, st_table *table); +void rb_obj_init_too_complex(VALUE obj, st_table *table); +void rb_evict_ivars_to_hash(VALUE obj); +VALUE rb_obj_field_get(VALUE obj, shape_id_t target_shape_id); +void rb_ivar_set_internal(VALUE obj, ID id, VALUE val); +attr_index_t rb_ivar_set_index(VALUE obj, ID id, VALUE val); +attr_index_t rb_obj_field_set(VALUE obj, shape_id_t target_shape_id, ID field_name, VALUE val); +VALUE rb_ivar_get_at(VALUE obj, attr_index_t index, ID id); +VALUE rb_ivar_get_at_no_ractor_check(VALUE obj, attr_index_t index); + +RUBY_SYMBOL_EXPORT_BEGIN +/* variable.c (export) */ +void rb_mark_generic_ivar(VALUE obj); +VALUE rb_const_missing(VALUE klass, VALUE name); +bool rb_class_ivar_set(VALUE klass, ID vid, VALUE value); +void rb_fields_tbl_copy(VALUE dst, VALUE src); +RUBY_SYMBOL_EXPORT_END + +VALUE rb_ivar_lookup(VALUE obj, ID id, VALUE undef); +VALUE rb_gvar_get(ID); +VALUE rb_gvar_set(ID, VALUE); +VALUE rb_gvar_defined(ID); +void rb_const_warn_if_deprecated(const rb_const_entry_t *, VALUE, ID); +void rb_ensure_iv_list_size(VALUE obj, uint32_t current_len, uint32_t newsize); + +#endif /* INTERNAL_VARIABLE_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/vm.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/vm.h new file mode 100644 index 0000000..e5ed47a --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/vm.h @@ -0,0 +1,136 @@ +#ifndef INTERNAL_VM_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_VM_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for RubyVM. + */ +#include "ruby/internal/stdbool.h" /* for bool */ +#include "internal/serial.h" /* for rb_serial_t */ +#include "internal/static_assert.h" /* for STATIC_ASSERT */ +#include "ruby/ruby.h" /* for ID */ +#include "ruby/st.h" /* for st_table */ + +#ifdef rb_funcallv +# undef rb_funcallv +#endif + +#ifdef rb_method_basic_definition_p +# undef rb_method_basic_definition_p +#endif + +struct rb_callable_method_entry_struct; /* in method.h */ +struct rb_method_definition_struct; /* in method.h */ +struct rb_execution_context_struct; /* in vm_core.h */ +struct rb_control_frame_struct; /* in vm_core.h */ +struct rb_callinfo; /* in vm_core.h */ + +enum method_missing_reason { + MISSING_NOENTRY = 0x00, + MISSING_PRIVATE = 0x01, + MISSING_PROTECTED = 0x02, + MISSING_FCALL = 0x04, + MISSING_VCALL = 0x08, + MISSING_SUPER = 0x10, + MISSING_MISSING = 0x20, + MISSING_NONE = 0x40 +}; + +/* vm_insnhelper.h */ +VALUE rb_vm_push_frame_fname(struct rb_execution_context_struct *ec, VALUE fname); + +/* vm.c */ +VALUE rb_obj_is_thread(VALUE obj); +void rb_vm_mark(void *ptr); +void rb_vm_register_global_object(VALUE obj); +void rb_vm_each_stack_value(void *ptr, void (*cb)(VALUE, void*), void *ctx); +PUREFUNC(VALUE rb_vm_top_self(void)); +const void **rb_vm_get_insns_address_table(void); +VALUE rb_source_location(int *pline); +const char *rb_source_location_cstr(int *pline); +void rb_vm_pop_cfunc_frame(void); +void rb_vm_check_redefinition_by_prepend(VALUE klass); +int rb_vm_check_optimizable_mid(VALUE mid); +VALUE rb_yield_refine_block(VALUE refinement, VALUE refinements); +VALUE ruby_vm_special_exception_copy(VALUE); + +void rb_lastline_set_up(VALUE val, unsigned int up); + +/* vm_eval.c */ +VALUE rb_current_realfilepath(void); +VALUE rb_check_block_call(VALUE, ID, int, const VALUE *, rb_block_call_func_t, VALUE); +typedef void rb_check_funcall_hook(int, VALUE, ID, int, const VALUE *, VALUE); +VALUE rb_check_funcall_with_hook_kw(VALUE recv, ID mid, int argc, const VALUE *argv, + rb_check_funcall_hook *hook, VALUE arg, int kw_splat); +const char *rb_type_str(enum ruby_value_type type); +VALUE rb_check_funcall_default(VALUE, ID, int, const VALUE *, VALUE); +VALUE rb_check_funcall_basic_kw(VALUE, ID, VALUE, int, const VALUE*, int); +VALUE rb_yield_1(VALUE val); +VALUE rb_yield_force_blockarg(VALUE values); +VALUE rb_lambda_call(VALUE obj, ID mid, int argc, const VALUE *argv, + rb_block_call_func_t bl_proc, int min_argc, int max_argc, + VALUE data2); +void rb_check_stack_overflow(void); +#define RB_BLOCK_NO_USE_PACKED_ARGS 2 +VALUE rb_block_call2(VALUE obj, ID mid, int argc, const VALUE *argv, rb_block_call_func_t bl_proc, VALUE data2, long flags); +struct vm_ifunc *rb_current_ifunc(void); +VALUE rb_gccct_clear_table(VALUE); + +#if USE_YJIT || USE_ZJIT +/* vm_exec.c */ +extern uint64_t rb_vm_insn_count; +#endif + +extern bool rb_free_at_exit; + +/* miniinit.c and builtin.c */ +void rb_free_loaded_builtin_table(void); + +/* vm_insnhelper.c */ +VALUE rb_equal_opt(VALUE obj1, VALUE obj2); +VALUE rb_eql_opt(VALUE obj1, VALUE obj2); + +struct rb_iseq_struct; +const struct rb_callcache *rb_vm_search_method_slowpath(const struct rb_callinfo *ci, VALUE klass); + +/* vm_method.c */ +int rb_ec_obj_respond_to(struct rb_execution_context_struct *ec, VALUE obj, ID id, int priv); + +void rb_clear_constant_cache(void); + +/* vm_dump.c */ +void rb_print_backtrace(FILE *); + +/* vm_backtrace.c */ +VALUE rb_vm_thread_backtrace(int argc, const VALUE *argv, VALUE thval); +VALUE rb_vm_thread_backtrace_locations(int argc, const VALUE *argv, VALUE thval); +VALUE rb_vm_backtrace(int argc, const VALUE * argv, struct rb_execution_context_struct * ec); +VALUE rb_vm_backtrace_locations(int argc, const VALUE * argv, struct rb_execution_context_struct * ec); +VALUE rb_make_backtrace(void); +void rb_backtrace_print_as_bugreport(FILE*); +int rb_backtrace_p(VALUE obj); +VALUE rb_backtrace_to_str_ary(VALUE obj); +VALUE rb_backtrace_to_location_ary(VALUE obj); +VALUE rb_location_ary_to_backtrace(VALUE ary); +void rb_backtrace_each(VALUE (*iter)(VALUE recv, VALUE str), VALUE output); +int rb_frame_info_p(VALUE obj); +int rb_get_node_id_from_frame_info(VALUE obj); +const struct rb_iseq_struct *rb_get_iseq_from_frame_info(VALUE obj); + +VALUE rb_ec_backtrace_object(const struct rb_execution_context_struct *ec); + +#define RUBY_DTRACE_CREATE_HOOK(name, arg) \ + RUBY_DTRACE_HOOK(name##_CREATE, arg) +#define RUBY_DTRACE_HOOK(name, arg) \ +do { \ + if (UNLIKELY(RUBY_DTRACE_##name##_ENABLED())) { \ + int dtrace_line; \ + const char *dtrace_file = rb_source_location_cstr(&dtrace_line); \ + if (!dtrace_file) dtrace_file = ""; \ + RUBY_DTRACE_##name(arg, dtrace_file, dtrace_line); \ + } \ +} while (0) +#endif /* INTERNAL_VM_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/warnings.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/warnings.h new file mode 100644 index 0000000..020212e --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/internal/warnings.h @@ -0,0 +1,16 @@ +#ifndef INTERNAL_WARNINGS_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_WARNINGS_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header to suppress / mandate warnings. + */ +#include "ruby/internal/warning_push.h" +#define COMPILER_WARNING_PUSH RBIMPL_WARNING_PUSH() +#define COMPILER_WARNING_POP RBIMPL_WARNING_POP() +#define COMPILER_WARNING_ERROR(flag) RBIMPL_WARNING_ERROR(flag) +#define COMPILER_WARNING_IGNORED(flag) RBIMPL_WARNING_IGNORED(flag) +#endif /* INTERNAL_WARNINGS_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/iseq.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/iseq.h new file mode 100644 index 0000000..86063d8 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/iseq.h @@ -0,0 +1,357 @@ +#ifndef RUBY_ISEQ_H +#define RUBY_ISEQ_H 1 +/********************************************************************** + + iseq.h - + + $Author$ + created at: 04/01/01 23:36:57 JST + + Copyright (C) 2004-2008 Koichi Sasada + +**********************************************************************/ +#include "internal/gc.h" +#include "shape.h" +#include "vm_core.h" +#include "prism_compile.h" + +RUBY_EXTERN const int ruby_api_version[]; +#define ISEQ_MAJOR_VERSION ((unsigned int)ruby_api_version[0]) +#define ISEQ_MINOR_VERSION ((unsigned int)ruby_api_version[1]) + +#define ISEQ_MBITS_SIZE sizeof(iseq_bits_t) +#define ISEQ_MBITS_BITLENGTH (ISEQ_MBITS_SIZE * CHAR_BIT) +#define ISEQ_MBITS_SET(buf, i) (buf[(i) / ISEQ_MBITS_BITLENGTH] |= ((iseq_bits_t)1 << ((i) % ISEQ_MBITS_BITLENGTH))) +#define ISEQ_MBITS_SET_P(buf, i) ((buf[(i) / ISEQ_MBITS_BITLENGTH] >> ((i) % ISEQ_MBITS_BITLENGTH)) & 0x1) +#define ISEQ_MBITS_BUFLEN(size) roomof(size, ISEQ_MBITS_BITLENGTH) + +#ifndef USE_ISEQ_NODE_ID +#define USE_ISEQ_NODE_ID 1 +#endif + +#ifndef rb_iseq_t +typedef struct rb_iseq_struct rb_iseq_t; +#define rb_iseq_t rb_iseq_t +#endif +typedef void (*rb_iseq_callback)(const rb_iseq_t *, void *); + +extern const ID rb_iseq_shared_exc_local_tbl[]; + +#define ISEQ_COVERAGE(iseq) ISEQ_BODY(iseq)->variable.coverage +#define ISEQ_COVERAGE_SET(iseq, cov) RB_OBJ_WRITE(iseq, &ISEQ_BODY(iseq)->variable.coverage, cov) +#define ISEQ_LINE_COVERAGE(iseq) RARRAY_AREF(ISEQ_COVERAGE(iseq), COVERAGE_INDEX_LINES) +#define ISEQ_BRANCH_COVERAGE(iseq) RARRAY_AREF(ISEQ_COVERAGE(iseq), COVERAGE_INDEX_BRANCHES) + +#define ISEQ_PC2BRANCHINDEX(iseq) ISEQ_BODY(iseq)->variable.pc2branchindex +#define ISEQ_PC2BRANCHINDEX_SET(iseq, h) RB_OBJ_WRITE(iseq, &ISEQ_BODY(iseq)->variable.pc2branchindex, h) + +#define ISEQ_FLIP_CNT(iseq) ISEQ_BODY(iseq)->variable.flip_count + +#define ISEQ_FROZEN_STRING_LITERAL_ENABLED 1 +#define ISEQ_FROZEN_STRING_LITERAL_DISABLED 0 +#define ISEQ_FROZEN_STRING_LITERAL_UNSET -1 + +static inline rb_snum_t +ISEQ_FLIP_CNT_INCREMENT(const rb_iseq_t *iseq) +{ + rb_snum_t cnt = ISEQ_BODY(iseq)->variable.flip_count; + ISEQ_BODY(iseq)->variable.flip_count += 1; + return cnt; +} + +static inline VALUE * +ISEQ_ORIGINAL_ISEQ(const rb_iseq_t *iseq) +{ + return ISEQ_BODY(iseq)->variable.original_iseq; +} + +static inline void +ISEQ_ORIGINAL_ISEQ_CLEAR(const rb_iseq_t *iseq) +{ + void *ptr = ISEQ_BODY(iseq)->variable.original_iseq; + ISEQ_BODY(iseq)->variable.original_iseq = NULL; + ruby_xfree(ptr); +} + +static inline VALUE * +ISEQ_ORIGINAL_ISEQ_ALLOC(const rb_iseq_t *iseq, long size) +{ + return ISEQ_BODY(iseq)->variable.original_iseq = + ALLOC_N(VALUE, size); +} + +#define ISEQ_TRACE_EVENTS (RUBY_EVENT_LINE | \ + RUBY_EVENT_CLASS | \ + RUBY_EVENT_END | \ + RUBY_EVENT_CALL | \ + RUBY_EVENT_RETURN| \ + RUBY_EVENT_C_CALL| \ + RUBY_EVENT_C_RETURN | \ + RUBY_EVENT_B_CALL | \ + RUBY_EVENT_B_RETURN | \ + RUBY_EVENT_RESCUE | \ + RUBY_EVENT_COVERAGE_LINE| \ + RUBY_EVENT_COVERAGE_BRANCH) + +#define ISEQ_NOT_LOADED_YET IMEMO_FL_USER1 +#define ISEQ_USE_COMPILE_DATA IMEMO_FL_USER2 +#define ISEQ_TRANSLATED IMEMO_FL_USER3 + +#define ISEQ_EXECUTABLE_P(iseq) (FL_TEST_RAW(((VALUE)iseq), ISEQ_NOT_LOADED_YET | ISEQ_USE_COMPILE_DATA) == 0) + +struct iseq_compile_data { + /* GC is needed */ + const VALUE err_info; + const VALUE catch_table_ary; /* Array */ + + /* Mirror fields from ISEQ_BODY so they are accessible during iseq setup */ + unsigned int iseq_size; + VALUE *iseq_encoded; /* half-encoded iseq (insn addr and operands) */ + bool is_single_mark_bit; /* identifies whether mark bits are single or a list */ + + union { + iseq_bits_t * list; /* Find references for GC */ + iseq_bits_t single; + } mark_bits; + + /* GC is not needed */ + struct iseq_label_data *start_label; + struct iseq_label_data *end_label; + struct iseq_label_data *redo_label; + const rb_iseq_t *current_block; + struct iseq_compile_data_ensure_node_stack *ensure_node_stack; + struct { + struct iseq_compile_data_storage *storage_head; + struct iseq_compile_data_storage *storage_current; + } node; + struct { + struct iseq_compile_data_storage *storage_head; + struct iseq_compile_data_storage *storage_current; + } insn; + bool in_rescue; + bool in_masgn; + int loopval_popped; /* used by NODE_BREAK */ + int last_line; + int label_no; + int node_level; + int isolated_depth; + unsigned int ci_index; + unsigned int ic_index; + const rb_compile_option_t *option; + struct rb_id_table *ivar_cache_table; + const struct rb_builtin_function *builtin_function_table; + const NODE *root_node; + bool catch_except_p; // If a frame of this ISeq may catch exception, set true. +#if OPT_SUPPORT_JOKE + st_table *labels_table; +#endif +}; + +static inline struct iseq_compile_data * +ISEQ_COMPILE_DATA(const rb_iseq_t *iseq) +{ + if (iseq->flags & ISEQ_USE_COMPILE_DATA) { + return iseq->aux.compile_data; + } + else { + return NULL; + } +} + +static inline void +ISEQ_COMPILE_DATA_ALLOC(rb_iseq_t *iseq) +{ + iseq->aux.compile_data = ZALLOC(struct iseq_compile_data); + iseq->flags |= ISEQ_USE_COMPILE_DATA; +} + +static inline void +ISEQ_COMPILE_DATA_CLEAR(rb_iseq_t *iseq) +{ + iseq->flags &= ~ISEQ_USE_COMPILE_DATA; + iseq->aux.compile_data = NULL; +} + +static inline rb_iseq_t * +iseq_imemo_alloc(void) +{ + rb_iseq_t *iseq = SHAREABLE_IMEMO_NEW(rb_iseq_t, imemo_iseq, 0); + + // Clear out the whole iseq except for the flags. + memset((char *)iseq + sizeof(VALUE), 0, sizeof(rb_iseq_t) - sizeof(VALUE)); + + return iseq; +} + +VALUE rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt); +void rb_ibf_load_iseq_complete(rb_iseq_t *iseq); +const rb_iseq_t *rb_iseq_ibf_load(VALUE str); +const rb_iseq_t *rb_iseq_ibf_load_bytes(const char *cstr, size_t); +VALUE rb_iseq_ibf_load_extra_data(VALUE str); +void rb_iseq_init_trace(rb_iseq_t *iseq); +int rb_iseq_add_local_tracepoint_recursively(const rb_iseq_t *iseq, rb_event_flag_t turnon_events, VALUE tpval, unsigned int target_line, bool target_bmethod); +int rb_iseq_remove_local_tracepoint_recursively(const rb_iseq_t *iseq, VALUE tpval); +const rb_iseq_t *rb_iseq_load_iseq(VALUE fname); +const rb_iseq_t *rb_iseq_compile_iseq(VALUE str, VALUE fname); +int rb_iseq_opt_frozen_string_literal(void); + +#if VM_INSN_INFO_TABLE_IMPL == 2 +unsigned int *rb_iseq_insns_info_decode_positions(const struct rb_iseq_constant_body *body); +#endif + +int rb_vm_insn_addr2opcode(const void *addr); + +RUBY_SYMBOL_EXPORT_BEGIN + +/* compile.c */ +VALUE rb_iseq_compile_node(rb_iseq_t *iseq, const NODE *node); +VALUE rb_iseq_compile_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func * ifunc); +VALUE *rb_iseq_original_iseq(const rb_iseq_t *iseq); +void rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, + VALUE locals, VALUE args, + VALUE exception, VALUE body); +void rb_iseq_mark_and_move_insn_storage(struct iseq_compile_data_storage *arena); + +VALUE rb_iseq_load(VALUE data, VALUE parent, VALUE opt); +VALUE rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc); +unsigned int rb_iseq_line_no(const rb_iseq_t *iseq, size_t pos); +#ifdef USE_ISEQ_NODE_ID +int rb_iseq_node_id(const rb_iseq_t *iseq, size_t pos); +#endif +void rb_iseq_trace_set(const rb_iseq_t *iseq, rb_event_flag_t turnon_events); +void rb_iseq_trace_set_all(rb_event_flag_t turnon_events); +void rb_iseq_insns_info_encode_positions(const rb_iseq_t *iseq); + +struct rb_iseq_constant_body *rb_iseq_constant_body_alloc(void); +VALUE rb_iseqw_new(const rb_iseq_t *iseq); +const rb_iseq_t *rb_iseqw_to_iseq(VALUE iseqw); + +VALUE rb_iseq_absolute_path(const rb_iseq_t *iseq); /* obsolete */ +int rb_iseq_from_eval_p(const rb_iseq_t *iseq); +VALUE rb_iseq_type(const rb_iseq_t *iseq); +VALUE rb_iseq_label(const rb_iseq_t *iseq); +VALUE rb_iseq_base_label(const rb_iseq_t *iseq); +VALUE rb_iseq_first_lineno(const rb_iseq_t *iseq); +VALUE rb_iseq_method_name(const rb_iseq_t *iseq); +void rb_iseq_code_location(const rb_iseq_t *iseq, int *first_lineno, int *first_column, int *last_lineno, int *last_column); + +void rb_iseq_remove_coverage_all(void); + +/* proc.c */ +const rb_iseq_t *rb_method_iseq(VALUE body); +const rb_iseq_t *rb_proc_get_iseq(VALUE proc, int *is_proc); + +struct rb_compile_option_struct { + unsigned int inline_const_cache: 1; + unsigned int peephole_optimization: 1; + unsigned int tailcall_optimization: 1; + unsigned int specialized_instruction: 1; + unsigned int operands_unification: 1; + unsigned int instructions_unification: 1; + signed int frozen_string_literal: 2; /* -1: not specified, 0: false, 1: true */ + unsigned int debug_frozen_string_literal: 1; + unsigned int coverage_enabled: 1; + int debug_level; +}; + +struct iseq_insn_info_entry { + int line_no; +#ifdef USE_ISEQ_NODE_ID + int node_id; +#endif + rb_event_flag_t events; +}; + +/* + * iseq type: + * CATCH_TYPE_RESCUE, CATCH_TYPE_ENSURE: + * use iseq as continuation. + * + * CATCH_TYPE_BREAK (iter): + * use iseq as key. + * + * CATCH_TYPE_BREAK (while), CATCH_TYPE_RETRY, + * CATCH_TYPE_REDO, CATCH_TYPE_NEXT: + * NULL. + */ +enum rb_catch_type { + CATCH_TYPE_RESCUE = INT2FIX(1), + CATCH_TYPE_ENSURE = INT2FIX(2), + CATCH_TYPE_RETRY = INT2FIX(3), + CATCH_TYPE_BREAK = INT2FIX(4), + CATCH_TYPE_REDO = INT2FIX(5), + CATCH_TYPE_NEXT = INT2FIX(6) +}; + +struct iseq_catch_table_entry { + enum rb_catch_type type; + rb_iseq_t *iseq; + + unsigned int start; + unsigned int end; + unsigned int cont; + unsigned int sp; +}; + +RBIMPL_ATTR_PACKED_STRUCT_UNALIGNED_BEGIN() +struct iseq_catch_table { + unsigned int size; + struct iseq_catch_table_entry entries[FLEX_ARY_LEN]; +} RBIMPL_ATTR_PACKED_STRUCT_UNALIGNED_END(); + +static inline int +iseq_catch_table_bytes(int n) +{ + enum { + catch_table_entry_size = sizeof(struct iseq_catch_table_entry), + catch_table_entries_max = (INT_MAX - offsetof(struct iseq_catch_table, entries)) / catch_table_entry_size + }; + if (n > catch_table_entries_max) rb_fatal("too large iseq_catch_table - %d", n); + return (int)(offsetof(struct iseq_catch_table, entries) + + n * catch_table_entry_size); +} + +#define INITIAL_ISEQ_COMPILE_DATA_STORAGE_BUFF_SIZE (512) + +struct iseq_compile_data_storage { + struct iseq_compile_data_storage *next; + unsigned int pos; + unsigned int size; + char buff[FLEX_ARY_LEN]; +}; + +/* defined? */ + +enum defined_type { + DEFINED_NOT_DEFINED, + DEFINED_NIL = 1, + DEFINED_IVAR, + DEFINED_LVAR, + DEFINED_GVAR, + DEFINED_CVAR, + DEFINED_CONST, + DEFINED_METHOD, + DEFINED_YIELD, + DEFINED_ZSUPER, + DEFINED_SELF, + DEFINED_TRUE, + DEFINED_FALSE, + DEFINED_ASGN, + DEFINED_EXPR, + DEFINED_REF, + DEFINED_FUNC, + DEFINED_CONST_FROM +}; + +VALUE rb_iseq_defined_string(enum defined_type type); + +/* vm.c */ +VALUE rb_iseq_local_variables(const rb_iseq_t *iseq); + +attr_index_t rb_estimate_iv_count(VALUE klass, const rb_iseq_t * initialize_iseq); + +void rb_free_encoded_insn_data(void); + +RUBY_SYMBOL_EXPORT_END + +#endif /* RUBY_ISEQ_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/method.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/method.h new file mode 100644 index 0000000..87fb249 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/method.h @@ -0,0 +1,271 @@ +#ifndef RUBY_METHOD_H +#define RUBY_METHOD_H 1 +/********************************************************************** + + method.h - + + $Author$ + created at: Wed Jul 15 20:02:33 2009 + + Copyright (C) 2009 Koichi Sasada + +**********************************************************************/ + +#include "internal.h" +#include "internal/imemo.h" +#include "internal/compilers.h" +#include "internal/static_assert.h" +#include "ruby/atomic.h" + +#ifndef END_OF_ENUMERATION +# if defined(__GNUC__) &&! defined(__STRICT_ANSI__) +# define END_OF_ENUMERATION(key) +# else +# define END_OF_ENUMERATION(key) END_OF_##key##_PLACEHOLDER = 0 +# endif +#endif + +/* cref */ + +typedef enum { + METHOD_VISI_UNDEF = 0x00, + METHOD_VISI_PUBLIC = 0x01, + METHOD_VISI_PRIVATE = 0x02, + METHOD_VISI_PROTECTED = 0x03, + + METHOD_VISI_MASK = 0x03 +} rb_method_visibility_t; + +typedef struct rb_scope_visi_struct { + BITFIELD(rb_method_visibility_t, method_visi, 3); + unsigned int module_func : 1; +} rb_scope_visibility_t; + +/*! CREF (Class REFerence) */ +typedef struct rb_cref_struct { + VALUE flags; + VALUE refinements; + VALUE klass_or_self; + struct rb_cref_struct * next; + const rb_scope_visibility_t scope_visi; +} rb_cref_t; + +/* method data type */ + +typedef struct rb_method_entry_struct { + VALUE flags; + VALUE defined_class; + struct rb_method_definition_struct * const def; + ID called_id; + VALUE owner; +} rb_method_entry_t; + +typedef struct rb_callable_method_entry_struct { /* same fields with rb_method_entry_t */ + VALUE flags; + const VALUE defined_class; + struct rb_method_definition_struct * const def; + ID called_id; + const VALUE owner; +} rb_callable_method_entry_t; + +#define METHOD_ENTRY_VISI(me) (rb_method_visibility_t)(((me)->flags & (IMEMO_FL_USER0 | IMEMO_FL_USER1)) >> (IMEMO_FL_USHIFT+0)) +#define METHOD_ENTRY_BASIC(me) (int) (((me)->flags & (IMEMO_FL_USER2 )) >> (IMEMO_FL_USHIFT+2)) +#define METHOD_ENTRY_COMPLEMENTED(me) ((me)->flags & IMEMO_FL_USER3) +#define METHOD_ENTRY_COMPLEMENTED_SET(me) ((me)->flags |= IMEMO_FL_USER3) +#define METHOD_ENTRY_CACHED(me) ((me)->flags & IMEMO_FL_USER4) +#define METHOD_ENTRY_INVALIDATED(me) ((me)->flags & IMEMO_FL_USER5) +#define METHOD_ENTRY_INVALIDATED_SET(me) ((me)->flags |= IMEMO_FL_USER5) + +static inline void +METHOD_ENTRY_CACHED_SET(rb_callable_method_entry_t *me) +{ + if (!METHOD_ENTRY_CACHED(me)) { + me->flags |= IMEMO_FL_USER4; + } +} + +static inline void +METHOD_ENTRY_VISI_SET(rb_method_entry_t *me, rb_method_visibility_t visi) +{ + VM_ASSERT((int)visi >= 0 && visi <= 3); + me->flags = (me->flags & ~(IMEMO_FL_USER0 | IMEMO_FL_USER1)) | (visi << (IMEMO_FL_USHIFT+0)); +} +static inline void +METHOD_ENTRY_BASIC_SET(rb_method_entry_t *me, unsigned int basic) +{ + VM_ASSERT(basic <= 1); + me->flags = (me->flags & ~(IMEMO_FL_USER2 )) | (basic << (IMEMO_FL_USHIFT+2)); +} +static inline void +METHOD_ENTRY_FLAGS_SET(rb_method_entry_t *me, rb_method_visibility_t visi, unsigned int basic) +{ + VM_ASSERT((int)visi >= 0 && visi <= 3); + VM_ASSERT(basic <= 1); + me->flags = + (me->flags & ~(IMEMO_FL_USER0|IMEMO_FL_USER1|IMEMO_FL_USER2)) | + ((visi << (IMEMO_FL_USHIFT+0)) | (basic << (IMEMO_FL_USHIFT+2))); +} +static inline void +METHOD_ENTRY_FLAGS_COPY(rb_method_entry_t *dst, const rb_method_entry_t *src) +{ + dst->flags = + (dst->flags & ~(IMEMO_FL_USER0|IMEMO_FL_USER1|IMEMO_FL_USER2 + |IMEMO_FL_USER3)) | + (src->flags & (IMEMO_FL_USER0|IMEMO_FL_USER1|IMEMO_FL_USER2|IMEMO_FL_USER3)); +} + +typedef enum { + VM_METHOD_TYPE_ISEQ, /*!< Ruby method */ + VM_METHOD_TYPE_CFUNC, /*!< C method */ + VM_METHOD_TYPE_ATTRSET, /*!< attr_writer or attr_accessor */ + VM_METHOD_TYPE_IVAR, /*!< attr_reader or attr_accessor */ + VM_METHOD_TYPE_BMETHOD, + VM_METHOD_TYPE_ZSUPER, + VM_METHOD_TYPE_ALIAS, + VM_METHOD_TYPE_UNDEF, + VM_METHOD_TYPE_NOTIMPLEMENTED, + VM_METHOD_TYPE_OPTIMIZED, /*!< Kernel#send, Proc#call, etc */ + VM_METHOD_TYPE_MISSING, /*!< wrapper for method_missing(id) */ + VM_METHOD_TYPE_REFINED, /*!< refinement */ + + END_OF_ENUMERATION(VM_METHOD_TYPE) +} rb_method_type_t; +#define VM_METHOD_TYPE_MINIMUM_BITS 4 +STATIC_ASSERT(VM_METHOD_TYPE_MINIMUM_BITS, + VM_METHOD_TYPE_REFINED <= (1<klass is original owner */ +} rb_method_alias_t; + +typedef struct rb_method_refined_struct { + struct rb_method_entry_struct * orig_me; +} rb_method_refined_t; + +typedef struct rb_method_bmethod_struct { + VALUE proc; /* should be marked */ + struct rb_hook_list_struct *hooks; + VALUE defined_ractor; +} rb_method_bmethod_t; + +enum method_optimized_type { + OPTIMIZED_METHOD_TYPE_SEND, + OPTIMIZED_METHOD_TYPE_CALL, + OPTIMIZED_METHOD_TYPE_BLOCK_CALL, + OPTIMIZED_METHOD_TYPE_STRUCT_AREF, + OPTIMIZED_METHOD_TYPE_STRUCT_ASET, + OPTIMIZED_METHOD_TYPE__MAX +}; + +typedef struct rb_method_optimized { + enum method_optimized_type type; + unsigned int index; +} rb_method_optimized_t; + +struct rb_method_definition_struct { + BITFIELD(rb_method_type_t, type, VM_METHOD_TYPE_MINIMUM_BITS); + unsigned int iseq_overload: 1; + unsigned int no_redef_warning: 1; + unsigned int aliased : 1; + + rb_atomic_t reference_count; + + union { + rb_method_iseq_t iseq; + rb_method_cfunc_t cfunc; + rb_method_attr_t attr; + rb_method_alias_t alias; + rb_method_refined_t refined; + rb_method_bmethod_t bmethod; + rb_method_optimized_t optimized; + } body; + + ID original_id; + uintptr_t method_serial; + const rb_box_t *box; +}; + +struct rb_id_table; + +typedef struct rb_method_definition_struct rb_method_definition_t; +STATIC_ASSERT(sizeof_method_def, offsetof(rb_method_definition_t, body) <= 8); + +#define UNDEFINED_METHOD_ENTRY_P(me) (!(me) || !(me)->def || (me)->def->type == VM_METHOD_TYPE_UNDEF) +#define UNDEFINED_REFINED_METHOD_P(def) \ + ((def)->type == VM_METHOD_TYPE_REFINED && \ + UNDEFINED_METHOD_ENTRY_P((def)->body.refined.orig_me)) + +void rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *option, rb_method_visibility_t visi); +void rb_add_method_cfunc(VALUE klass, ID mid, VALUE (*func)(ANYARGS), int argc, rb_method_visibility_t visi); +void rb_add_method_iseq(VALUE klass, ID mid, const rb_iseq_t *iseq, rb_cref_t *cref, rb_method_visibility_t visi); +void rb_add_method_optimized(VALUE klass, ID mid, enum method_optimized_type, unsigned int index, rb_method_visibility_t visi); +void rb_add_refined_method_entry(VALUE refined_class, ID mid); + +rb_method_entry_t *rb_method_entry_set(VALUE klass, ID mid, const rb_method_entry_t *, rb_method_visibility_t noex); +rb_method_entry_t *rb_method_entry_create(ID called_id, VALUE klass, rb_method_visibility_t visi, rb_method_definition_t *def); + +const rb_method_entry_t *rb_method_entry_at(VALUE obj, ID id); + +const rb_method_entry_t *rb_method_entry(VALUE klass, ID id); +const rb_method_entry_t *rb_method_entry_with_refinements(VALUE klass, ID id, VALUE *defined_class); +const rb_method_entry_t *rb_method_entry_without_refinements(VALUE klass, ID id, VALUE *defined_class); +const rb_method_entry_t *rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me); +RUBY_SYMBOL_EXPORT_BEGIN +const rb_method_entry_t *rb_resolve_me_location(const rb_method_entry_t *, VALUE[5]); +RUBY_SYMBOL_EXPORT_END + +const rb_callable_method_entry_t *rb_callable_method_entry(VALUE klass, ID id); +const rb_callable_method_entry_t *rb_callable_method_entry_or_negative(VALUE klass, ID id); +const rb_callable_method_entry_t *rb_callable_method_entry_with_refinements(VALUE klass, ID id, VALUE *defined_class); +const rb_callable_method_entry_t *rb_callable_method_entry_without_refinements(VALUE klass, ID id, VALUE *defined_class); + +int rb_method_entry_arity(const rb_method_entry_t *me); +int rb_method_entry_eq(const rb_method_entry_t *m1, const rb_method_entry_t *m2); +st_index_t rb_hash_method_entry(st_index_t hash, const rb_method_entry_t *me); + +VALUE rb_method_entry_location(const rb_method_entry_t *me); + +void rb_free_method_entry_vm_weak_references(const rb_method_entry_t *me); +void rb_free_method_entry(const rb_method_entry_t *me); + +const rb_method_entry_t *rb_method_entry_clone(const rb_method_entry_t *me); +const rb_callable_method_entry_t *rb_method_entry_complement_defined_class(const rb_method_entry_t *src_me, ID called_id, VALUE defined_class); +void rb_method_entry_copy(rb_method_entry_t *dst, const rb_method_entry_t *src); + +void rb_method_table_insert(VALUE klass, struct rb_id_table *table, ID method_id, const rb_method_entry_t *me); +void rb_method_table_insert0(VALUE klass, struct rb_id_table *table, ID method_id, const rb_method_entry_t *me, bool iclass_shared_mtbl); + +void rb_scope_visibility_set(rb_method_visibility_t); + +VALUE rb_unnamed_parameters(int arity); + +void rb_vm_insert_cc_refinement(const struct rb_callcache *cc); +void rb_vm_delete_cc_refinement(const struct rb_callcache *cc); + +void rb_clear_method_cache(VALUE klass_or_module, ID mid); +void rb_clear_all_refinement_method_cache(void); +void rb_invalidate_method_caches(struct rb_id_table *cm_tbl, VALUE cc_tbl); + +#endif /* RUBY_METHOD_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/node.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/node.h new file mode 100644 index 0000000..d8ee7db --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/node.h @@ -0,0 +1,122 @@ +#ifndef RUBY_NODE_H +#define RUBY_NODE_H 1 +/********************************************************************** + + node.h - + + $Author$ + created at: Fri May 28 15:14:02 JST 1993 + + Copyright (C) 1993-2007 Yukihiro Matsumoto + +**********************************************************************/ + +#include +#include "rubyparser.h" +#include "ruby/backward/2/attributes.h" + +typedef void (*bug_report_func)(const char *fmt, ...) RUBYPARSER_ATTRIBUTE_FORMAT(1, 2); +typedef struct node_buffer_elem_struct { + struct node_buffer_elem_struct *next; + long len; /* Length of nodes */ + size_t allocated; /* Total memory size of allocated buf */ + size_t used; /* Current usage of buf */ + NODE **nodes; /* Array of node pointers */ + NODE *buf[FLEX_ARY_LEN]; +} node_buffer_elem_t; + +typedef struct { + node_buffer_elem_t *head; + node_buffer_elem_t *last; +} node_buffer_list_t; + +struct node_buffer_struct { + node_buffer_list_t buffer_list; + struct rb_ast_local_table_link *local_tables; + // - id (sequence number) + // - token_type + // - text of token + // - location info + // Array, whose entry is array + rb_parser_ary_t *tokens; +}; + +RUBY_SYMBOL_EXPORT_BEGIN + +#ifdef UNIVERSAL_PARSER +rb_ast_t *rb_ast_new(const rb_parser_config_t *config); +#else +rb_ast_t *rb_ast_new(void); +#endif +size_t rb_ast_memsize(const rb_ast_t*); +void rb_ast_dispose(rb_ast_t*); +const char *ruby_node_name(int node); +void rb_node_init(NODE *n, enum node_type type); + +void rb_ast_update_references(rb_ast_t*); +void rb_ast_free(rb_ast_t*); +NODE *rb_ast_newnode(rb_ast_t*, enum node_type type, size_t size, size_t alignment); +void rb_ast_delete_node(rb_ast_t*, NODE *n); +rb_ast_id_table_t *rb_ast_new_local_table(rb_ast_t*, int); +rb_ast_id_table_t *rb_ast_resize_latest_local_table(rb_ast_t*, int); + +VALUE rb_parser_dump_tree(const NODE *node, int comment); + +const struct kwtable *rb_reserved_word(const char *, unsigned int); + +struct parser_params; +PRINTF_ARGS(void rb_parser_printf(struct parser_params *parser, const char *fmt, ...), 2, 3); +VALUE rb_node_set_type(NODE *n, enum node_type t); +enum node_type rb_node_get_type(const NODE *n); + +RUBY_SYMBOL_EXPORT_END + +#define NODE_LSHIFT (NODE_TYPESHIFT+7) +#define NODE_LMASK (((SIGNED_VALUE)1<<(sizeof(VALUE)*CHAR_BIT-NODE_LSHIFT))-1) + +static inline int +nd_line(const NODE *n) +{ + if (!n) return -1; + SIGNED_VALUE flags = (SIGNED_VALUE)n->flags; + return (int)(flags >> NODE_LSHIFT); +} + +static inline void +nd_set_line(NODE *n, SIGNED_VALUE l) +{ + n->flags &= ~(~(VALUE)0 << NODE_LSHIFT); + n->flags |= ((VALUE)(l & NODE_LMASK) << NODE_LSHIFT); +} + +#define NODE_SPECIAL_REQUIRED_KEYWORD ((NODE *)-1) +#define NODE_REQUIRED_KEYWORD_P(node) ((node) == NODE_SPECIAL_REQUIRED_KEYWORD) +#define NODE_SPECIAL_NO_NAME_REST ((NODE *)-1) +#define NODE_NAMED_REST_P(node) ((node) != NODE_SPECIAL_NO_NAME_REST) +#define NODE_SPECIAL_EXCESSIVE_COMMA ((ID)1) +#define NODE_SPECIAL_NO_REST_KEYWORD ((NODE *)-1) + +#define nd_code_loc(n) (&RNODE(n)->nd_loc) +#define nd_first_column(n) ((int)(RNODE(n)->nd_loc.beg_pos.column)) +#define nd_set_first_column(n, v) (RNODE(n)->nd_loc.beg_pos.column = (v)) +#define nd_first_lineno(n) ((int)(RNODE(n)->nd_loc.beg_pos.lineno)) +#define nd_set_first_lineno(n, v) (RNODE(n)->nd_loc.beg_pos.lineno = (v)) +#define nd_first_loc(n) (RNODE(n)->nd_loc.beg_pos) +#define nd_set_first_loc(n, v) (nd_first_loc(n) = (v)) + +#define nd_last_column(n) ((int)(RNODE(n)->nd_loc.end_pos.column)) +#define nd_set_last_column(n, v) (RNODE(n)->nd_loc.end_pos.column = (v)) +#define nd_last_lineno(n) ((int)(RNODE(n)->nd_loc.end_pos.lineno)) +#define nd_set_last_lineno(n, v) (RNODE(n)->nd_loc.end_pos.lineno = (v)) +#define nd_last_loc(n) (RNODE(n)->nd_loc.end_pos) +#define nd_set_last_loc(n, v) (nd_last_loc(n) = (v)) +#define nd_node_id(n) (RNODE(n)->node_id) +#define nd_set_node_id(n,id) (RNODE(n)->node_id = (id)) + +static inline bool +nd_type_p(const NODE *n, enum node_type t) +{ + return (enum node_type)nd_type(n) == t; +} + +#endif /* RUBY_NODE_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/parser_st.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/parser_st.h new file mode 100644 index 0000000..877b1e9 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/parser_st.h @@ -0,0 +1,162 @@ +/* This is a public domain general purpose hash table package + originally written by Peter Moore @ UCB. + + The hash table data structures were redesigned and the package was + rewritten by Vladimir Makarov . */ + +#ifndef RUBY_ST2_H +#define RUBY_ST2_H 1 + +#if defined(__cplusplus) +extern "C" { +#if 0 +} /* satisfy cc-mode */ +#endif +#endif + +#include +#include +#include "ruby/config.h" +#include "ruby/backward/2/long_long.h" +#include "ruby/defines.h" + +RUBY_SYMBOL_EXPORT_BEGIN + +#if SIZEOF_LONG == SIZEOF_VOIDP +typedef unsigned long parser_st_data_t; +#elif SIZEOF_LONG_LONG == SIZEOF_VOIDP +typedef unsigned LONG_LONG parser_st_data_t; +#else +# error ---->> parser_st.c requires sizeof(void*) == sizeof(long) or sizeof(LONG_LONG) to be compiled. <<---- +#endif +#define ST2_DATA_T_DEFINED + +#ifndef CHAR_BIT +# ifdef HAVE_LIMITS_H +# include +# else +# define CHAR_BIT 8 +# endif +#endif +#ifndef _ +# define _(args) args +#endif +#ifndef ANYARGS +# ifdef __cplusplus +# define ANYARGS ... +# else +# define ANYARGS +# endif +#endif + +typedef struct parser_st_table parser_st_table; + +typedef parser_st_data_t parser_st_index_t; + +/* Maximal value of unsigned integer type parser_st_index_t. */ +#define MAX_ST2_INDEX_VAL (~(parser_st_index_t) 0) + +typedef int parser_st_compare_func(parser_st_data_t, parser_st_data_t); +typedef parser_st_index_t parser_st_hash_func(parser_st_data_t); + +typedef char st_check_for_sizeof_parser_st_index_t[SIZEOF_VOIDP == (int)sizeof(parser_st_index_t) ? 1 : -1]; +#define SIZEOF_ST_INDEX_T SIZEOF_VOIDP + +struct parser_st_hash_type { + int (*compare)(parser_st_data_t, parser_st_data_t); /* parser_st_compare_func* */ + parser_st_index_t (*hash)(parser_st_data_t); /* parser_st_hash_func* */ +}; + +#define ST_INDEX_BITS (SIZEOF_ST_INDEX_T * CHAR_BIT) + +#if defined(HAVE_BUILTIN___BUILTIN_CHOOSE_EXPR) && defined(HAVE_BUILTIN___BUILTIN_TYPES_COMPATIBLE_P) +# define ST2_DATA_COMPATIBLE_P(type) \ + __builtin_choose_expr(__builtin_types_compatible_p(type, parser_st_data_t), 1, 0) +#else +# define ST2_DATA_COMPATIBLE_P(type) 0 +#endif + +typedef struct parser_st_table_entry parser_st_table_entry; + +struct parser_st_table_entry; /* defined in parser_st.c */ + +struct parser_st_table { + /* Cached features of the table -- see st.c for more details. */ + unsigned char entry_power, bin_power, size_ind; + /* How many times the table was rebuilt. */ + unsigned int rebuilds_num; + const struct parser_st_hash_type *type; + /* Number of entries currently in the table. */ + parser_st_index_t num_entries; + /* Array of bins used for access by keys. */ + parser_st_index_t *bins; + /* Start and bound index of entries in array entries. + entries_starts and entries_bound are in interval + [0,allocated_entries]. */ + parser_st_index_t entries_start, entries_bound; + /* Array of size 2^entry_power. */ + parser_st_table_entry *entries; +}; + +#define parser_st_is_member(table,key) rb_parser_st_lookup((table),(key),(parser_st_data_t *)0) + +enum parser_st_retval {ST2_CONTINUE, ST2_STOP, ST2_DELETE, ST2_CHECK, ST2_REPLACE}; + +size_t rb_parser_st_table_size(const struct parser_st_table *tbl); +parser_st_table *rb_parser_st_init_table(const struct parser_st_hash_type *); +parser_st_table *rb_parser_st_init_table_with_size(const struct parser_st_hash_type *, parser_st_index_t); +parser_st_table *rb_parser_st_init_existing_table_with_size(parser_st_table *, const struct parser_st_hash_type *, parser_st_index_t); +parser_st_table *rb_parser_st_init_numtable(void); +parser_st_table *rb_parser_st_init_numtable_with_size(parser_st_index_t); +parser_st_table *rb_parser_st_init_strtable(void); +parser_st_table *rb_parser_st_init_strtable_with_size(parser_st_index_t); +parser_st_table *rb_parser_st_init_strcasetable(void); +parser_st_table *rb_parser_st_init_strcasetable_with_size(parser_st_index_t); +int rb_parser_st_delete(parser_st_table *, parser_st_data_t *, parser_st_data_t *); /* returns 0:notfound 1:deleted */ +int rb_parser_st_delete_safe(parser_st_table *, parser_st_data_t *, parser_st_data_t *, parser_st_data_t); +int rb_parser_st_shift(parser_st_table *, parser_st_data_t *, parser_st_data_t *); /* returns 0:notfound 1:deleted */ +int rb_parser_st_insert(parser_st_table *, parser_st_data_t, parser_st_data_t); +int rb_parser_st_insert2(parser_st_table *, parser_st_data_t, parser_st_data_t, parser_st_data_t (*)(parser_st_data_t)); +int rb_parser_st_lookup(parser_st_table *, parser_st_data_t, parser_st_data_t *); +int rb_parser_st_get_key(parser_st_table *, parser_st_data_t, parser_st_data_t *); +typedef int parser_st_update_callback_func(parser_st_data_t *key, parser_st_data_t *value, parser_st_data_t arg, int existing); +/* *key may be altered, but must equal to the old key, i.e., the + * results of hash() are same and compare() returns 0, otherwise the + * behavior is undefined */ +int rb_parser_st_update(parser_st_table *table, parser_st_data_t key, parser_st_update_callback_func *func, parser_st_data_t arg); +typedef int parser_st_foreach_callback_func(parser_st_data_t, parser_st_data_t, parser_st_data_t); +typedef int parser_st_foreach_check_callback_func(parser_st_data_t, parser_st_data_t, parser_st_data_t, int); +int rb_parser_st_foreach_with_replace(parser_st_table *tab, parser_st_foreach_check_callback_func *func, parser_st_update_callback_func *replace, parser_st_data_t arg); +int rb_parser_st_foreach(parser_st_table *, parser_st_foreach_callback_func *, parser_st_data_t); +int rb_parser_st_foreach_check(parser_st_table *, parser_st_foreach_check_callback_func *, parser_st_data_t, parser_st_data_t); +parser_st_index_t rb_parser_st_keys(parser_st_table *table, parser_st_data_t *keys, parser_st_index_t size); +parser_st_index_t rb_parser_st_keys_check(parser_st_table *table, parser_st_data_t *keys, parser_st_index_t size, parser_st_data_t never); +parser_st_index_t rb_parser_st_values(parser_st_table *table, parser_st_data_t *values, parser_st_index_t size); +parser_st_index_t rb_parser_st_values_check(parser_st_table *table, parser_st_data_t *values, parser_st_index_t size, parser_st_data_t never); +void rb_parser_st_add_direct(parser_st_table *, parser_st_data_t, parser_st_data_t); +void rb_parser_st_free_table(parser_st_table *); +void rb_parser_st_cleanup_safe(parser_st_table *, parser_st_data_t); +void rb_parser_st_clear(parser_st_table *); +parser_st_table *rb_parser_st_replace(parser_st_table *, parser_st_table *); +parser_st_table *rb_parser_st_copy(parser_st_table *); +CONSTFUNC(int rb_parser_st_numcmp(parser_st_data_t, parser_st_data_t)); +CONSTFUNC(parser_st_index_t rb_parser_st_numhash(parser_st_data_t)); +PUREFUNC(int rb_parser_st_locale_insensitive_strcasecmp(const char *s1, const char *s2)); +PUREFUNC(int rb_parser_st_locale_insensitive_strncasecmp(const char *s1, const char *s2, size_t n)); +PUREFUNC(size_t rb_parser_st_memsize(const parser_st_table *)); +PUREFUNC(parser_st_index_t rb_parser_st_hash(const void *ptr, size_t len, parser_st_index_t h)); +CONSTFUNC(parser_st_index_t rb_parser_st_hash_uint32(parser_st_index_t h, uint32_t i)); +CONSTFUNC(parser_st_index_t rb_parser_st_hash_uint(parser_st_index_t h, parser_st_index_t i)); +CONSTFUNC(parser_st_index_t rb_parser_st_hash_end(parser_st_index_t h)); +CONSTFUNC(parser_st_index_t rb_parser_st_hash_start(parser_st_index_t h)); + +RUBY_SYMBOL_EXPORT_END + +#if defined(__cplusplus) +#if 0 +{ /* satisfy cc-mode */ +#endif +} /* extern "C" { */ +#endif + +#endif /* RUBY_ST2_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/parser_value.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/parser_value.h new file mode 100644 index 0000000..4fe444e --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/parser_value.h @@ -0,0 +1,106 @@ +#ifndef EXTERNAL_VALUE_H +#define EXTERNAL_VALUE_H + +#include "ruby/config.h" + +#if defined(__DOXYGEN__) + +/** + * Type that represents a Ruby object. It is an unsigned integer of some kind, + * depending on platforms. + * + * ```CXX + * VALUE value = rb_eval_string("ARGF.readlines.map.with_index"); + * ``` + * + * @warning ::VALUE is not a pointer. + * @warning ::VALUE can be wider than `long`. + */ +typedef uintptr_t VALUE; + +/** + * Type that represents a Ruby identifier such as a variable name. + * + * ```CXX + * ID method = rb_intern("method"); + * VALUE result = rb_funcall(obj, method, 0); + * ``` + * + * @note ::rb_cSymbol is a Ruby-level data type for the same thing. + */ +typedef uintptr_t ID; + +/** + * A signed integer type that has the same width with ::VALUE. + * + * @internal + * + * @shyouhei wonders: is it guaranteed that `uintptr_t` and `intptr_t` are the + * same width? As far as I read ISO/IEC 9899:2018 section 7.20.1.4 paragraph 1 + * no such description is given... or defined elsewhere? + */ +typedef intptr_t SIGNED_VALUE; + +/** + * Identical to `sizeof(VALUE)`, except it is a macro that can also be used + * inside of preprocessor directives such as `#if`. Handy on occasions. + */ +#define SIZEOF_VALUE SIZEOF_UINTPTR_T + +/** + * @private + * + * A compile-time constant of type ::VALUE whose value is 0. + */ +#define RBIMPL_VALUE_NULL UINTPTR_C(0) + +/** + * @private + * + * A compile-time constant of type ::VALUE whose value is 1. + */ +#define RBIMPL_VALUE_ONE UINTPTR_C(1) + +/** + * @private + * + * Maximum possible value that a ::VALUE can take. + */ +#define RBIMPL_VALUE_FULL UINTPTR_MAX + +#elif defined HAVE_UINTPTR_T && 0 +typedef uintptr_t VALUE; +typedef uintptr_t ID; +# define SIGNED_VALUE intptr_t +# define SIZEOF_VALUE SIZEOF_UINTPTR_T +# undef PRI_VALUE_PREFIX +# define RBIMPL_VALUE_NULL UINTPTR_C(0) +# define RBIMPL_VALUE_ONE UINTPTR_C(1) +# define RBIMPL_VALUE_FULL UINTPTR_MAX + +#elif SIZEOF_LONG == SIZEOF_VOIDP +typedef unsigned long VALUE; +typedef unsigned long ID; +# define SIGNED_VALUE long +# define SIZEOF_VALUE SIZEOF_LONG +# define PRI_VALUE_PREFIX "l" +# define RBIMPL_VALUE_NULL 0UL +# define RBIMPL_VALUE_ONE 1UL +# define RBIMPL_VALUE_FULL ULONG_MAX + +#elif SIZEOF_LONG_LONG == SIZEOF_VOIDP +typedef unsigned LONG_LONG VALUE; +typedef unsigned LONG_LONG ID; +# define SIGNED_VALUE LONG_LONG +# define LONG_LONG_VALUE 1 +# define SIZEOF_VALUE SIZEOF_LONG_LONG +# define PRI_VALUE_PREFIX PRI_LL_PREFIX +# define RBIMPL_VALUE_NULL 0ULL +# define RBIMPL_VALUE_ONE 1ULL +# define RBIMPL_VALUE_FULL ULLONG_MAX + +#else +# error ---->> ruby requires sizeof(void*) == sizeof(long) or sizeof(LONG_LONG) to be compiled. <<---- +#endif + +#endif /* EXTERNAL_VALUE_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/ast.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/ast.h new file mode 100644 index 0000000..c230131 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/ast.h @@ -0,0 +1,8233 @@ +/* :markup: markdown */ + +/*----------------------------------------------------------------------------*/ +/* This file is generated by the templates/template.rb script and should not */ +/* be modified manually. See */ +/* templates/include/prism/ast.h.erb */ +/* if you are looking to modify the */ +/* template */ +/*----------------------------------------------------------------------------*/ + +/** + * @file ast.h + * + * The abstract syntax tree. + * + * -- + */ +#ifndef PRISM_AST_H +#define PRISM_AST_H + +#include "prism/defines.h" +#include "prism/util/pm_constant_pool.h" +#include "prism/util/pm_integer.h" +#include "prism/util/pm_string.h" + +#include +#include +#include + +/** + * This enum represents every type of token in the Ruby source. + */ +typedef enum pm_token_type { + /** final token in the file */ + PM_TOKEN_EOF = 1, + + /** } */ + PM_TOKEN_BRACE_RIGHT, + + /** , */ + PM_TOKEN_COMMA, + + /** } */ + PM_TOKEN_EMBEXPR_END, + + /** do */ + PM_TOKEN_KEYWORD_DO, + + /** else */ + PM_TOKEN_KEYWORD_ELSE, + + /** elsif */ + PM_TOKEN_KEYWORD_ELSIF, + + /** end */ + PM_TOKEN_KEYWORD_END, + + /** ensure */ + PM_TOKEN_KEYWORD_ENSURE, + + /** in */ + PM_TOKEN_KEYWORD_IN, + + /** rescue */ + PM_TOKEN_KEYWORD_RESCUE, + + /** then */ + PM_TOKEN_KEYWORD_THEN, + + /** when */ + PM_TOKEN_KEYWORD_WHEN, + + /** a newline character outside of other tokens */ + PM_TOKEN_NEWLINE, + + /** ) */ + PM_TOKEN_PARENTHESIS_RIGHT, + + /** | */ + PM_TOKEN_PIPE, + + /** ; */ + PM_TOKEN_SEMICOLON, + + /** & */ + PM_TOKEN_AMPERSAND, + + /** && */ + PM_TOKEN_AMPERSAND_AMPERSAND, + + /** &&= */ + PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL, + + /** &. */ + PM_TOKEN_AMPERSAND_DOT, + + /** &= */ + PM_TOKEN_AMPERSAND_EQUAL, + + /** ` */ + PM_TOKEN_BACKTICK, + + /** a back reference */ + PM_TOKEN_BACK_REFERENCE, + + /** ! or !@ */ + PM_TOKEN_BANG, + + /** != */ + PM_TOKEN_BANG_EQUAL, + + /** !~ */ + PM_TOKEN_BANG_TILDE, + + /** { */ + PM_TOKEN_BRACE_LEFT, + + /** [ */ + PM_TOKEN_BRACKET_LEFT, + + /** [ for the beginning of an array */ + PM_TOKEN_BRACKET_LEFT_ARRAY, + + /** [] */ + PM_TOKEN_BRACKET_LEFT_RIGHT, + + /** []= */ + PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL, + + /** ] */ + PM_TOKEN_BRACKET_RIGHT, + + /** ^ */ + PM_TOKEN_CARET, + + /** ^= */ + PM_TOKEN_CARET_EQUAL, + + /** a character literal */ + PM_TOKEN_CHARACTER_LITERAL, + + /** a class variable */ + PM_TOKEN_CLASS_VARIABLE, + + /** : */ + PM_TOKEN_COLON, + + /** :: */ + PM_TOKEN_COLON_COLON, + + /** a comment */ + PM_TOKEN_COMMENT, + + /** a constant */ + PM_TOKEN_CONSTANT, + + /** the . call operator */ + PM_TOKEN_DOT, + + /** the .. range operator */ + PM_TOKEN_DOT_DOT, + + /** the ... range operator or forwarding parameter */ + PM_TOKEN_DOT_DOT_DOT, + + /** =begin */ + PM_TOKEN_EMBDOC_BEGIN, + + /** =end */ + PM_TOKEN_EMBDOC_END, + + /** a line inside of embedded documentation */ + PM_TOKEN_EMBDOC_LINE, + + /** #{ */ + PM_TOKEN_EMBEXPR_BEGIN, + + /** # */ + PM_TOKEN_EMBVAR, + + /** = */ + PM_TOKEN_EQUAL, + + /** == */ + PM_TOKEN_EQUAL_EQUAL, + + /** === */ + PM_TOKEN_EQUAL_EQUAL_EQUAL, + + /** => */ + PM_TOKEN_EQUAL_GREATER, + + /** =~ */ + PM_TOKEN_EQUAL_TILDE, + + /** a floating point number */ + PM_TOKEN_FLOAT, + + /** a floating pointer number with an imaginary suffix */ + PM_TOKEN_FLOAT_IMAGINARY, + + /** a floating pointer number with a rational suffix */ + PM_TOKEN_FLOAT_RATIONAL, + + /** a floating pointer number with a rational and imaginary suffix */ + PM_TOKEN_FLOAT_RATIONAL_IMAGINARY, + + /** a global variable */ + PM_TOKEN_GLOBAL_VARIABLE, + + /** > */ + PM_TOKEN_GREATER, + + /** >= */ + PM_TOKEN_GREATER_EQUAL, + + /** >> */ + PM_TOKEN_GREATER_GREATER, + + /** >>= */ + PM_TOKEN_GREATER_GREATER_EQUAL, + + /** the end of a heredoc */ + PM_TOKEN_HEREDOC_END, + + /** the start of a heredoc */ + PM_TOKEN_HEREDOC_START, + + /** an identifier */ + PM_TOKEN_IDENTIFIER, + + /** an ignored newline */ + PM_TOKEN_IGNORED_NEWLINE, + + /** an instance variable */ + PM_TOKEN_INSTANCE_VARIABLE, + + /** an integer (any base) */ + PM_TOKEN_INTEGER, + + /** an integer with an imaginary suffix */ + PM_TOKEN_INTEGER_IMAGINARY, + + /** an integer with a rational suffix */ + PM_TOKEN_INTEGER_RATIONAL, + + /** an integer with a rational and imaginary suffix */ + PM_TOKEN_INTEGER_RATIONAL_IMAGINARY, + + /** alias */ + PM_TOKEN_KEYWORD_ALIAS, + + /** and */ + PM_TOKEN_KEYWORD_AND, + + /** begin */ + PM_TOKEN_KEYWORD_BEGIN, + + /** BEGIN */ + PM_TOKEN_KEYWORD_BEGIN_UPCASE, + + /** break */ + PM_TOKEN_KEYWORD_BREAK, + + /** case */ + PM_TOKEN_KEYWORD_CASE, + + /** class */ + PM_TOKEN_KEYWORD_CLASS, + + /** def */ + PM_TOKEN_KEYWORD_DEF, + + /** defined? */ + PM_TOKEN_KEYWORD_DEFINED, + + /** do keyword for a predicate in a while, until, or for loop */ + PM_TOKEN_KEYWORD_DO_LOOP, + + /** END */ + PM_TOKEN_KEYWORD_END_UPCASE, + + /** false */ + PM_TOKEN_KEYWORD_FALSE, + + /** for */ + PM_TOKEN_KEYWORD_FOR, + + /** if */ + PM_TOKEN_KEYWORD_IF, + + /** if in the modifier form */ + PM_TOKEN_KEYWORD_IF_MODIFIER, + + /** module */ + PM_TOKEN_KEYWORD_MODULE, + + /** next */ + PM_TOKEN_KEYWORD_NEXT, + + /** nil */ + PM_TOKEN_KEYWORD_NIL, + + /** not */ + PM_TOKEN_KEYWORD_NOT, + + /** or */ + PM_TOKEN_KEYWORD_OR, + + /** redo */ + PM_TOKEN_KEYWORD_REDO, + + /** rescue in the modifier form */ + PM_TOKEN_KEYWORD_RESCUE_MODIFIER, + + /** retry */ + PM_TOKEN_KEYWORD_RETRY, + + /** return */ + PM_TOKEN_KEYWORD_RETURN, + + /** self */ + PM_TOKEN_KEYWORD_SELF, + + /** super */ + PM_TOKEN_KEYWORD_SUPER, + + /** true */ + PM_TOKEN_KEYWORD_TRUE, + + /** undef */ + PM_TOKEN_KEYWORD_UNDEF, + + /** unless */ + PM_TOKEN_KEYWORD_UNLESS, + + /** unless in the modifier form */ + PM_TOKEN_KEYWORD_UNLESS_MODIFIER, + + /** until */ + PM_TOKEN_KEYWORD_UNTIL, + + /** until in the modifier form */ + PM_TOKEN_KEYWORD_UNTIL_MODIFIER, + + /** while */ + PM_TOKEN_KEYWORD_WHILE, + + /** while in the modifier form */ + PM_TOKEN_KEYWORD_WHILE_MODIFIER, + + /** yield */ + PM_TOKEN_KEYWORD_YIELD, + + /** __ENCODING__ */ + PM_TOKEN_KEYWORD___ENCODING__, + + /** __FILE__ */ + PM_TOKEN_KEYWORD___FILE__, + + /** __LINE__ */ + PM_TOKEN_KEYWORD___LINE__, + + /** a label */ + PM_TOKEN_LABEL, + + /** the end of a label */ + PM_TOKEN_LABEL_END, + + /** { */ + PM_TOKEN_LAMBDA_BEGIN, + + /** < */ + PM_TOKEN_LESS, + + /** <= */ + PM_TOKEN_LESS_EQUAL, + + /** <=> */ + PM_TOKEN_LESS_EQUAL_GREATER, + + /** << */ + PM_TOKEN_LESS_LESS, + + /** <<= */ + PM_TOKEN_LESS_LESS_EQUAL, + + /** a method name */ + PM_TOKEN_METHOD_NAME, + + /** - */ + PM_TOKEN_MINUS, + + /** -= */ + PM_TOKEN_MINUS_EQUAL, + + /** -> */ + PM_TOKEN_MINUS_GREATER, + + /** a numbered reference to a capture group in the previous regular expression match */ + PM_TOKEN_NUMBERED_REFERENCE, + + /** ( */ + PM_TOKEN_PARENTHESIS_LEFT, + + /** ( for a parentheses node */ + PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES, + + /** % */ + PM_TOKEN_PERCENT, + + /** %= */ + PM_TOKEN_PERCENT_EQUAL, + + /** %i */ + PM_TOKEN_PERCENT_LOWER_I, + + /** %w */ + PM_TOKEN_PERCENT_LOWER_W, + + /** %x */ + PM_TOKEN_PERCENT_LOWER_X, + + /** %I */ + PM_TOKEN_PERCENT_UPPER_I, + + /** %W */ + PM_TOKEN_PERCENT_UPPER_W, + + /** |= */ + PM_TOKEN_PIPE_EQUAL, + + /** || */ + PM_TOKEN_PIPE_PIPE, + + /** ||= */ + PM_TOKEN_PIPE_PIPE_EQUAL, + + /** + */ + PM_TOKEN_PLUS, + + /** += */ + PM_TOKEN_PLUS_EQUAL, + + /** ? */ + PM_TOKEN_QUESTION_MARK, + + /** the beginning of a regular expression */ + PM_TOKEN_REGEXP_BEGIN, + + /** the end of a regular expression */ + PM_TOKEN_REGEXP_END, + + /** / */ + PM_TOKEN_SLASH, + + /** /= */ + PM_TOKEN_SLASH_EQUAL, + + /** * */ + PM_TOKEN_STAR, + + /** *= */ + PM_TOKEN_STAR_EQUAL, + + /** ** */ + PM_TOKEN_STAR_STAR, + + /** **= */ + PM_TOKEN_STAR_STAR_EQUAL, + + /** the beginning of a string */ + PM_TOKEN_STRING_BEGIN, + + /** the contents of a string */ + PM_TOKEN_STRING_CONTENT, + + /** the end of a string */ + PM_TOKEN_STRING_END, + + /** the beginning of a symbol */ + PM_TOKEN_SYMBOL_BEGIN, + + /** ~ or ~@ */ + PM_TOKEN_TILDE, + + /** unary & */ + PM_TOKEN_UAMPERSAND, + + /** unary :: */ + PM_TOKEN_UCOLON_COLON, + + /** unary .. operator */ + PM_TOKEN_UDOT_DOT, + + /** unary ... operator */ + PM_TOKEN_UDOT_DOT_DOT, + + /** -@ */ + PM_TOKEN_UMINUS, + + /** -@ for a number */ + PM_TOKEN_UMINUS_NUM, + + /** +@ */ + PM_TOKEN_UPLUS, + + /** unary * */ + PM_TOKEN_USTAR, + + /** unary ** */ + PM_TOKEN_USTAR_STAR, + + /** a separator between words in a list */ + PM_TOKEN_WORDS_SEP, + + /** marker for the point in the file at which the parser should stop */ + PM_TOKEN___END__, + + /** a token that was expected but not found */ + PM_TOKEN_MISSING, + + /** a token that was not present but it is okay */ + PM_TOKEN_NOT_PROVIDED, + + /** The maximum token value. */ + PM_TOKEN_MAXIMUM, +} pm_token_type_t; + +/** + * This struct represents a token in the Ruby source. We use it to track both + * type and location information. + */ +typedef struct { + /** The type of the token. */ + pm_token_type_t type; + + /** A pointer to the start location of the token in the source. */ + const uint8_t *start; + + /** A pointer to the end location of the token in the source. */ + const uint8_t *end; +} pm_token_t; + +/** + * This represents a range of bytes in the source string to which a node or + * token corresponds. + */ +typedef struct { + /** A pointer to the start location of the range in the source. */ + const uint8_t *start; + + /** A pointer to the end location of the range in the source. */ + const uint8_t *end; +} pm_location_t; + +struct pm_node; + +/** + * A list of nodes in the source, most often used for lists of children. + */ +typedef struct pm_node_list { + /** The number of nodes in the list. */ + size_t size; + + /** The capacity of the list that has been allocated. */ + size_t capacity; + + /** The nodes in the list. */ + struct pm_node **nodes; +} pm_node_list_t; + +/** + * This enum represents every type of node in the Ruby syntax tree. + */ +enum pm_node_type { + /** AliasGlobalVariableNode */ + PM_ALIAS_GLOBAL_VARIABLE_NODE = 1, + + /** AliasMethodNode */ + PM_ALIAS_METHOD_NODE = 2, + + /** AlternationPatternNode */ + PM_ALTERNATION_PATTERN_NODE = 3, + + /** AndNode */ + PM_AND_NODE = 4, + + /** ArgumentsNode */ + PM_ARGUMENTS_NODE = 5, + + /** ArrayNode */ + PM_ARRAY_NODE = 6, + + /** ArrayPatternNode */ + PM_ARRAY_PATTERN_NODE = 7, + + /** AssocNode */ + PM_ASSOC_NODE = 8, + + /** AssocSplatNode */ + PM_ASSOC_SPLAT_NODE = 9, + + /** BackReferenceReadNode */ + PM_BACK_REFERENCE_READ_NODE = 10, + + /** BeginNode */ + PM_BEGIN_NODE = 11, + + /** BlockArgumentNode */ + PM_BLOCK_ARGUMENT_NODE = 12, + + /** BlockLocalVariableNode */ + PM_BLOCK_LOCAL_VARIABLE_NODE = 13, + + /** BlockNode */ + PM_BLOCK_NODE = 14, + + /** BlockParameterNode */ + PM_BLOCK_PARAMETER_NODE = 15, + + /** BlockParametersNode */ + PM_BLOCK_PARAMETERS_NODE = 16, + + /** BreakNode */ + PM_BREAK_NODE = 17, + + /** CallAndWriteNode */ + PM_CALL_AND_WRITE_NODE = 18, + + /** CallNode */ + PM_CALL_NODE = 19, + + /** CallOperatorWriteNode */ + PM_CALL_OPERATOR_WRITE_NODE = 20, + + /** CallOrWriteNode */ + PM_CALL_OR_WRITE_NODE = 21, + + /** CallTargetNode */ + PM_CALL_TARGET_NODE = 22, + + /** CapturePatternNode */ + PM_CAPTURE_PATTERN_NODE = 23, + + /** CaseMatchNode */ + PM_CASE_MATCH_NODE = 24, + + /** CaseNode */ + PM_CASE_NODE = 25, + + /** ClassNode */ + PM_CLASS_NODE = 26, + + /** ClassVariableAndWriteNode */ + PM_CLASS_VARIABLE_AND_WRITE_NODE = 27, + + /** ClassVariableOperatorWriteNode */ + PM_CLASS_VARIABLE_OPERATOR_WRITE_NODE = 28, + + /** ClassVariableOrWriteNode */ + PM_CLASS_VARIABLE_OR_WRITE_NODE = 29, + + /** ClassVariableReadNode */ + PM_CLASS_VARIABLE_READ_NODE = 30, + + /** ClassVariableTargetNode */ + PM_CLASS_VARIABLE_TARGET_NODE = 31, + + /** ClassVariableWriteNode */ + PM_CLASS_VARIABLE_WRITE_NODE = 32, + + /** ConstantAndWriteNode */ + PM_CONSTANT_AND_WRITE_NODE = 33, + + /** ConstantOperatorWriteNode */ + PM_CONSTANT_OPERATOR_WRITE_NODE = 34, + + /** ConstantOrWriteNode */ + PM_CONSTANT_OR_WRITE_NODE = 35, + + /** ConstantPathAndWriteNode */ + PM_CONSTANT_PATH_AND_WRITE_NODE = 36, + + /** ConstantPathNode */ + PM_CONSTANT_PATH_NODE = 37, + + /** ConstantPathOperatorWriteNode */ + PM_CONSTANT_PATH_OPERATOR_WRITE_NODE = 38, + + /** ConstantPathOrWriteNode */ + PM_CONSTANT_PATH_OR_WRITE_NODE = 39, + + /** ConstantPathTargetNode */ + PM_CONSTANT_PATH_TARGET_NODE = 40, + + /** ConstantPathWriteNode */ + PM_CONSTANT_PATH_WRITE_NODE = 41, + + /** ConstantReadNode */ + PM_CONSTANT_READ_NODE = 42, + + /** ConstantTargetNode */ + PM_CONSTANT_TARGET_NODE = 43, + + /** ConstantWriteNode */ + PM_CONSTANT_WRITE_NODE = 44, + + /** DefNode */ + PM_DEF_NODE = 45, + + /** DefinedNode */ + PM_DEFINED_NODE = 46, + + /** ElseNode */ + PM_ELSE_NODE = 47, + + /** EmbeddedStatementsNode */ + PM_EMBEDDED_STATEMENTS_NODE = 48, + + /** EmbeddedVariableNode */ + PM_EMBEDDED_VARIABLE_NODE = 49, + + /** EnsureNode */ + PM_ENSURE_NODE = 50, + + /** FalseNode */ + PM_FALSE_NODE = 51, + + /** FindPatternNode */ + PM_FIND_PATTERN_NODE = 52, + + /** FlipFlopNode */ + PM_FLIP_FLOP_NODE = 53, + + /** FloatNode */ + PM_FLOAT_NODE = 54, + + /** ForNode */ + PM_FOR_NODE = 55, + + /** ForwardingArgumentsNode */ + PM_FORWARDING_ARGUMENTS_NODE = 56, + + /** ForwardingParameterNode */ + PM_FORWARDING_PARAMETER_NODE = 57, + + /** ForwardingSuperNode */ + PM_FORWARDING_SUPER_NODE = 58, + + /** GlobalVariableAndWriteNode */ + PM_GLOBAL_VARIABLE_AND_WRITE_NODE = 59, + + /** GlobalVariableOperatorWriteNode */ + PM_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE = 60, + + /** GlobalVariableOrWriteNode */ + PM_GLOBAL_VARIABLE_OR_WRITE_NODE = 61, + + /** GlobalVariableReadNode */ + PM_GLOBAL_VARIABLE_READ_NODE = 62, + + /** GlobalVariableTargetNode */ + PM_GLOBAL_VARIABLE_TARGET_NODE = 63, + + /** GlobalVariableWriteNode */ + PM_GLOBAL_VARIABLE_WRITE_NODE = 64, + + /** HashNode */ + PM_HASH_NODE = 65, + + /** HashPatternNode */ + PM_HASH_PATTERN_NODE = 66, + + /** IfNode */ + PM_IF_NODE = 67, + + /** ImaginaryNode */ + PM_IMAGINARY_NODE = 68, + + /** ImplicitNode */ + PM_IMPLICIT_NODE = 69, + + /** ImplicitRestNode */ + PM_IMPLICIT_REST_NODE = 70, + + /** InNode */ + PM_IN_NODE = 71, + + /** IndexAndWriteNode */ + PM_INDEX_AND_WRITE_NODE = 72, + + /** IndexOperatorWriteNode */ + PM_INDEX_OPERATOR_WRITE_NODE = 73, + + /** IndexOrWriteNode */ + PM_INDEX_OR_WRITE_NODE = 74, + + /** IndexTargetNode */ + PM_INDEX_TARGET_NODE = 75, + + /** InstanceVariableAndWriteNode */ + PM_INSTANCE_VARIABLE_AND_WRITE_NODE = 76, + + /** InstanceVariableOperatorWriteNode */ + PM_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE = 77, + + /** InstanceVariableOrWriteNode */ + PM_INSTANCE_VARIABLE_OR_WRITE_NODE = 78, + + /** InstanceVariableReadNode */ + PM_INSTANCE_VARIABLE_READ_NODE = 79, + + /** InstanceVariableTargetNode */ + PM_INSTANCE_VARIABLE_TARGET_NODE = 80, + + /** InstanceVariableWriteNode */ + PM_INSTANCE_VARIABLE_WRITE_NODE = 81, + + /** IntegerNode */ + PM_INTEGER_NODE = 82, + + /** InterpolatedMatchLastLineNode */ + PM_INTERPOLATED_MATCH_LAST_LINE_NODE = 83, + + /** InterpolatedRegularExpressionNode */ + PM_INTERPOLATED_REGULAR_EXPRESSION_NODE = 84, + + /** InterpolatedStringNode */ + PM_INTERPOLATED_STRING_NODE = 85, + + /** InterpolatedSymbolNode */ + PM_INTERPOLATED_SYMBOL_NODE = 86, + + /** InterpolatedXStringNode */ + PM_INTERPOLATED_X_STRING_NODE = 87, + + /** ItLocalVariableReadNode */ + PM_IT_LOCAL_VARIABLE_READ_NODE = 88, + + /** ItParametersNode */ + PM_IT_PARAMETERS_NODE = 89, + + /** KeywordHashNode */ + PM_KEYWORD_HASH_NODE = 90, + + /** KeywordRestParameterNode */ + PM_KEYWORD_REST_PARAMETER_NODE = 91, + + /** LambdaNode */ + PM_LAMBDA_NODE = 92, + + /** LocalVariableAndWriteNode */ + PM_LOCAL_VARIABLE_AND_WRITE_NODE = 93, + + /** LocalVariableOperatorWriteNode */ + PM_LOCAL_VARIABLE_OPERATOR_WRITE_NODE = 94, + + /** LocalVariableOrWriteNode */ + PM_LOCAL_VARIABLE_OR_WRITE_NODE = 95, + + /** LocalVariableReadNode */ + PM_LOCAL_VARIABLE_READ_NODE = 96, + + /** LocalVariableTargetNode */ + PM_LOCAL_VARIABLE_TARGET_NODE = 97, + + /** LocalVariableWriteNode */ + PM_LOCAL_VARIABLE_WRITE_NODE = 98, + + /** MatchLastLineNode */ + PM_MATCH_LAST_LINE_NODE = 99, + + /** MatchPredicateNode */ + PM_MATCH_PREDICATE_NODE = 100, + + /** MatchRequiredNode */ + PM_MATCH_REQUIRED_NODE = 101, + + /** MatchWriteNode */ + PM_MATCH_WRITE_NODE = 102, + + /** MissingNode */ + PM_MISSING_NODE = 103, + + /** ModuleNode */ + PM_MODULE_NODE = 104, + + /** MultiTargetNode */ + PM_MULTI_TARGET_NODE = 105, + + /** MultiWriteNode */ + PM_MULTI_WRITE_NODE = 106, + + /** NextNode */ + PM_NEXT_NODE = 107, + + /** NilNode */ + PM_NIL_NODE = 108, + + /** NoKeywordsParameterNode */ + PM_NO_KEYWORDS_PARAMETER_NODE = 109, + + /** NumberedParametersNode */ + PM_NUMBERED_PARAMETERS_NODE = 110, + + /** NumberedReferenceReadNode */ + PM_NUMBERED_REFERENCE_READ_NODE = 111, + + /** OptionalKeywordParameterNode */ + PM_OPTIONAL_KEYWORD_PARAMETER_NODE = 112, + + /** OptionalParameterNode */ + PM_OPTIONAL_PARAMETER_NODE = 113, + + /** OrNode */ + PM_OR_NODE = 114, + + /** ParametersNode */ + PM_PARAMETERS_NODE = 115, + + /** ParenthesesNode */ + PM_PARENTHESES_NODE = 116, + + /** PinnedExpressionNode */ + PM_PINNED_EXPRESSION_NODE = 117, + + /** PinnedVariableNode */ + PM_PINNED_VARIABLE_NODE = 118, + + /** PostExecutionNode */ + PM_POST_EXECUTION_NODE = 119, + + /** PreExecutionNode */ + PM_PRE_EXECUTION_NODE = 120, + + /** ProgramNode */ + PM_PROGRAM_NODE = 121, + + /** RangeNode */ + PM_RANGE_NODE = 122, + + /** RationalNode */ + PM_RATIONAL_NODE = 123, + + /** RedoNode */ + PM_REDO_NODE = 124, + + /** RegularExpressionNode */ + PM_REGULAR_EXPRESSION_NODE = 125, + + /** RequiredKeywordParameterNode */ + PM_REQUIRED_KEYWORD_PARAMETER_NODE = 126, + + /** RequiredParameterNode */ + PM_REQUIRED_PARAMETER_NODE = 127, + + /** RescueModifierNode */ + PM_RESCUE_MODIFIER_NODE = 128, + + /** RescueNode */ + PM_RESCUE_NODE = 129, + + /** RestParameterNode */ + PM_REST_PARAMETER_NODE = 130, + + /** RetryNode */ + PM_RETRY_NODE = 131, + + /** ReturnNode */ + PM_RETURN_NODE = 132, + + /** SelfNode */ + PM_SELF_NODE = 133, + + /** ShareableConstantNode */ + PM_SHAREABLE_CONSTANT_NODE = 134, + + /** SingletonClassNode */ + PM_SINGLETON_CLASS_NODE = 135, + + /** SourceEncodingNode */ + PM_SOURCE_ENCODING_NODE = 136, + + /** SourceFileNode */ + PM_SOURCE_FILE_NODE = 137, + + /** SourceLineNode */ + PM_SOURCE_LINE_NODE = 138, + + /** SplatNode */ + PM_SPLAT_NODE = 139, + + /** StatementsNode */ + PM_STATEMENTS_NODE = 140, + + /** StringNode */ + PM_STRING_NODE = 141, + + /** SuperNode */ + PM_SUPER_NODE = 142, + + /** SymbolNode */ + PM_SYMBOL_NODE = 143, + + /** TrueNode */ + PM_TRUE_NODE = 144, + + /** UndefNode */ + PM_UNDEF_NODE = 145, + + /** UnlessNode */ + PM_UNLESS_NODE = 146, + + /** UntilNode */ + PM_UNTIL_NODE = 147, + + /** WhenNode */ + PM_WHEN_NODE = 148, + + /** WhileNode */ + PM_WHILE_NODE = 149, + + /** XStringNode */ + PM_X_STRING_NODE = 150, + + /** YieldNode */ + PM_YIELD_NODE = 151, + + /** A special kind of node used for compilation. */ + PM_SCOPE_NODE +}; + +/** + * This is the type of node embedded in the node struct. We explicitly control + * the size of it here to avoid having the variable-width enum. + */ +typedef uint16_t pm_node_type_t; + +/** + * These are the flags embedded in the node struct. We explicitly control the + * size of it here to avoid having the variable-width enum. + */ +typedef uint16_t pm_node_flags_t; + +/** + * We store the flags enum in every node in the tree. Some flags are common to + * all nodes (the ones listed below). Others are specific to certain node types. + */ +static const pm_node_flags_t PM_NODE_FLAG_NEWLINE = 0x1; +static const pm_node_flags_t PM_NODE_FLAG_STATIC_LITERAL = 0x2; + +/** + * Cast the type to an enum to allow the compiler to provide exhaustiveness + * checking. + */ +#define PM_NODE_TYPE(node) ((enum pm_node_type) (node)->type) + +/** + * Return true if the type of the given node matches the given type. + */ +#define PM_NODE_TYPE_P(node, type) (PM_NODE_TYPE(node) == (type)) + +/** + * Return true if the given flag is set on the given node. + */ +#define PM_NODE_FLAG_P(node, flag) ((((pm_node_t *)(node))->flags & (flag)) != 0) + +/** + * This is the base structure that represents a node in the syntax tree. It is + * embedded into every node type. + */ +typedef struct pm_node { + /** + * This represents the type of the node. It somewhat maps to the nodes that + * existed in the original grammar and ripper, but it's not a 1:1 mapping. + */ + pm_node_type_t type; + + /** + * This represents any flags on the node. Some are common to all nodes, and + * some are specific to the type of node. + */ + pm_node_flags_t flags; + + /** + * The unique identifier for this node, which is deterministic based on the + * source. It is used to identify unique nodes across parses. + */ + uint32_t node_id; + + /** + * This is the location of the node in the source. It's a range of bytes + * containing a start and an end. + */ + pm_location_t location; +} pm_node_t; + +/** + * AliasGlobalVariableNode + * + * Represents the use of the `alias` keyword to alias a global variable. + * + * alias $foo $bar + * ^^^^^^^^^^^^^^^ + * + * Type: ::PM_ALIAS_GLOBAL_VARIABLE_NODE + * + * @extends pm_node_t + */ +typedef struct pm_alias_global_variable_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * AliasGlobalVariableNode#new_name + * + * Represents the new name of the global variable that can be used after aliasing. + * + * alias $foo $bar + * ^^^^ + */ + struct pm_node *new_name; + + /** + * AliasGlobalVariableNode#old_name + * + * Represents the old name of the global variable that can be used before aliasing. + * + * alias $foo $bar + * ^^^^ + */ + struct pm_node *old_name; + + /** + * AliasGlobalVariableNode#keyword_loc + * + * The location of the `alias` keyword. + * + * alias $foo $bar + * ^^^^^ + */ + pm_location_t keyword_loc; +} pm_alias_global_variable_node_t; + +/** + * AliasMethodNode + * + * Represents the use of the `alias` keyword to alias a method. + * + * alias foo bar + * ^^^^^^^^^^^^^ + * + * Type: ::PM_ALIAS_METHOD_NODE + * + * @extends pm_node_t + */ +typedef struct pm_alias_method_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * AliasMethodNode#new_name + * + * Represents the new name of the method that will be aliased. + * + * alias foo bar + * ^^^ + * + * alias :foo :bar + * ^^^^ + * + * alias :"#{foo}" :"#{bar}" + * ^^^^^^^^^ + */ + struct pm_node *new_name; + + /** + * AliasMethodNode#old_name + * + * Represents the old name of the method that will be aliased. + * + * alias foo bar + * ^^^ + * + * alias :foo :bar + * ^^^^ + * + * alias :"#{foo}" :"#{bar}" + * ^^^^^^^^^ + */ + struct pm_node *old_name; + + /** + * AliasMethodNode#keyword_loc + * + * Represents the location of the `alias` keyword. + * + * alias foo bar + * ^^^^^ + */ + pm_location_t keyword_loc; +} pm_alias_method_node_t; + +/** + * AlternationPatternNode + * + * Represents an alternation pattern in pattern matching. + * + * foo => bar | baz + * ^^^^^^^^^ + * + * Type: ::PM_ALTERNATION_PATTERN_NODE + * + * @extends pm_node_t + */ +typedef struct pm_alternation_pattern_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * AlternationPatternNode#left + * + * Represents the left side of the expression. + * + * foo => bar | baz + * ^^^ + */ + struct pm_node *left; + + /** + * AlternationPatternNode#right + * + * Represents the right side of the expression. + * + * foo => bar | baz + * ^^^ + */ + struct pm_node *right; + + /** + * AlternationPatternNode#operator_loc + * + * Represents the alternation operator location. + * + * foo => bar | baz + * ^ + */ + pm_location_t operator_loc; +} pm_alternation_pattern_node_t; + +/** + * AndNode + * + * Represents the use of the `&&` operator or the `and` keyword. + * + * left and right + * ^^^^^^^^^^^^^^ + * + * Type: ::PM_AND_NODE + * + * @extends pm_node_t + */ +typedef struct pm_and_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * AndNode#left + * + * Represents the left side of the expression. It can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression). + * + * left and right + * ^^^^ + * + * 1 && 2 + * ^ + */ + struct pm_node *left; + + /** + * AndNode#right + * + * Represents the right side of the expression. + * + * left && right + * ^^^^^ + * + * 1 and 2 + * ^ + */ + struct pm_node *right; + + /** + * AndNode#operator_loc + * + * The location of the `and` keyword or the `&&` operator. + * + * left and right + * ^^^ + */ + pm_location_t operator_loc; +} pm_and_node_t; + +/** + * ArgumentsNode + * + * Represents a set of arguments to a method or a keyword. + * + * return foo, bar, baz + * ^^^^^^^^^^^^^ + * + * Type: ::PM_ARGUMENTS_NODE + + * Flags (#pm_arguments_node_flags): + * * ::PM_ARGUMENTS_NODE_FLAGS_CONTAINS_FORWARDING + * * ::PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS + * * ::PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT + * * ::PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT + * * ::PM_ARGUMENTS_NODE_FLAGS_CONTAINS_MULTIPLE_SPLATS + * + * @extends pm_node_t + */ +typedef struct pm_arguments_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * ArgumentsNode#arguments + * + * The list of arguments, if present. These can be any [non-void expressions](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression). + * + * foo(bar, baz) + * ^^^^^^^^ + */ + struct pm_node_list arguments; +} pm_arguments_node_t; + +/** + * ArrayNode + * + * Represents an array literal. This can be a regular array using brackets or a special array using % like %w or %i. + * + * [1, 2, 3] + * ^^^^^^^^^ + * + * Type: ::PM_ARRAY_NODE + + * Flags (#pm_array_node_flags): + * * ::PM_ARRAY_NODE_FLAGS_CONTAINS_SPLAT + * + * @extends pm_node_t + */ +typedef struct pm_array_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * ArrayNode#elements + * + * Represent the list of zero or more [non-void expressions](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression) within the array. + */ + struct pm_node_list elements; + + /** + * ArrayNode#opening_loc + * + * Represents the optional source location for the opening token. + * + * [1,2,3] # "[" + * %w[foo bar baz] # "%w[" + * %I(apple orange banana) # "%I(" + * foo = 1, 2, 3 # nil + */ + pm_location_t opening_loc; + + /** + * ArrayNode#closing_loc + * + * Represents the optional source location for the closing token. + * + * [1,2,3] # "]" + * %w[foo bar baz] # "]" + * %I(apple orange banana) # ")" + * foo = 1, 2, 3 # nil + */ + pm_location_t closing_loc; +} pm_array_node_t; + +/** + * ArrayPatternNode + * + * Represents an array pattern in pattern matching. + * + * foo in 1, 2 + * ^^^^^^^^^^^ + * + * foo in [1, 2] + * ^^^^^^^^^^^^^ + * + * foo in *bar + * ^^^^^^^^^^^ + * + * foo in Bar[] + * ^^^^^^^^^^^^ + * + * foo in Bar[1, 2, 3] + * ^^^^^^^^^^^^^^^^^^^ + * + * Type: ::PM_ARRAY_PATTERN_NODE + * + * @extends pm_node_t + */ +typedef struct pm_array_pattern_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * ArrayPatternNode#constant + * + * Represents the optional constant preceding the Array + * + * foo in Bar[] + * ^^^ + * + * foo in Bar[1, 2, 3] + * ^^^ + * + * foo in Bar::Baz[1, 2, 3] + * ^^^^^^^^ + */ + struct pm_node *constant; + + /** + * ArrayPatternNode#requireds + * + * Represents the required elements of the array pattern. + * + * foo in [1, 2] + * ^ ^ + */ + struct pm_node_list requireds; + + /** + * ArrayPatternNode#rest + * + * Represents the rest element of the array pattern. + * + * foo in *bar + * ^^^^ + */ + struct pm_node *rest; + + /** + * ArrayPatternNode#posts + * + * Represents the elements after the rest element of the array pattern. + * + * foo in *bar, baz + * ^^^ + */ + struct pm_node_list posts; + + /** + * ArrayPatternNode#opening_loc + * + * Represents the opening location of the array pattern. + * + * foo in [1, 2] + * ^ + */ + pm_location_t opening_loc; + + /** + * ArrayPatternNode#closing_loc + * + * Represents the closing location of the array pattern. + * + * foo in [1, 2] + * ^ + */ + pm_location_t closing_loc; +} pm_array_pattern_node_t; + +/** + * AssocNode + * + * Represents a hash key/value pair. + * + * { a => b } + * ^^^^^^ + * + * Type: ::PM_ASSOC_NODE + * + * @extends pm_node_t + */ +typedef struct pm_assoc_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * AssocNode#key + * + * The key of the association. This can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression). + * + * { a: b } + * ^ + * + * { foo => bar } + * ^^^ + * + * { def a; end => 1 } + * ^^^^^^^^^^ + */ + struct pm_node *key; + + /** + * AssocNode#value + * + * The value of the association, if present. This can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression). + * + * { foo => bar } + * ^^^ + * + * { x: 1 } + * ^ + */ + struct pm_node *value; + + /** + * AssocNode#operator_loc + * + * The location of the `=>` operator, if present. + * + * { foo => bar } + * ^^ + */ + pm_location_t operator_loc; +} pm_assoc_node_t; + +/** + * AssocSplatNode + * + * Represents a splat in a hash literal. + * + * { **foo } + * ^^^^^ + * + * Type: ::PM_ASSOC_SPLAT_NODE + * + * @extends pm_node_t + */ +typedef struct pm_assoc_splat_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * AssocSplatNode#value + * + * The value to be splatted, if present. Will be missing when keyword rest argument forwarding is used. + * + * { **foo } + * ^^^ + */ + struct pm_node *value; + + /** + * AssocSplatNode#operator_loc + * + * The location of the `**` operator. + * + * { **x } + * ^^ + */ + pm_location_t operator_loc; +} pm_assoc_splat_node_t; + +/** + * BackReferenceReadNode + * + * Represents reading a reference to a field in the previous match. + * + * $' + * ^^ + * + * Type: ::PM_BACK_REFERENCE_READ_NODE + * + * @extends pm_node_t + */ +typedef struct pm_back_reference_read_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * BackReferenceReadNode#name + * + * The name of the back-reference variable, including the leading `$`. + * + * $& # name `:$&` + * + * $+ # name `:$+` + */ + pm_constant_id_t name; +} pm_back_reference_read_node_t; + +/** + * BeginNode + * + * Represents a begin statement. + * + * begin + * foo + * end + * ^^^^^ + * + * Type: ::PM_BEGIN_NODE + * + * @extends pm_node_t + */ +typedef struct pm_begin_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * BeginNode#begin_keyword_loc + * + * Represents the location of the `begin` keyword. + * + * begin x end + * ^^^^^ + */ + pm_location_t begin_keyword_loc; + + /** + * BeginNode#statements + * + * Represents the statements within the begin block. + * + * begin x end + * ^ + */ + struct pm_statements_node *statements; + + /** + * BeginNode#rescue_clause + * + * Represents the rescue clause within the begin block. + * + * begin x; rescue y; end + * ^^^^^^^^ + */ + struct pm_rescue_node *rescue_clause; + + /** + * BeginNode#else_clause + * + * Represents the else clause within the begin block. + * + * begin x; rescue y; else z; end + * ^^^^^^ + */ + struct pm_else_node *else_clause; + + /** + * BeginNode#ensure_clause + * + * Represents the ensure clause within the begin block. + * + * begin x; ensure y; end + * ^^^^^^^^ + */ + struct pm_ensure_node *ensure_clause; + + /** + * BeginNode#end_keyword_loc + * + * Represents the location of the `end` keyword. + * + * begin x end + * ^^^ + */ + pm_location_t end_keyword_loc; +} pm_begin_node_t; + +/** + * BlockArgumentNode + * + * Represents a block argument using `&`. + * + * bar(&args) + * ^^^^^^^^^^ + * + * Type: ::PM_BLOCK_ARGUMENT_NODE + * + * @extends pm_node_t + */ +typedef struct pm_block_argument_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * BlockArgumentNode#expression + * + * The expression that is being passed as a block argument. This can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression). + * + * foo(&args) + * ^^^^^ + */ + struct pm_node *expression; + + /** + * BlockArgumentNode#operator_loc + * + * Represents the location of the `&` operator. + * + * foo(&args) + * ^ + */ + pm_location_t operator_loc; +} pm_block_argument_node_t; + +/** + * BlockLocalVariableNode + * + * Represents a block local variable. + * + * a { |; b| } + * ^ + * + * Type: ::PM_BLOCK_LOCAL_VARIABLE_NODE + + * Flags (#pm_parameter_flags): + * * ::PM_PARAMETER_FLAGS_REPEATED_PARAMETER + * + * @extends pm_node_t + */ +typedef struct pm_block_local_variable_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * BlockLocalVariableNode#name + * + * The name of the block local variable. + * + * a { |; b| } # name `:b` + * ^ + */ + pm_constant_id_t name; +} pm_block_local_variable_node_t; + +/** + * BlockNode + * + * Represents a block of ruby code. + * + * [1, 2, 3].each { |i| puts x } + * ^^^^^^^^^^^^^^ + * + * Type: ::PM_BLOCK_NODE + * + * @extends pm_node_t + */ +typedef struct pm_block_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * BlockNode#locals + * + * The local variables declared in the block. + * + * [1, 2, 3].each { |i| puts x } # locals: [:i] + * ^ + */ + pm_constant_id_list_t locals; + + /** + * BlockNode#parameters + * + * The parameters of the block. + * + * [1, 2, 3].each { |i| puts x } + * ^^^ + * [1, 2, 3].each { puts _1 } + * ^^^^^^^^^^^ + * [1, 2, 3].each { puts it } + * ^^^^^^^^^^^ + */ + struct pm_node *parameters; + + /** + * BlockNode#body + * + * The body of the block. + * + * [1, 2, 3].each { |i| puts x } + * ^^^^^^ + */ + struct pm_node *body; + + /** + * BlockNode#opening_loc + * + * Represents the location of the opening `|`. + * + * [1, 2, 3].each { |i| puts x } + * ^ + */ + pm_location_t opening_loc; + + /** + * BlockNode#closing_loc + * + * Represents the location of the closing `|`. + * + * [1, 2, 3].each { |i| puts x } + * ^ + */ + pm_location_t closing_loc; +} pm_block_node_t; + +/** + * BlockParameterNode + * + * Represents a block parameter of a method, block, or lambda definition. + * + * def a(&b) + * ^^ + * end + * + * Type: ::PM_BLOCK_PARAMETER_NODE + + * Flags (#pm_parameter_flags): + * * ::PM_PARAMETER_FLAGS_REPEATED_PARAMETER + * + * @extends pm_node_t + */ +typedef struct pm_block_parameter_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * BlockParameterNode#name + * + * The name of the block parameter. + * + * def a(&b) # name `:b` + * ^ + * end + */ + pm_constant_id_t name; + + /** + * BlockParameterNode#name_loc + * + * Represents the location of the block parameter name. + * + * def a(&b) + * ^ + */ + pm_location_t name_loc; + + /** + * BlockParameterNode#operator_loc + * + * Represents the location of the `&` operator. + * + * def a(&b) + * ^ + * end + */ + pm_location_t operator_loc; +} pm_block_parameter_node_t; + +/** + * BlockParametersNode + * + * Represents a block's parameters declaration. + * + * -> (a, b = 1; local) { } + * ^^^^^^^^^^^^^^^^^ + * + * foo do |a, b = 1; local| + * ^^^^^^^^^^^^^^^^^ + * end + * + * Type: ::PM_BLOCK_PARAMETERS_NODE + * + * @extends pm_node_t + */ +typedef struct pm_block_parameters_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * BlockParametersNode#parameters + * + * Represents the parameters of the block. + * + * -> (a, b = 1; local) { } + * ^^^^^^^^ + * + * foo do |a, b = 1; local| + * ^^^^^^^^ + * end + */ + struct pm_parameters_node *parameters; + + /** + * BlockParametersNode#locals + * + * Represents the local variables of the block. + * + * -> (a, b = 1; local) { } + * ^^^^^ + * + * foo do |a, b = 1; local| + * ^^^^^ + * end + */ + struct pm_node_list locals; + + /** + * BlockParametersNode#opening_loc + * + * Represents the opening location of the block parameters. + * + * -> (a, b = 1; local) { } + * ^ + * + * foo do |a, b = 1; local| + * ^ + * end + */ + pm_location_t opening_loc; + + /** + * BlockParametersNode#closing_loc + * + * Represents the closing location of the block parameters. + * + * -> (a, b = 1; local) { } + * ^ + * + * foo do |a, b = 1; local| + * ^ + * end + */ + pm_location_t closing_loc; +} pm_block_parameters_node_t; + +/** + * BreakNode + * + * Represents the use of the `break` keyword. + * + * break foo + * ^^^^^^^^^ + * + * Type: ::PM_BREAK_NODE + * + * @extends pm_node_t + */ +typedef struct pm_break_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * BreakNode#arguments + * + * The arguments to the break statement, if present. These can be any [non-void expressions](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression). + * + * break foo + * ^^^ + */ + struct pm_arguments_node *arguments; + + /** + * BreakNode#keyword_loc + * + * The location of the `break` keyword. + * + * break foo + * ^^^^^ + */ + pm_location_t keyword_loc; +} pm_break_node_t; + +/** + * CallAndWriteNode + * + * Represents the use of the `&&=` operator on a call. + * + * foo.bar &&= value + * ^^^^^^^^^^^^^^^^^ + * + * Type: ::PM_CALL_AND_WRITE_NODE + + * Flags (#pm_call_node_flags): + * * ::PM_CALL_NODE_FLAGS_SAFE_NAVIGATION + * * ::PM_CALL_NODE_FLAGS_VARIABLE_CALL + * * ::PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE + * * ::PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY + * + * @extends pm_node_t + */ +typedef struct pm_call_and_write_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * CallAndWriteNode#receiver + * + * The object that the method is being called on. This can be either `nil` or any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression). + * + * foo.bar &&= value + * ^^^ + */ + struct pm_node *receiver; + + /** + * CallAndWriteNode#call_operator_loc + * + * Represents the location of the call operator. + * + * foo.bar &&= value + * ^ + */ + pm_location_t call_operator_loc; + + /** + * CallAndWriteNode#message_loc + * + * Represents the location of the message. + * + * foo.bar &&= value + * ^^^ + */ + pm_location_t message_loc; + + /** + * CallAndWriteNode#read_name + * + * Represents the name of the method being called. + * + * foo.bar &&= value # read_name `:bar` + * ^^^ + */ + pm_constant_id_t read_name; + + /** + * CallAndWriteNode#write_name + * + * Represents the name of the method being written to. + * + * foo.bar &&= value # write_name `:bar=` + * ^^^ + */ + pm_constant_id_t write_name; + + /** + * CallAndWriteNode#operator_loc + * + * Represents the location of the operator. + * + * foo.bar &&= value + * ^^^ + */ + pm_location_t operator_loc; + + /** + * CallAndWriteNode#value + * + * Represents the value being assigned. + * + * foo.bar &&= value + * ^^^^^ + */ + struct pm_node *value; +} pm_call_and_write_node_t; + +/** + * CallNode + * + * Represents a method call, in all of the various forms that can take. + * + * foo + * ^^^ + * + * foo() + * ^^^^^ + * + * +foo + * ^^^^ + * + * foo + bar + * ^^^^^^^^^ + * + * foo.bar + * ^^^^^^^ + * + * foo&.bar + * ^^^^^^^^ + * + * Type: ::PM_CALL_NODE + + * Flags (#pm_call_node_flags): + * * ::PM_CALL_NODE_FLAGS_SAFE_NAVIGATION + * * ::PM_CALL_NODE_FLAGS_VARIABLE_CALL + * * ::PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE + * * ::PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY + * + * @extends pm_node_t + */ +typedef struct pm_call_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * CallNode#receiver + * + * The object that the method is being called on. This can be either `nil` or any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression). + * + * foo.bar + * ^^^ + * + * +foo + * ^^^ + * + * foo + bar + * ^^^ + */ + struct pm_node *receiver; + + /** + * CallNode#call_operator_loc + * + * Represents the location of the call operator. + * + * foo.bar + * ^ + * + * foo&.bar + * ^^ + */ + pm_location_t call_operator_loc; + + /** + * CallNode#name + * + * Represents the name of the method being called. + * + * foo.bar # name `:foo` + * ^^^ + */ + pm_constant_id_t name; + + /** + * CallNode#message_loc + * + * Represents the location of the message. + * + * foo.bar + * ^^^ + */ + pm_location_t message_loc; + + /** + * CallNode#opening_loc + * + * Represents the location of the left parenthesis. + * foo(bar) + * ^ + */ + pm_location_t opening_loc; + + /** + * CallNode#arguments + * + * Represents the arguments to the method call. These can be any [non-void expressions](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression). + * + * foo(bar) + * ^^^ + */ + struct pm_arguments_node *arguments; + + /** + * CallNode#closing_loc + * + * Represents the location of the right parenthesis. + * + * foo(bar) + * ^ + */ + pm_location_t closing_loc; + + /** + * CallNode#equal_loc + * + * Represents the location of the equal sign, in the case that this is an attribute write. + * + * foo.bar = value + * ^ + * + * foo[bar] = value + * ^ + */ + pm_location_t equal_loc; + + /** + * CallNode#block + * + * Represents the block that is being passed to the method. + * + * foo { |a| a } + * ^^^^^^^^^ + */ + struct pm_node *block; +} pm_call_node_t; + +/** + * CallOperatorWriteNode + * + * Represents the use of an assignment operator on a call. + * + * foo.bar += baz + * ^^^^^^^^^^^^^^ + * + * Type: ::PM_CALL_OPERATOR_WRITE_NODE + + * Flags (#pm_call_node_flags): + * * ::PM_CALL_NODE_FLAGS_SAFE_NAVIGATION + * * ::PM_CALL_NODE_FLAGS_VARIABLE_CALL + * * ::PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE + * * ::PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY + * + * @extends pm_node_t + */ +typedef struct pm_call_operator_write_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * CallOperatorWriteNode#receiver + * + * The object that the method is being called on. This can be either `nil` or any [non-void expressions](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression). + * + * foo.bar += value + * ^^^ + */ + struct pm_node *receiver; + + /** + * CallOperatorWriteNode#call_operator_loc + * + * Represents the location of the call operator. + * + * foo.bar += value + * ^ + */ + pm_location_t call_operator_loc; + + /** + * CallOperatorWriteNode#message_loc + * + * Represents the location of the message. + * + * foo.bar += value + * ^^^ + */ + pm_location_t message_loc; + + /** + * CallOperatorWriteNode#read_name + * + * Represents the name of the method being called. + * + * foo.bar += value # read_name `:bar` + * ^^^ + */ + pm_constant_id_t read_name; + + /** + * CallOperatorWriteNode#write_name + * + * Represents the name of the method being written to. + * + * foo.bar += value # write_name `:bar=` + * ^^^ + */ + pm_constant_id_t write_name; + + /** + * CallOperatorWriteNode#binary_operator + * + * Represents the binary operator being used. + * + * foo.bar += value # binary_operator `:+` + * ^ + */ + pm_constant_id_t binary_operator; + + /** + * CallOperatorWriteNode#binary_operator_loc + * + * Represents the location of the binary operator. + * + * foo.bar += value + * ^^ + */ + pm_location_t binary_operator_loc; + + /** + * CallOperatorWriteNode#value + * + * Represents the value being assigned. + * + * foo.bar += value + * ^^^^^ + */ + struct pm_node *value; +} pm_call_operator_write_node_t; + +/** + * CallOrWriteNode + * + * Represents the use of the `||=` operator on a call. + * + * foo.bar ||= value + * ^^^^^^^^^^^^^^^^^ + * + * Type: ::PM_CALL_OR_WRITE_NODE + + * Flags (#pm_call_node_flags): + * * ::PM_CALL_NODE_FLAGS_SAFE_NAVIGATION + * * ::PM_CALL_NODE_FLAGS_VARIABLE_CALL + * * ::PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE + * * ::PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY + * + * @extends pm_node_t + */ +typedef struct pm_call_or_write_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * CallOrWriteNode#receiver + * + * The object that the method is being called on. This can be either `nil` or any [non-void expressions](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression). + * + * foo.bar ||= value + * ^^^ + */ + struct pm_node *receiver; + + /** + * CallOrWriteNode#call_operator_loc + * + * Represents the location of the call operator. + * + * foo.bar ||= value + * ^ + */ + pm_location_t call_operator_loc; + + /** + * CallOrWriteNode#message_loc + * + * Represents the location of the message. + * + * foo.bar ||= value + * ^^^ + */ + pm_location_t message_loc; + + /** + * CallOrWriteNode#read_name + * + * Represents the name of the method being called. + * + * foo.bar ||= value # read_name `:bar` + * ^^^ + */ + pm_constant_id_t read_name; + + /** + * CallOrWriteNode#write_name + * + * Represents the name of the method being written to. + * + * foo.bar ||= value # write_name `:bar=` + * ^^^ + */ + pm_constant_id_t write_name; + + /** + * CallOrWriteNode#operator_loc + * + * Represents the location of the operator. + * + * foo.bar ||= value + * ^^^ + */ + pm_location_t operator_loc; + + /** + * CallOrWriteNode#value + * + * Represents the value being assigned. + * + * foo.bar ||= value + * ^^^^^ + */ + struct pm_node *value; +} pm_call_or_write_node_t; + +/** + * CallTargetNode + * + * Represents assigning to a method call. + * + * foo.bar, = 1 + * ^^^^^^^ + * + * begin + * rescue => foo.bar + * ^^^^^^^ + * end + * + * for foo.bar in baz do end + * ^^^^^^^ + * + * Type: ::PM_CALL_TARGET_NODE + + * Flags (#pm_call_node_flags): + * * ::PM_CALL_NODE_FLAGS_SAFE_NAVIGATION + * * ::PM_CALL_NODE_FLAGS_VARIABLE_CALL + * * ::PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE + * * ::PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY + * + * @extends pm_node_t + */ +typedef struct pm_call_target_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * CallTargetNode#receiver + * + * The object that the method is being called on. This can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression). + * + * foo.bar = 1 + * ^^^ + */ + struct pm_node *receiver; + + /** + * CallTargetNode#call_operator_loc + * + * Represents the location of the call operator. + * + * foo.bar = 1 + * ^ + */ + pm_location_t call_operator_loc; + + /** + * CallTargetNode#name + * + * Represents the name of the method being called. + * + * foo.bar = 1 # name `:foo` + * ^^^ + */ + pm_constant_id_t name; + + /** + * CallTargetNode#message_loc + * + * Represents the location of the message. + * + * foo.bar = 1 + * ^^^ + */ + pm_location_t message_loc; +} pm_call_target_node_t; + +/** + * CapturePatternNode + * + * Represents assigning to a local variable in pattern matching. + * + * foo => [bar => baz] + * ^^^^^^^^^^^^ + * + * Type: ::PM_CAPTURE_PATTERN_NODE + * + * @extends pm_node_t + */ +typedef struct pm_capture_pattern_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * CapturePatternNode#value + * + * Represents the value to capture. + * + * foo => bar + * ^^^ + */ + struct pm_node *value; + + /** + * CapturePatternNode#target + * + * Represents the target of the capture. + * + * foo => bar + * ^^^ + */ + struct pm_local_variable_target_node *target; + + /** + * CapturePatternNode#operator_loc + * + * Represents the location of the `=>` operator. + * + * foo => bar + * ^^ + */ + pm_location_t operator_loc; +} pm_capture_pattern_node_t; + +/** + * CaseMatchNode + * + * Represents the use of a case statement for pattern matching. + * + * case true + * in false + * end + * ^^^^^^^^^ + * + * Type: ::PM_CASE_MATCH_NODE + * + * @extends pm_node_t + */ +typedef struct pm_case_match_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * CaseMatchNode#predicate + * + * Represents the predicate of the case match. This can be either `nil` or any [non-void expressions](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression). + * + * case true; in false; end + * ^^^^ + */ + struct pm_node *predicate; + + /** + * CaseMatchNode#conditions + * + * Represents the conditions of the case match. + * + * case true; in false; end + * ^^^^^^^^ + */ + struct pm_node_list conditions; + + /** + * CaseMatchNode#else_clause + * + * Represents the else clause of the case match. + * + * case true; in false; else; end + * ^^^^ + */ + struct pm_else_node *else_clause; + + /** + * CaseMatchNode#case_keyword_loc + * + * Represents the location of the `case` keyword. + * + * case true; in false; end + * ^^^^ + */ + pm_location_t case_keyword_loc; + + /** + * CaseMatchNode#end_keyword_loc + * + * Represents the location of the `end` keyword. + * + * case true; in false; end + * ^^^ + */ + pm_location_t end_keyword_loc; +} pm_case_match_node_t; + +/** + * CaseNode + * + * Represents the use of a case statement. + * + * case true + * when false + * end + * ^^^^^^^^^^ + * + * Type: ::PM_CASE_NODE + * + * @extends pm_node_t + */ +typedef struct pm_case_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * CaseNode#predicate + * + * Represents the predicate of the case statement. This can be either `nil` or any [non-void expressions](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression). + * + * case true; when false; end + * ^^^^ + */ + struct pm_node *predicate; + + /** + * CaseNode#conditions + * + * Represents the conditions of the case statement. + * + * case true; when false; end + * ^^^^^^^^^^ + */ + struct pm_node_list conditions; + + /** + * CaseNode#else_clause + * + * Represents the else clause of the case statement. + * + * case true; when false; else; end + * ^^^^ + */ + struct pm_else_node *else_clause; + + /** + * CaseNode#case_keyword_loc + * + * Represents the location of the `case` keyword. + * + * case true; when false; end + * ^^^^ + */ + pm_location_t case_keyword_loc; + + /** + * CaseNode#end_keyword_loc + * + * Represents the location of the `end` keyword. + * + * case true; when false; end + * ^^^ + */ + pm_location_t end_keyword_loc; +} pm_case_node_t; + +/** + * ClassNode + * + * Represents a class declaration involving the `class` keyword. + * + * class Foo end + * ^^^^^^^^^^^^^ + * + * Type: ::PM_CLASS_NODE + * + * @extends pm_node_t + */ +typedef struct pm_class_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * ClassNode#locals + */ + pm_constant_id_list_t locals; + + /** + * ClassNode#class_keyword_loc + * + * Represents the location of the `class` keyword. + * + * class Foo end + * ^^^^^ + */ + pm_location_t class_keyword_loc; + + /** + * ClassNode#constant_path + */ + struct pm_node *constant_path; + + /** + * ClassNode#inheritance_operator_loc + * + * Represents the location of the `<` operator. + * + * class Foo < Bar + * ^ + */ + pm_location_t inheritance_operator_loc; + + /** + * ClassNode#superclass + * + * Represents the superclass of the class. + * + * class Foo < Bar + * ^^^ + */ + struct pm_node *superclass; + + /** + * ClassNode#body + * + * Represents the body of the class. + * + * class Foo + * foo + * ^^^ + */ + struct pm_node *body; + + /** + * ClassNode#end_keyword_loc + * + * Represents the location of the `end` keyword. + * + * class Foo end + * ^^^ + */ + pm_location_t end_keyword_loc; + + /** + * ClassNode#name + * + * The name of the class. + * + * class Foo end # name `:Foo` + */ + pm_constant_id_t name; +} pm_class_node_t; + +/** + * ClassVariableAndWriteNode + * + * Represents the use of the `&&=` operator for assignment to a class variable. + * + * @@target &&= value + * ^^^^^^^^^^^^^^^^^^ + * + * Type: ::PM_CLASS_VARIABLE_AND_WRITE_NODE + * + * @extends pm_node_t + */ +typedef struct pm_class_variable_and_write_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * ClassVariableAndWriteNode#name + * + * The name of the class variable, which is a `@@` followed by an [identifier](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#identifiers). + * + * @@target &&= value # name `:@@target` + * ^^^^^^^^ + */ + pm_constant_id_t name; + + /** + * ClassVariableAndWriteNode#name_loc + * + * Represents the location of the variable name. + * + * @@target &&= value + * ^^^^^^^^ + */ + pm_location_t name_loc; + + /** + * ClassVariableAndWriteNode#operator_loc + * + * Represents the location of the `&&=` operator. + * + * @@target &&= value + * ^^^ + */ + pm_location_t operator_loc; + + /** + * ClassVariableAndWriteNode#value + * + * Represents the value being assigned. This can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression). + * + * @@target &&= value + * ^^^^^ + */ + struct pm_node *value; +} pm_class_variable_and_write_node_t; + +/** + * ClassVariableOperatorWriteNode + * + * Represents assigning to a class variable using an operator that isn't `=`. + * + * @@target += value + * ^^^^^^^^^^^^^^^^^ + * + * Type: ::PM_CLASS_VARIABLE_OPERATOR_WRITE_NODE + * + * @extends pm_node_t + */ +typedef struct pm_class_variable_operator_write_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * ClassVariableOperatorWriteNode#name + */ + pm_constant_id_t name; + + /** + * ClassVariableOperatorWriteNode#name_loc + */ + pm_location_t name_loc; + + /** + * ClassVariableOperatorWriteNode#binary_operator_loc + */ + pm_location_t binary_operator_loc; + + /** + * ClassVariableOperatorWriteNode#value + */ + struct pm_node *value; + + /** + * ClassVariableOperatorWriteNode#binary_operator + */ + pm_constant_id_t binary_operator; +} pm_class_variable_operator_write_node_t; + +/** + * ClassVariableOrWriteNode + * + * Represents the use of the `||=` operator for assignment to a class variable. + * + * @@target ||= value + * ^^^^^^^^^^^^^^^^^^ + * + * Type: ::PM_CLASS_VARIABLE_OR_WRITE_NODE + * + * @extends pm_node_t + */ +typedef struct pm_class_variable_or_write_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * ClassVariableOrWriteNode#name + */ + pm_constant_id_t name; + + /** + * ClassVariableOrWriteNode#name_loc + */ + pm_location_t name_loc; + + /** + * ClassVariableOrWriteNode#operator_loc + */ + pm_location_t operator_loc; + + /** + * ClassVariableOrWriteNode#value + */ + struct pm_node *value; +} pm_class_variable_or_write_node_t; + +/** + * ClassVariableReadNode + * + * Represents referencing a class variable. + * + * @@foo + * ^^^^^ + * + * Type: ::PM_CLASS_VARIABLE_READ_NODE + * + * @extends pm_node_t + */ +typedef struct pm_class_variable_read_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * ClassVariableReadNode#name + * + * The name of the class variable, which is a `@@` followed by an [identifier](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#identifiers). + * + * @@abc # name `:@@abc` + * + * @@_test # name `:@@_test` + */ + pm_constant_id_t name; +} pm_class_variable_read_node_t; + +/** + * ClassVariableTargetNode + * + * Represents writing to a class variable in a context that doesn't have an explicit value. + * + * @@foo, @@bar = baz + * ^^^^^ ^^^^^ + * + * Type: ::PM_CLASS_VARIABLE_TARGET_NODE + * + * @extends pm_node_t + */ +typedef struct pm_class_variable_target_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * ClassVariableTargetNode#name + */ + pm_constant_id_t name; +} pm_class_variable_target_node_t; + +/** + * ClassVariableWriteNode + * + * Represents writing to a class variable. + * + * @@foo = 1 + * ^^^^^^^^^ + * + * Type: ::PM_CLASS_VARIABLE_WRITE_NODE + * + * @extends pm_node_t + */ +typedef struct pm_class_variable_write_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * ClassVariableWriteNode#name + * + * The name of the class variable, which is a `@@` followed by an [identifier](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#identifiers). + * + * @@abc = 123 # name `@@abc` + * + * @@_test = :test # name `@@_test` + */ + pm_constant_id_t name; + + /** + * ClassVariableWriteNode#name_loc + * + * The location of the variable name. + * + * @@foo = :bar + * ^^^^^ + */ + pm_location_t name_loc; + + /** + * ClassVariableWriteNode#value + * + * The value to write to the class variable. This can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression). + * + * @@foo = :bar + * ^^^^ + * + * @@_xyz = 123 + * ^^^ + */ + struct pm_node *value; + + /** + * ClassVariableWriteNode#operator_loc + * + * The location of the `=` operator. + * + * @@foo = :bar + * ^ + */ + pm_location_t operator_loc; +} pm_class_variable_write_node_t; + +/** + * ConstantAndWriteNode + * + * Represents the use of the `&&=` operator for assignment to a constant. + * + * Target &&= value + * ^^^^^^^^^^^^^^^^ + * + * Type: ::PM_CONSTANT_AND_WRITE_NODE + * + * @extends pm_node_t + */ +typedef struct pm_constant_and_write_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * ConstantAndWriteNode#name + */ + pm_constant_id_t name; + + /** + * ConstantAndWriteNode#name_loc + */ + pm_location_t name_loc; + + /** + * ConstantAndWriteNode#operator_loc + */ + pm_location_t operator_loc; + + /** + * ConstantAndWriteNode#value + */ + struct pm_node *value; +} pm_constant_and_write_node_t; + +/** + * ConstantOperatorWriteNode + * + * Represents assigning to a constant using an operator that isn't `=`. + * + * Target += value + * ^^^^^^^^^^^^^^^ + * + * Type: ::PM_CONSTANT_OPERATOR_WRITE_NODE + * + * @extends pm_node_t + */ +typedef struct pm_constant_operator_write_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * ConstantOperatorWriteNode#name + */ + pm_constant_id_t name; + + /** + * ConstantOperatorWriteNode#name_loc + */ + pm_location_t name_loc; + + /** + * ConstantOperatorWriteNode#binary_operator_loc + */ + pm_location_t binary_operator_loc; + + /** + * ConstantOperatorWriteNode#value + */ + struct pm_node *value; + + /** + * ConstantOperatorWriteNode#binary_operator + */ + pm_constant_id_t binary_operator; +} pm_constant_operator_write_node_t; + +/** + * ConstantOrWriteNode + * + * Represents the use of the `||=` operator for assignment to a constant. + * + * Target ||= value + * ^^^^^^^^^^^^^^^^ + * + * Type: ::PM_CONSTANT_OR_WRITE_NODE + * + * @extends pm_node_t + */ +typedef struct pm_constant_or_write_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * ConstantOrWriteNode#name + */ + pm_constant_id_t name; + + /** + * ConstantOrWriteNode#name_loc + */ + pm_location_t name_loc; + + /** + * ConstantOrWriteNode#operator_loc + */ + pm_location_t operator_loc; + + /** + * ConstantOrWriteNode#value + */ + struct pm_node *value; +} pm_constant_or_write_node_t; + +/** + * ConstantPathAndWriteNode + * + * Represents the use of the `&&=` operator for assignment to a constant path. + * + * Parent::Child &&= value + * ^^^^^^^^^^^^^^^^^^^^^^^ + * + * Type: ::PM_CONSTANT_PATH_AND_WRITE_NODE + * + * @extends pm_node_t + */ +typedef struct pm_constant_path_and_write_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * ConstantPathAndWriteNode#target + */ + struct pm_constant_path_node *target; + + /** + * ConstantPathAndWriteNode#operator_loc + */ + pm_location_t operator_loc; + + /** + * ConstantPathAndWriteNode#value + */ + struct pm_node *value; +} pm_constant_path_and_write_node_t; + +/** + * ConstantPathNode + * + * Represents accessing a constant through a path of `::` operators. + * + * Foo::Bar + * ^^^^^^^^ + * + * Type: ::PM_CONSTANT_PATH_NODE + * + * @extends pm_node_t + */ +typedef struct pm_constant_path_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * ConstantPathNode#parent + * + * The left-hand node of the path, if present. It can be `nil` or any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression). It will be `nil` when the constant lookup is at the root of the module tree. + * + * Foo::Bar + * ^^^ + * + * self::Test + * ^^^^ + * + * a.b::C + * ^^^ + */ + struct pm_node *parent; + + /** + * ConstantPathNode#name + * + * The name of the constant being accessed. This could be `nil` in the event of a syntax error. + */ + pm_constant_id_t name; + + /** + * ConstantPathNode#delimiter_loc + * + * The location of the `::` delimiter. + * + * ::Foo + * ^^ + * + * One::Two + * ^^ + */ + pm_location_t delimiter_loc; + + /** + * ConstantPathNode#name_loc + * + * The location of the name of the constant. + * + * ::Foo + * ^^^ + * + * One::Two + * ^^^ + */ + pm_location_t name_loc; +} pm_constant_path_node_t; + +/** + * ConstantPathOperatorWriteNode + * + * Represents assigning to a constant path using an operator that isn't `=`. + * + * Parent::Child += value + * ^^^^^^^^^^^^^^^^^^^^^^ + * + * Type: ::PM_CONSTANT_PATH_OPERATOR_WRITE_NODE + * + * @extends pm_node_t + */ +typedef struct pm_constant_path_operator_write_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * ConstantPathOperatorWriteNode#target + */ + struct pm_constant_path_node *target; + + /** + * ConstantPathOperatorWriteNode#binary_operator_loc + */ + pm_location_t binary_operator_loc; + + /** + * ConstantPathOperatorWriteNode#value + */ + struct pm_node *value; + + /** + * ConstantPathOperatorWriteNode#binary_operator + */ + pm_constant_id_t binary_operator; +} pm_constant_path_operator_write_node_t; + +/** + * ConstantPathOrWriteNode + * + * Represents the use of the `||=` operator for assignment to a constant path. + * + * Parent::Child ||= value + * ^^^^^^^^^^^^^^^^^^^^^^^ + * + * Type: ::PM_CONSTANT_PATH_OR_WRITE_NODE + * + * @extends pm_node_t + */ +typedef struct pm_constant_path_or_write_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * ConstantPathOrWriteNode#target + */ + struct pm_constant_path_node *target; + + /** + * ConstantPathOrWriteNode#operator_loc + */ + pm_location_t operator_loc; + + /** + * ConstantPathOrWriteNode#value + */ + struct pm_node *value; +} pm_constant_path_or_write_node_t; + +/** + * ConstantPathTargetNode + * + * Represents writing to a constant path in a context that doesn't have an explicit value. + * + * Foo::Foo, Bar::Bar = baz + * ^^^^^^^^ ^^^^^^^^ + * + * Type: ::PM_CONSTANT_PATH_TARGET_NODE + * + * @extends pm_node_t + */ +typedef struct pm_constant_path_target_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * ConstantPathTargetNode#parent + */ + struct pm_node *parent; + + /** + * ConstantPathTargetNode#name + */ + pm_constant_id_t name; + + /** + * ConstantPathTargetNode#delimiter_loc + */ + pm_location_t delimiter_loc; + + /** + * ConstantPathTargetNode#name_loc + */ + pm_location_t name_loc; +} pm_constant_path_target_node_t; + +/** + * ConstantPathWriteNode + * + * Represents writing to a constant path. + * + * ::Foo = 1 + * ^^^^^^^^^ + * + * Foo::Bar = 1 + * ^^^^^^^^^^^^ + * + * ::Foo::Bar = 1 + * ^^^^^^^^^^^^^^ + * + * Type: ::PM_CONSTANT_PATH_WRITE_NODE + * + * @extends pm_node_t + */ +typedef struct pm_constant_path_write_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * ConstantPathWriteNode#target + * + * A node representing the constant path being written to. + * + * Foo::Bar = 1 + * ^^^^^^^^ + * + * ::Foo = :abc + * ^^^^^ + */ + struct pm_constant_path_node *target; + + /** + * ConstantPathWriteNode#operator_loc + * + * The location of the `=` operator. + * + * ::ABC = 123 + * ^ + */ + pm_location_t operator_loc; + + /** + * ConstantPathWriteNode#value + * + * The value to write to the constant path. It can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression). + * + * FOO::BAR = :abc + * ^^^^ + */ + struct pm_node *value; +} pm_constant_path_write_node_t; + +/** + * ConstantReadNode + * + * Represents referencing a constant. + * + * Foo + * ^^^ + * + * Type: ::PM_CONSTANT_READ_NODE + * + * @extends pm_node_t + */ +typedef struct pm_constant_read_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * ConstantReadNode#name + * + * The name of the [constant](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#constants). + * + * X # name `:X` + * + * SOME_CONSTANT # name `:SOME_CONSTANT` + */ + pm_constant_id_t name; +} pm_constant_read_node_t; + +/** + * ConstantTargetNode + * + * Represents writing to a constant in a context that doesn't have an explicit value. + * + * Foo, Bar = baz + * ^^^ ^^^ + * + * Type: ::PM_CONSTANT_TARGET_NODE + * + * @extends pm_node_t + */ +typedef struct pm_constant_target_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * ConstantTargetNode#name + */ + pm_constant_id_t name; +} pm_constant_target_node_t; + +/** + * ConstantWriteNode + * + * Represents writing to a constant. + * + * Foo = 1 + * ^^^^^^^ + * + * Type: ::PM_CONSTANT_WRITE_NODE + * + * @extends pm_node_t + */ +typedef struct pm_constant_write_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * ConstantWriteNode#name + * + * The name of the [constant](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#constants). + * + * Foo = :bar # name `:Foo` + * + * XYZ = 1 # name `:XYZ` + */ + pm_constant_id_t name; + + /** + * ConstantWriteNode#name_loc + * + * The location of the constant name. + * + * FOO = 1 + * ^^^ + */ + pm_location_t name_loc; + + /** + * ConstantWriteNode#value + * + * The value to write to the constant. It can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression). + * + * FOO = :bar + * ^^^^ + * + * MyClass = Class.new + * ^^^^^^^^^ + */ + struct pm_node *value; + + /** + * ConstantWriteNode#operator_loc + * + * The location of the `=` operator. + * + * FOO = :bar + * ^ + */ + pm_location_t operator_loc; +} pm_constant_write_node_t; + +/** + * DefNode + * + * Represents a method definition. + * + * def method + * end + * ^^^^^^^^^^ + * + * Type: ::PM_DEF_NODE + * + * @extends pm_node_t + */ +typedef struct pm_def_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * DefNode#name + */ + pm_constant_id_t name; + + /** + * DefNode#name_loc + */ + pm_location_t name_loc; + + /** + * DefNode#receiver + */ + struct pm_node *receiver; + + /** + * DefNode#parameters + */ + struct pm_parameters_node *parameters; + + /** + * DefNode#body + */ + struct pm_node *body; + + /** + * DefNode#locals + */ + pm_constant_id_list_t locals; + + /** + * DefNode#def_keyword_loc + */ + pm_location_t def_keyword_loc; + + /** + * DefNode#operator_loc + */ + pm_location_t operator_loc; + + /** + * DefNode#lparen_loc + */ + pm_location_t lparen_loc; + + /** + * DefNode#rparen_loc + */ + pm_location_t rparen_loc; + + /** + * DefNode#equal_loc + */ + pm_location_t equal_loc; + + /** + * DefNode#end_keyword_loc + */ + pm_location_t end_keyword_loc; +} pm_def_node_t; + +/** + * DefinedNode + * + * Represents the use of the `defined?` keyword. + * + * defined?(a) + * ^^^^^^^^^^^ + * + * Type: ::PM_DEFINED_NODE + * + * @extends pm_node_t + */ +typedef struct pm_defined_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * DefinedNode#lparen_loc + */ + pm_location_t lparen_loc; + + /** + * DefinedNode#value + */ + struct pm_node *value; + + /** + * DefinedNode#rparen_loc + */ + pm_location_t rparen_loc; + + /** + * DefinedNode#keyword_loc + */ + pm_location_t keyword_loc; +} pm_defined_node_t; + +/** + * ElseNode + * + * Represents an `else` clause in a `case`, `if`, or `unless` statement. + * + * if a then b else c end + * ^^^^^^^^^^ + * + * Type: ::PM_ELSE_NODE + * + * @extends pm_node_t + */ +typedef struct pm_else_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * ElseNode#else_keyword_loc + */ + pm_location_t else_keyword_loc; + + /** + * ElseNode#statements + */ + struct pm_statements_node *statements; + + /** + * ElseNode#end_keyword_loc + */ + pm_location_t end_keyword_loc; +} pm_else_node_t; + +/** + * EmbeddedStatementsNode + * + * Represents an interpolated set of statements. + * + * "foo #{bar}" + * ^^^^^^ + * + * Type: ::PM_EMBEDDED_STATEMENTS_NODE + * + * @extends pm_node_t + */ +typedef struct pm_embedded_statements_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * EmbeddedStatementsNode#opening_loc + */ + pm_location_t opening_loc; + + /** + * EmbeddedStatementsNode#statements + */ + struct pm_statements_node *statements; + + /** + * EmbeddedStatementsNode#closing_loc + */ + pm_location_t closing_loc; +} pm_embedded_statements_node_t; + +/** + * EmbeddedVariableNode + * + * Represents an interpolated variable. + * + * "foo #@bar" + * ^^^^^ + * + * Type: ::PM_EMBEDDED_VARIABLE_NODE + * + * @extends pm_node_t + */ +typedef struct pm_embedded_variable_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * EmbeddedVariableNode#operator_loc + */ + pm_location_t operator_loc; + + /** + * EmbeddedVariableNode#variable + */ + struct pm_node *variable; +} pm_embedded_variable_node_t; + +/** + * EnsureNode + * + * Represents an `ensure` clause in a `begin` statement. + * + * begin + * foo + * ensure + * ^^^^^^ + * bar + * end + * + * Type: ::PM_ENSURE_NODE + * + * @extends pm_node_t + */ +typedef struct pm_ensure_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * EnsureNode#ensure_keyword_loc + */ + pm_location_t ensure_keyword_loc; + + /** + * EnsureNode#statements + */ + struct pm_statements_node *statements; + + /** + * EnsureNode#end_keyword_loc + */ + pm_location_t end_keyword_loc; +} pm_ensure_node_t; + +/** + * FalseNode + * + * Represents the use of the literal `false` keyword. + * + * false + * ^^^^^ + * + * Type: ::PM_FALSE_NODE + * + * @extends pm_node_t + */ +typedef struct pm_false_node { + /** The embedded base node. */ + pm_node_t base; + +} pm_false_node_t; + +/** + * FindPatternNode + * + * Represents a find pattern in pattern matching. + * + * foo in *bar, baz, *qux + * ^^^^^^^^^^^^^^^ + * + * foo in [*bar, baz, *qux] + * ^^^^^^^^^^^^^^^^^ + * + * foo in Foo(*bar, baz, *qux) + * ^^^^^^^^^^^^^^^^^^^^ + * + * foo => *bar, baz, *qux + * ^^^^^^^^^^^^^^^ + * + * Type: ::PM_FIND_PATTERN_NODE + * + * @extends pm_node_t + */ +typedef struct pm_find_pattern_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * FindPatternNode#constant + * + * Represents the optional constant preceding the pattern + * + * foo in Foo(*bar, baz, *qux) + * ^^^ + */ + struct pm_node *constant; + + /** + * FindPatternNode#left + * + * Represents the first wildcard node in the pattern. + * + * foo in *bar, baz, *qux + * ^^^^ + * + * foo in Foo(*bar, baz, *qux) + * ^^^^ + */ + struct pm_splat_node *left; + + /** + * FindPatternNode#requireds + * + * Represents the nodes in between the wildcards. + * + * foo in *bar, baz, *qux + * ^^^ + * + * foo in Foo(*bar, baz, 1, *qux) + * ^^^^^^ + */ + struct pm_node_list requireds; + + /** + * FindPatternNode#right + * + * Represents the second wildcard node in the pattern. + * + * foo in *bar, baz, *qux + * ^^^^ + * + * foo in Foo(*bar, baz, *qux) + * ^^^^ + */ + struct pm_node *right; + + /** + * FindPatternNode#opening_loc + * + * The location of the opening brace. + * + * foo in [*bar, baz, *qux] + * ^ + * + * foo in Foo(*bar, baz, *qux) + * ^ + */ + pm_location_t opening_loc; + + /** + * FindPatternNode#closing_loc + * + * The location of the closing brace. + * + * foo in [*bar, baz, *qux] + * ^ + * + * foo in Foo(*bar, baz, *qux) + * ^ + */ + pm_location_t closing_loc; +} pm_find_pattern_node_t; + +/** + * FlipFlopNode + * + * Represents the use of the `..` or `...` operators to create flip flops. + * + * baz if foo .. bar + * ^^^^^^^^^^ + * + * Type: ::PM_FLIP_FLOP_NODE + + * Flags (#pm_range_flags): + * * ::PM_RANGE_FLAGS_EXCLUDE_END + * + * @extends pm_node_t + */ +typedef struct pm_flip_flop_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * FlipFlopNode#left + */ + struct pm_node *left; + + /** + * FlipFlopNode#right + */ + struct pm_node *right; + + /** + * FlipFlopNode#operator_loc + */ + pm_location_t operator_loc; +} pm_flip_flop_node_t; + +/** + * FloatNode + * + * Represents a floating point number literal. + * + * 1.0 + * ^^^ + * + * Type: ::PM_FLOAT_NODE + * + * @extends pm_node_t + */ +typedef struct pm_float_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * FloatNode#value + * + * The value of the floating point number as a Float. + */ + double value; +} pm_float_node_t; + +/** + * ForNode + * + * Represents the use of the `for` keyword. + * + * for i in a end + * ^^^^^^^^^^^^^^ + * + * Type: ::PM_FOR_NODE + * + * @extends pm_node_t + */ +typedef struct pm_for_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * ForNode#index + * + * The index expression for `for` loops. + * + * for i in a end + * ^ + */ + struct pm_node *index; + + /** + * ForNode#collection + * + * The collection to iterate over. + * + * for i in a end + * ^ + */ + struct pm_node *collection; + + /** + * ForNode#statements + * + * Represents the body of statements to execute for each iteration of the loop. + * + * for i in a + * foo(i) + * ^^^^^^ + * end + */ + struct pm_statements_node *statements; + + /** + * ForNode#for_keyword_loc + * + * The location of the `for` keyword. + * + * for i in a end + * ^^^ + */ + pm_location_t for_keyword_loc; + + /** + * ForNode#in_keyword_loc + * + * The location of the `in` keyword. + * + * for i in a end + * ^^ + */ + pm_location_t in_keyword_loc; + + /** + * ForNode#do_keyword_loc + * + * The location of the `do` keyword, if present. + * + * for i in a do end + * ^^ + */ + pm_location_t do_keyword_loc; + + /** + * ForNode#end_keyword_loc + * + * The location of the `end` keyword. + * + * for i in a end + * ^^^ + */ + pm_location_t end_keyword_loc; +} pm_for_node_t; + +/** + * ForwardingArgumentsNode + * + * Represents forwarding all arguments to this method to another method. + * + * def foo(...) + * bar(...) + * ^^^ + * end + * + * Type: ::PM_FORWARDING_ARGUMENTS_NODE + * + * @extends pm_node_t + */ +typedef struct pm_forwarding_arguments_node { + /** The embedded base node. */ + pm_node_t base; + +} pm_forwarding_arguments_node_t; + +/** + * ForwardingParameterNode + * + * Represents the use of the forwarding parameter in a method, block, or lambda declaration. + * + * def foo(...) + * ^^^ + * end + * + * Type: ::PM_FORWARDING_PARAMETER_NODE + * + * @extends pm_node_t + */ +typedef struct pm_forwarding_parameter_node { + /** The embedded base node. */ + pm_node_t base; + +} pm_forwarding_parameter_node_t; + +/** + * ForwardingSuperNode + * + * Represents the use of the `super` keyword without parentheses or arguments. + * + * super + * ^^^^^ + * + * Type: ::PM_FORWARDING_SUPER_NODE + * + * @extends pm_node_t + */ +typedef struct pm_forwarding_super_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * ForwardingSuperNode#block + */ + struct pm_block_node *block; +} pm_forwarding_super_node_t; + +/** + * GlobalVariableAndWriteNode + * + * Represents the use of the `&&=` operator for assignment to a global variable. + * + * $target &&= value + * ^^^^^^^^^^^^^^^^^ + * + * Type: ::PM_GLOBAL_VARIABLE_AND_WRITE_NODE + * + * @extends pm_node_t + */ +typedef struct pm_global_variable_and_write_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * GlobalVariableAndWriteNode#name + */ + pm_constant_id_t name; + + /** + * GlobalVariableAndWriteNode#name_loc + */ + pm_location_t name_loc; + + /** + * GlobalVariableAndWriteNode#operator_loc + */ + pm_location_t operator_loc; + + /** + * GlobalVariableAndWriteNode#value + */ + struct pm_node *value; +} pm_global_variable_and_write_node_t; + +/** + * GlobalVariableOperatorWriteNode + * + * Represents assigning to a global variable using an operator that isn't `=`. + * + * $target += value + * ^^^^^^^^^^^^^^^^ + * + * Type: ::PM_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE + * + * @extends pm_node_t + */ +typedef struct pm_global_variable_operator_write_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * GlobalVariableOperatorWriteNode#name + */ + pm_constant_id_t name; + + /** + * GlobalVariableOperatorWriteNode#name_loc + */ + pm_location_t name_loc; + + /** + * GlobalVariableOperatorWriteNode#binary_operator_loc + */ + pm_location_t binary_operator_loc; + + /** + * GlobalVariableOperatorWriteNode#value + */ + struct pm_node *value; + + /** + * GlobalVariableOperatorWriteNode#binary_operator + */ + pm_constant_id_t binary_operator; +} pm_global_variable_operator_write_node_t; + +/** + * GlobalVariableOrWriteNode + * + * Represents the use of the `||=` operator for assignment to a global variable. + * + * $target ||= value + * ^^^^^^^^^^^^^^^^^ + * + * Type: ::PM_GLOBAL_VARIABLE_OR_WRITE_NODE + * + * @extends pm_node_t + */ +typedef struct pm_global_variable_or_write_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * GlobalVariableOrWriteNode#name + */ + pm_constant_id_t name; + + /** + * GlobalVariableOrWriteNode#name_loc + */ + pm_location_t name_loc; + + /** + * GlobalVariableOrWriteNode#operator_loc + */ + pm_location_t operator_loc; + + /** + * GlobalVariableOrWriteNode#value + */ + struct pm_node *value; +} pm_global_variable_or_write_node_t; + +/** + * GlobalVariableReadNode + * + * Represents referencing a global variable. + * + * $foo + * ^^^^ + * + * Type: ::PM_GLOBAL_VARIABLE_READ_NODE + * + * @extends pm_node_t + */ +typedef struct pm_global_variable_read_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * GlobalVariableReadNode#name + * + * The name of the global variable, which is a `$` followed by an [identifier](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#identifier). Alternatively, it can be one of the special global variables designated by a symbol. + * + * $foo # name `:$foo` + * + * $_Test # name `:$_Test` + */ + pm_constant_id_t name; +} pm_global_variable_read_node_t; + +/** + * GlobalVariableTargetNode + * + * Represents writing to a global variable in a context that doesn't have an explicit value. + * + * $foo, $bar = baz + * ^^^^ ^^^^ + * + * Type: ::PM_GLOBAL_VARIABLE_TARGET_NODE + * + * @extends pm_node_t + */ +typedef struct pm_global_variable_target_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * GlobalVariableTargetNode#name + */ + pm_constant_id_t name; +} pm_global_variable_target_node_t; + +/** + * GlobalVariableWriteNode + * + * Represents writing to a global variable. + * + * $foo = 1 + * ^^^^^^^^ + * + * Type: ::PM_GLOBAL_VARIABLE_WRITE_NODE + * + * @extends pm_node_t + */ +typedef struct pm_global_variable_write_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * GlobalVariableWriteNode#name + * + * The name of the global variable, which is a `$` followed by an [identifier](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#identifier). Alternatively, it can be one of the special global variables designated by a symbol. + * + * $foo = :bar # name `:$foo` + * + * $_Test = 123 # name `:$_Test` + */ + pm_constant_id_t name; + + /** + * GlobalVariableWriteNode#name_loc + * + * The location of the global variable's name. + * + * $foo = :bar + * ^^^^ + */ + pm_location_t name_loc; + + /** + * GlobalVariableWriteNode#value + * + * The value to write to the global variable. It can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression). + * + * $foo = :bar + * ^^^^ + * + * $-xyz = 123 + * ^^^ + */ + struct pm_node *value; + + /** + * GlobalVariableWriteNode#operator_loc + * + * The location of the `=` operator. + * + * $foo = :bar + * ^ + */ + pm_location_t operator_loc; +} pm_global_variable_write_node_t; + +/** + * HashNode + * + * Represents a hash literal. + * + * { a => b } + * ^^^^^^^^^^ + * + * Type: ::PM_HASH_NODE + * + * @extends pm_node_t + */ +typedef struct pm_hash_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * HashNode#opening_loc + * + * The location of the opening brace. + * + * { a => b } + * ^ + */ + pm_location_t opening_loc; + + /** + * HashNode#elements + * + * The elements of the hash. These can be either `AssocNode`s or `AssocSplatNode`s. + * + * { a: b } + * ^^^^ + * + * { **foo } + * ^^^^^ + */ + struct pm_node_list elements; + + /** + * HashNode#closing_loc + * + * The location of the closing brace. + * + * { a => b } + * ^ + */ + pm_location_t closing_loc; +} pm_hash_node_t; + +/** + * HashPatternNode + * + * Represents a hash pattern in pattern matching. + * + * foo => { a: 1, b: 2 } + * ^^^^^^^^^^^^^^ + * + * foo => { a: 1, b: 2, **c } + * ^^^^^^^^^^^^^^^^^^^ + * + * foo => Bar[a: 1, b: 2] + * ^^^^^^^^^^^^^^^ + * + * foo in { a: 1, b: 2 } + * ^^^^^^^^^^^^^^ + * + * Type: ::PM_HASH_PATTERN_NODE + * + * @extends pm_node_t + */ +typedef struct pm_hash_pattern_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * HashPatternNode#constant + * + * Represents the optional constant preceding the Hash. + * + * foo => Bar[a: 1, b: 2] + * ^^^ + * + * foo => Bar::Baz[a: 1, b: 2] + * ^^^^^^^^ + */ + struct pm_node *constant; + + /** + * HashPatternNode#elements + * + * Represents the explicit named hash keys and values. + * + * foo => { a: 1, b:, ** } + * ^^^^^^^^ + */ + struct pm_node_list elements; + + /** + * HashPatternNode#rest + * + * Represents the rest of the Hash keys and values. This can be named, unnamed, or explicitly forbidden via `**nil`, this last one results in a `NoKeywordsParameterNode`. + * + * foo => { a: 1, b:, **c } + * ^^^ + * + * foo => { a: 1, b:, ** } + * ^^ + * + * foo => { a: 1, b:, **nil } + * ^^^^^ + */ + struct pm_node *rest; + + /** + * HashPatternNode#opening_loc + * + * The location of the opening brace. + * + * foo => { a: 1 } + * ^ + * + * foo => Bar[a: 1] + * ^ + */ + pm_location_t opening_loc; + + /** + * HashPatternNode#closing_loc + * + * The location of the closing brace. + * + * foo => { a: 1 } + * ^ + * + * foo => Bar[a: 1] + * ^ + */ + pm_location_t closing_loc; +} pm_hash_pattern_node_t; + +/** + * IfNode + * + * Represents the use of the `if` keyword, either in the block form or the modifier form, or a ternary expression. + * + * bar if foo + * ^^^^^^^^^^ + * + * if foo then bar end + * ^^^^^^^^^^^^^^^^^^^ + * + * foo ? bar : baz + * ^^^^^^^^^^^^^^^ + * + * Type: ::PM_IF_NODE + * + * @extends pm_node_t + */ +typedef struct pm_if_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * IfNode#if_keyword_loc + * + * The location of the `if` keyword if present. + * + * bar if foo + * ^^ + * + * The `if_keyword_loc` field will be `nil` when the `IfNode` represents a ternary expression. + */ + pm_location_t if_keyword_loc; + + /** + * IfNode#predicate + * + * The node for the condition the `IfNode` is testing. + * + * if foo + * ^^^ + * bar + * end + * + * bar if foo + * ^^^ + * + * foo ? bar : baz + * ^^^ + */ + struct pm_node *predicate; + + /** + * IfNode#then_keyword_loc + * + * The location of the `then` keyword (if present) or the `?` in a ternary expression, `nil` otherwise. + * + * if foo then bar end + * ^^^^ + * + * a ? b : c + * ^ + */ + pm_location_t then_keyword_loc; + + /** + * IfNode#statements + * + * Represents the body of statements that will be executed when the predicate is evaluated as truthy. Will be `nil` when no body is provided. + * + * if foo + * bar + * ^^^ + * baz + * ^^^ + * end + */ + struct pm_statements_node *statements; + + /** + * IfNode#subsequent + * + * Represents an `ElseNode` or an `IfNode` when there is an `else` or an `elsif` in the `if` statement. + * + * if foo + * bar + * elsif baz + * ^^^^^^^^^ + * qux + * ^^^ + * end + * ^^^ + * + * if foo then bar else baz end + * ^^^^^^^^^^^^ + */ + struct pm_node *subsequent; + + /** + * IfNode#end_keyword_loc + * + * The location of the `end` keyword if present, `nil` otherwise. + * + * if foo + * bar + * end + * ^^^ + */ + pm_location_t end_keyword_loc; +} pm_if_node_t; + +/** + * ImaginaryNode + * + * Represents an imaginary number literal. + * + * 1.0i + * ^^^^ + * + * Type: ::PM_IMAGINARY_NODE + * + * @extends pm_node_t + */ +typedef struct pm_imaginary_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * ImaginaryNode#numeric + */ + struct pm_node *numeric; +} pm_imaginary_node_t; + +/** + * ImplicitNode + * + * Represents a node that is implicitly being added to the tree but doesn't correspond directly to a node in the source. + * + * { foo: } + * ^^^^ + * + * { Foo: } + * ^^^^ + * + * foo in { bar: } + * ^^^^ + * + * Type: ::PM_IMPLICIT_NODE + * + * @extends pm_node_t + */ +typedef struct pm_implicit_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * ImplicitNode#value + */ + struct pm_node *value; +} pm_implicit_node_t; + +/** + * ImplicitRestNode + * + * Represents using a trailing comma to indicate an implicit rest parameter. + * + * foo { |bar,| } + * ^ + * + * foo in [bar,] + * ^ + * + * for foo, in bar do end + * ^ + * + * foo, = bar + * ^ + * + * Type: ::PM_IMPLICIT_REST_NODE + * + * @extends pm_node_t + */ +typedef struct pm_implicit_rest_node { + /** The embedded base node. */ + pm_node_t base; + +} pm_implicit_rest_node_t; + +/** + * InNode + * + * Represents the use of the `in` keyword in a case statement. + * + * case a; in b then c end + * ^^^^^^^^^^^ + * + * Type: ::PM_IN_NODE + * + * @extends pm_node_t + */ +typedef struct pm_in_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * InNode#pattern + */ + struct pm_node *pattern; + + /** + * InNode#statements + */ + struct pm_statements_node *statements; + + /** + * InNode#in_loc + */ + pm_location_t in_loc; + + /** + * InNode#then_loc + */ + pm_location_t then_loc; +} pm_in_node_t; + +/** + * IndexAndWriteNode + * + * Represents the use of the `&&=` operator on a call to the `[]` method. + * + * foo.bar[baz] &&= value + * ^^^^^^^^^^^^^^^^^^^^^^ + * + * Type: ::PM_INDEX_AND_WRITE_NODE + + * Flags (#pm_call_node_flags): + * * ::PM_CALL_NODE_FLAGS_SAFE_NAVIGATION + * * ::PM_CALL_NODE_FLAGS_VARIABLE_CALL + * * ::PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE + * * ::PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY + * + * @extends pm_node_t + */ +typedef struct pm_index_and_write_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * IndexAndWriteNode#receiver + */ + struct pm_node *receiver; + + /** + * IndexAndWriteNode#call_operator_loc + */ + pm_location_t call_operator_loc; + + /** + * IndexAndWriteNode#opening_loc + */ + pm_location_t opening_loc; + + /** + * IndexAndWriteNode#arguments + */ + struct pm_arguments_node *arguments; + + /** + * IndexAndWriteNode#closing_loc + */ + pm_location_t closing_loc; + + /** + * IndexAndWriteNode#block + */ + struct pm_block_argument_node *block; + + /** + * IndexAndWriteNode#operator_loc + */ + pm_location_t operator_loc; + + /** + * IndexAndWriteNode#value + */ + struct pm_node *value; +} pm_index_and_write_node_t; + +/** + * IndexOperatorWriteNode + * + * Represents the use of an assignment operator on a call to `[]`. + * + * foo.bar[baz] += value + * ^^^^^^^^^^^^^^^^^^^^^ + * + * Type: ::PM_INDEX_OPERATOR_WRITE_NODE + + * Flags (#pm_call_node_flags): + * * ::PM_CALL_NODE_FLAGS_SAFE_NAVIGATION + * * ::PM_CALL_NODE_FLAGS_VARIABLE_CALL + * * ::PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE + * * ::PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY + * + * @extends pm_node_t + */ +typedef struct pm_index_operator_write_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * IndexOperatorWriteNode#receiver + */ + struct pm_node *receiver; + + /** + * IndexOperatorWriteNode#call_operator_loc + */ + pm_location_t call_operator_loc; + + /** + * IndexOperatorWriteNode#opening_loc + */ + pm_location_t opening_loc; + + /** + * IndexOperatorWriteNode#arguments + */ + struct pm_arguments_node *arguments; + + /** + * IndexOperatorWriteNode#closing_loc + */ + pm_location_t closing_loc; + + /** + * IndexOperatorWriteNode#block + */ + struct pm_block_argument_node *block; + + /** + * IndexOperatorWriteNode#binary_operator + */ + pm_constant_id_t binary_operator; + + /** + * IndexOperatorWriteNode#binary_operator_loc + */ + pm_location_t binary_operator_loc; + + /** + * IndexOperatorWriteNode#value + */ + struct pm_node *value; +} pm_index_operator_write_node_t; + +/** + * IndexOrWriteNode + * + * Represents the use of the `||=` operator on a call to `[]`. + * + * foo.bar[baz] ||= value + * ^^^^^^^^^^^^^^^^^^^^^^ + * + * Type: ::PM_INDEX_OR_WRITE_NODE + + * Flags (#pm_call_node_flags): + * * ::PM_CALL_NODE_FLAGS_SAFE_NAVIGATION + * * ::PM_CALL_NODE_FLAGS_VARIABLE_CALL + * * ::PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE + * * ::PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY + * + * @extends pm_node_t + */ +typedef struct pm_index_or_write_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * IndexOrWriteNode#receiver + */ + struct pm_node *receiver; + + /** + * IndexOrWriteNode#call_operator_loc + */ + pm_location_t call_operator_loc; + + /** + * IndexOrWriteNode#opening_loc + */ + pm_location_t opening_loc; + + /** + * IndexOrWriteNode#arguments + */ + struct pm_arguments_node *arguments; + + /** + * IndexOrWriteNode#closing_loc + */ + pm_location_t closing_loc; + + /** + * IndexOrWriteNode#block + */ + struct pm_block_argument_node *block; + + /** + * IndexOrWriteNode#operator_loc + */ + pm_location_t operator_loc; + + /** + * IndexOrWriteNode#value + */ + struct pm_node *value; +} pm_index_or_write_node_t; + +/** + * IndexTargetNode + * + * Represents assigning to an index. + * + * foo[bar], = 1 + * ^^^^^^^^ + * + * begin + * rescue => foo[bar] + * ^^^^^^^^ + * end + * + * for foo[bar] in baz do end + * ^^^^^^^^ + * + * Type: ::PM_INDEX_TARGET_NODE + + * Flags (#pm_call_node_flags): + * * ::PM_CALL_NODE_FLAGS_SAFE_NAVIGATION + * * ::PM_CALL_NODE_FLAGS_VARIABLE_CALL + * * ::PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE + * * ::PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY + * + * @extends pm_node_t + */ +typedef struct pm_index_target_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * IndexTargetNode#receiver + */ + struct pm_node *receiver; + + /** + * IndexTargetNode#opening_loc + */ + pm_location_t opening_loc; + + /** + * IndexTargetNode#arguments + */ + struct pm_arguments_node *arguments; + + /** + * IndexTargetNode#closing_loc + */ + pm_location_t closing_loc; + + /** + * IndexTargetNode#block + */ + struct pm_block_argument_node *block; +} pm_index_target_node_t; + +/** + * InstanceVariableAndWriteNode + * + * Represents the use of the `&&=` operator for assignment to an instance variable. + * + * @target &&= value + * ^^^^^^^^^^^^^^^^^ + * + * Type: ::PM_INSTANCE_VARIABLE_AND_WRITE_NODE + * + * @extends pm_node_t + */ +typedef struct pm_instance_variable_and_write_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * InstanceVariableAndWriteNode#name + */ + pm_constant_id_t name; + + /** + * InstanceVariableAndWriteNode#name_loc + */ + pm_location_t name_loc; + + /** + * InstanceVariableAndWriteNode#operator_loc + */ + pm_location_t operator_loc; + + /** + * InstanceVariableAndWriteNode#value + */ + struct pm_node *value; +} pm_instance_variable_and_write_node_t; + +/** + * InstanceVariableOperatorWriteNode + * + * Represents assigning to an instance variable using an operator that isn't `=`. + * + * @target += value + * ^^^^^^^^^^^^^^^^ + * + * Type: ::PM_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE + * + * @extends pm_node_t + */ +typedef struct pm_instance_variable_operator_write_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * InstanceVariableOperatorWriteNode#name + */ + pm_constant_id_t name; + + /** + * InstanceVariableOperatorWriteNode#name_loc + */ + pm_location_t name_loc; + + /** + * InstanceVariableOperatorWriteNode#binary_operator_loc + */ + pm_location_t binary_operator_loc; + + /** + * InstanceVariableOperatorWriteNode#value + */ + struct pm_node *value; + + /** + * InstanceVariableOperatorWriteNode#binary_operator + */ + pm_constant_id_t binary_operator; +} pm_instance_variable_operator_write_node_t; + +/** + * InstanceVariableOrWriteNode + * + * Represents the use of the `||=` operator for assignment to an instance variable. + * + * @target ||= value + * ^^^^^^^^^^^^^^^^^ + * + * Type: ::PM_INSTANCE_VARIABLE_OR_WRITE_NODE + * + * @extends pm_node_t + */ +typedef struct pm_instance_variable_or_write_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * InstanceVariableOrWriteNode#name + */ + pm_constant_id_t name; + + /** + * InstanceVariableOrWriteNode#name_loc + */ + pm_location_t name_loc; + + /** + * InstanceVariableOrWriteNode#operator_loc + */ + pm_location_t operator_loc; + + /** + * InstanceVariableOrWriteNode#value + */ + struct pm_node *value; +} pm_instance_variable_or_write_node_t; + +/** + * InstanceVariableReadNode + * + * Represents referencing an instance variable. + * + * @foo + * ^^^^ + * + * Type: ::PM_INSTANCE_VARIABLE_READ_NODE + * + * @extends pm_node_t + */ +typedef struct pm_instance_variable_read_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * InstanceVariableReadNode#name + * + * The name of the instance variable, which is a `@` followed by an [identifier](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#identifiers). + * + * @x # name `:@x` + * + * @_test # name `:@_test` + */ + pm_constant_id_t name; +} pm_instance_variable_read_node_t; + +/** + * InstanceVariableTargetNode + * + * Represents writing to an instance variable in a context that doesn't have an explicit value. + * + * @foo, @bar = baz + * ^^^^ ^^^^ + * + * Type: ::PM_INSTANCE_VARIABLE_TARGET_NODE + * + * @extends pm_node_t + */ +typedef struct pm_instance_variable_target_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * InstanceVariableTargetNode#name + */ + pm_constant_id_t name; +} pm_instance_variable_target_node_t; + +/** + * InstanceVariableWriteNode + * + * Represents writing to an instance variable. + * + * @foo = 1 + * ^^^^^^^^ + * + * Type: ::PM_INSTANCE_VARIABLE_WRITE_NODE + * + * @extends pm_node_t + */ +typedef struct pm_instance_variable_write_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * InstanceVariableWriteNode#name + * + * The name of the instance variable, which is a `@` followed by an [identifier](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#identifiers). + * + * @x = :y # name `:@x` + * + * @_foo = "bar" # name `@_foo` + */ + pm_constant_id_t name; + + /** + * InstanceVariableWriteNode#name_loc + * + * The location of the variable name. + * + * @_x = 1 + * ^^^ + */ + pm_location_t name_loc; + + /** + * InstanceVariableWriteNode#value + * + * The value to write to the instance variable. It can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression). + * + * @foo = :bar + * ^^^^ + * + * @_x = 1234 + * ^^^^ + */ + struct pm_node *value; + + /** + * InstanceVariableWriteNode#operator_loc + * + * The location of the `=` operator. + * + * @x = y + * ^ + */ + pm_location_t operator_loc; +} pm_instance_variable_write_node_t; + +/** + * IntegerNode + * + * Represents an integer number literal. + * + * 1 + * ^ + * + * Type: ::PM_INTEGER_NODE + + * Flags (#pm_integer_base_flags): + * * ::PM_INTEGER_BASE_FLAGS_BINARY + * * ::PM_INTEGER_BASE_FLAGS_DECIMAL + * * ::PM_INTEGER_BASE_FLAGS_OCTAL + * * ::PM_INTEGER_BASE_FLAGS_HEXADECIMAL + * + * @extends pm_node_t + */ +typedef struct pm_integer_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * IntegerNode#value + * + * The value of the integer literal as a number. + */ + pm_integer_t value; +} pm_integer_node_t; + +/** + * InterpolatedMatchLastLineNode + * + * Represents a regular expression literal that contains interpolation that is being used in the predicate of a conditional to implicitly match against the last line read by an IO object. + * + * if /foo #{bar} baz/ then end + * ^^^^^^^^^^^^^^^^ + * + * Type: ::PM_INTERPOLATED_MATCH_LAST_LINE_NODE + + * Flags (#pm_regular_expression_flags): + * * ::PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE + * * ::PM_REGULAR_EXPRESSION_FLAGS_EXTENDED + * * ::PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE + * * ::PM_REGULAR_EXPRESSION_FLAGS_ONCE + * * ::PM_REGULAR_EXPRESSION_FLAGS_EUC_JP + * * ::PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT + * * ::PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J + * * ::PM_REGULAR_EXPRESSION_FLAGS_UTF_8 + * * ::PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING + * * ::PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING + * * ::PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING + * + * @extends pm_node_t + */ +typedef struct pm_interpolated_match_last_line_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * InterpolatedMatchLastLineNode#opening_loc + */ + pm_location_t opening_loc; + + /** + * InterpolatedMatchLastLineNode#parts + */ + struct pm_node_list parts; + + /** + * InterpolatedMatchLastLineNode#closing_loc + */ + pm_location_t closing_loc; +} pm_interpolated_match_last_line_node_t; + +/** + * InterpolatedRegularExpressionNode + * + * Represents a regular expression literal that contains interpolation. + * + * /foo #{bar} baz/ + * ^^^^^^^^^^^^^^^^ + * + * Type: ::PM_INTERPOLATED_REGULAR_EXPRESSION_NODE + + * Flags (#pm_regular_expression_flags): + * * ::PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE + * * ::PM_REGULAR_EXPRESSION_FLAGS_EXTENDED + * * ::PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE + * * ::PM_REGULAR_EXPRESSION_FLAGS_ONCE + * * ::PM_REGULAR_EXPRESSION_FLAGS_EUC_JP + * * ::PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT + * * ::PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J + * * ::PM_REGULAR_EXPRESSION_FLAGS_UTF_8 + * * ::PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING + * * ::PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING + * * ::PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING + * + * @extends pm_node_t + */ +typedef struct pm_interpolated_regular_expression_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * InterpolatedRegularExpressionNode#opening_loc + */ + pm_location_t opening_loc; + + /** + * InterpolatedRegularExpressionNode#parts + */ + struct pm_node_list parts; + + /** + * InterpolatedRegularExpressionNode#closing_loc + */ + pm_location_t closing_loc; +} pm_interpolated_regular_expression_node_t; + +/** + * InterpolatedStringNode + * + * Represents a string literal that contains interpolation. + * + * "foo #{bar} baz" + * ^^^^^^^^^^^^^^^^ + * + * Type: ::PM_INTERPOLATED_STRING_NODE + + * Flags (#pm_interpolated_string_node_flags): + * * ::PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN + * * ::PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE + * + * @extends pm_node_t + */ +typedef struct pm_interpolated_string_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * InterpolatedStringNode#opening_loc + */ + pm_location_t opening_loc; + + /** + * InterpolatedStringNode#parts + */ + struct pm_node_list parts; + + /** + * InterpolatedStringNode#closing_loc + */ + pm_location_t closing_loc; +} pm_interpolated_string_node_t; + +/** + * InterpolatedSymbolNode + * + * Represents a symbol literal that contains interpolation. + * + * :"foo #{bar} baz" + * ^^^^^^^^^^^^^^^^^ + * + * Type: ::PM_INTERPOLATED_SYMBOL_NODE + * + * @extends pm_node_t + */ +typedef struct pm_interpolated_symbol_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * InterpolatedSymbolNode#opening_loc + */ + pm_location_t opening_loc; + + /** + * InterpolatedSymbolNode#parts + */ + struct pm_node_list parts; + + /** + * InterpolatedSymbolNode#closing_loc + */ + pm_location_t closing_loc; +} pm_interpolated_symbol_node_t; + +/** + * InterpolatedXStringNode + * + * Represents an xstring literal that contains interpolation. + * + * `foo #{bar} baz` + * ^^^^^^^^^^^^^^^^ + * + * Type: ::PM_INTERPOLATED_X_STRING_NODE + * + * @extends pm_node_t + */ +typedef struct pm_interpolated_x_string_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * InterpolatedXStringNode#opening_loc + */ + pm_location_t opening_loc; + + /** + * InterpolatedXStringNode#parts + */ + struct pm_node_list parts; + + /** + * InterpolatedXStringNode#closing_loc + */ + pm_location_t closing_loc; +} pm_interpolated_x_string_node_t; + +/** + * ItLocalVariableReadNode + * + * Represents reading from the implicit `it` local variable. + * + * -> { it } + * ^^ + * + * Type: ::PM_IT_LOCAL_VARIABLE_READ_NODE + * + * @extends pm_node_t + */ +typedef struct pm_it_local_variable_read_node { + /** The embedded base node. */ + pm_node_t base; + +} pm_it_local_variable_read_node_t; + +/** + * ItParametersNode + * + * Represents an implicit set of parameters through the use of the `it` keyword within a block or lambda. + * + * -> { it + it } + * ^^^^^^^^^^^^^^ + * + * Type: ::PM_IT_PARAMETERS_NODE + * + * @extends pm_node_t + */ +typedef struct pm_it_parameters_node { + /** The embedded base node. */ + pm_node_t base; + +} pm_it_parameters_node_t; + +/** + * KeywordHashNode + * + * Represents a hash literal without opening and closing braces. + * + * foo(a: b) + * ^^^^ + * + * Type: ::PM_KEYWORD_HASH_NODE + + * Flags (#pm_keyword_hash_node_flags): + * * ::PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS + * + * @extends pm_node_t + */ +typedef struct pm_keyword_hash_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * KeywordHashNode#elements + */ + struct pm_node_list elements; +} pm_keyword_hash_node_t; + +/** + * KeywordRestParameterNode + * + * Represents a keyword rest parameter to a method, block, or lambda definition. + * + * def a(**b) + * ^^^ + * end + * + * Type: ::PM_KEYWORD_REST_PARAMETER_NODE + + * Flags (#pm_parameter_flags): + * * ::PM_PARAMETER_FLAGS_REPEATED_PARAMETER + * + * @extends pm_node_t + */ +typedef struct pm_keyword_rest_parameter_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * KeywordRestParameterNode#name + */ + pm_constant_id_t name; + + /** + * KeywordRestParameterNode#name_loc + */ + pm_location_t name_loc; + + /** + * KeywordRestParameterNode#operator_loc + */ + pm_location_t operator_loc; +} pm_keyword_rest_parameter_node_t; + +/** + * LambdaNode + * + * Represents using a lambda literal (not the lambda method call). + * + * ->(value) { value * 2 } + * ^^^^^^^^^^^^^^^^^^^^^^^ + * + * Type: ::PM_LAMBDA_NODE + * + * @extends pm_node_t + */ +typedef struct pm_lambda_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * LambdaNode#locals + */ + pm_constant_id_list_t locals; + + /** + * LambdaNode#operator_loc + */ + pm_location_t operator_loc; + + /** + * LambdaNode#opening_loc + */ + pm_location_t opening_loc; + + /** + * LambdaNode#closing_loc + */ + pm_location_t closing_loc; + + /** + * LambdaNode#parameters + */ + struct pm_node *parameters; + + /** + * LambdaNode#body + */ + struct pm_node *body; +} pm_lambda_node_t; + +/** + * LocalVariableAndWriteNode + * + * Represents the use of the `&&=` operator for assignment to a local variable. + * + * target &&= value + * ^^^^^^^^^^^^^^^^ + * + * Type: ::PM_LOCAL_VARIABLE_AND_WRITE_NODE + * + * @extends pm_node_t + */ +typedef struct pm_local_variable_and_write_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * LocalVariableAndWriteNode#name_loc + */ + pm_location_t name_loc; + + /** + * LocalVariableAndWriteNode#operator_loc + */ + pm_location_t operator_loc; + + /** + * LocalVariableAndWriteNode#value + */ + struct pm_node *value; + + /** + * LocalVariableAndWriteNode#name + */ + pm_constant_id_t name; + + /** + * LocalVariableAndWriteNode#depth + */ + uint32_t depth; +} pm_local_variable_and_write_node_t; + +/** + * LocalVariableOperatorWriteNode + * + * Represents assigning to a local variable using an operator that isn't `=`. + * + * target += value + * ^^^^^^^^^^^^^^^ + * + * Type: ::PM_LOCAL_VARIABLE_OPERATOR_WRITE_NODE + * + * @extends pm_node_t + */ +typedef struct pm_local_variable_operator_write_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * LocalVariableOperatorWriteNode#name_loc + */ + pm_location_t name_loc; + + /** + * LocalVariableOperatorWriteNode#binary_operator_loc + */ + pm_location_t binary_operator_loc; + + /** + * LocalVariableOperatorWriteNode#value + */ + struct pm_node *value; + + /** + * LocalVariableOperatorWriteNode#name + */ + pm_constant_id_t name; + + /** + * LocalVariableOperatorWriteNode#binary_operator + */ + pm_constant_id_t binary_operator; + + /** + * LocalVariableOperatorWriteNode#depth + */ + uint32_t depth; +} pm_local_variable_operator_write_node_t; + +/** + * LocalVariableOrWriteNode + * + * Represents the use of the `||=` operator for assignment to a local variable. + * + * target ||= value + * ^^^^^^^^^^^^^^^^ + * + * Type: ::PM_LOCAL_VARIABLE_OR_WRITE_NODE + * + * @extends pm_node_t + */ +typedef struct pm_local_variable_or_write_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * LocalVariableOrWriteNode#name_loc + */ + pm_location_t name_loc; + + /** + * LocalVariableOrWriteNode#operator_loc + */ + pm_location_t operator_loc; + + /** + * LocalVariableOrWriteNode#value + */ + struct pm_node *value; + + /** + * LocalVariableOrWriteNode#name + */ + pm_constant_id_t name; + + /** + * LocalVariableOrWriteNode#depth + */ + uint32_t depth; +} pm_local_variable_or_write_node_t; + +/** + * LocalVariableReadNode + * + * Represents reading a local variable. Note that this requires that a local variable of the same name has already been written to in the same scope, otherwise it is parsed as a method call. + * + * foo + * ^^^ + * + * Type: ::PM_LOCAL_VARIABLE_READ_NODE + * + * @extends pm_node_t + */ +typedef struct pm_local_variable_read_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * LocalVariableReadNode#name + * + * The name of the local variable, which is an [identifier](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#identifiers). + * + * x # name `:x` + * + * _Test # name `:_Test` + * + * Note that this can also be an underscore followed by a number for the default block parameters. + * + * _1 # name `:_1` + */ + pm_constant_id_t name; + + /** + * LocalVariableReadNode#depth + * + * The number of visible scopes that should be searched to find the origin of this local variable. + * + * foo = 1; foo # depth 0 + * + * bar = 2; tap { bar } # depth 1 + * + * The specific rules for calculating the depth may differ from individual Ruby implementations, as they are not specified by the language. For more information, see [the Prism documentation](https://github.com/ruby/prism/blob/main/docs/local_variable_depth.md). + */ + uint32_t depth; +} pm_local_variable_read_node_t; + +/** + * LocalVariableTargetNode + * + * Represents writing to a local variable in a context that doesn't have an explicit value. + * + * foo, bar = baz + * ^^^ ^^^ + * + * foo => baz + * ^^^ + * + * Type: ::PM_LOCAL_VARIABLE_TARGET_NODE + * + * @extends pm_node_t + */ +typedef struct pm_local_variable_target_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * LocalVariableTargetNode#name + */ + pm_constant_id_t name; + + /** + * LocalVariableTargetNode#depth + */ + uint32_t depth; +} pm_local_variable_target_node_t; + +/** + * LocalVariableWriteNode + * + * Represents writing to a local variable. + * + * foo = 1 + * ^^^^^^^ + * + * Type: ::PM_LOCAL_VARIABLE_WRITE_NODE + * + * @extends pm_node_t + */ +typedef struct pm_local_variable_write_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * LocalVariableWriteNode#name + * + * The name of the local variable, which is an [identifier](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#identifiers). + * + * foo = :bar # name `:foo` + * + * abc = 123 # name `:abc` + */ + pm_constant_id_t name; + + /** + * LocalVariableWriteNode#depth + * + * The number of semantic scopes we have to traverse to find the declaration of this variable. + * + * foo = 1 # depth 0 + * + * tap { foo = 1 } # depth 1 + * + * The specific rules for calculating the depth may differ from individual Ruby implementations, as they are not specified by the language. For more information, see [the Prism documentation](https://github.com/ruby/prism/blob/main/docs/local_variable_depth.md). + */ + uint32_t depth; + + /** + * LocalVariableWriteNode#name_loc + * + * The location of the variable name. + * + * foo = :bar + * ^^^ + */ + pm_location_t name_loc; + + /** + * LocalVariableWriteNode#value + * + * The value to write to the local variable. It can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression). + * + * foo = :bar + * ^^^^ + * + * abc = 1234 + * ^^^^ + * + * Note that since the name of a local variable is known before the value is parsed, it is valid for a local variable to appear within the value of its own write. + * + * foo = foo + */ + struct pm_node *value; + + /** + * LocalVariableWriteNode#operator_loc + * + * The location of the `=` operator. + * + * x = :y + * ^ + */ + pm_location_t operator_loc; +} pm_local_variable_write_node_t; + +/** + * MatchLastLineNode + * + * Represents a regular expression literal used in the predicate of a conditional to implicitly match against the last line read by an IO object. + * + * if /foo/i then end + * ^^^^^^ + * + * Type: ::PM_MATCH_LAST_LINE_NODE + + * Flags (#pm_regular_expression_flags): + * * ::PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE + * * ::PM_REGULAR_EXPRESSION_FLAGS_EXTENDED + * * ::PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE + * * ::PM_REGULAR_EXPRESSION_FLAGS_ONCE + * * ::PM_REGULAR_EXPRESSION_FLAGS_EUC_JP + * * ::PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT + * * ::PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J + * * ::PM_REGULAR_EXPRESSION_FLAGS_UTF_8 + * * ::PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING + * * ::PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING + * * ::PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING + * + * @extends pm_node_t + */ +typedef struct pm_match_last_line_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * MatchLastLineNode#opening_loc + */ + pm_location_t opening_loc; + + /** + * MatchLastLineNode#content_loc + */ + pm_location_t content_loc; + + /** + * MatchLastLineNode#closing_loc + */ + pm_location_t closing_loc; + + /** + * MatchLastLineNode#unescaped + */ + pm_string_t unescaped; +} pm_match_last_line_node_t; + +/** + * MatchPredicateNode + * + * Represents the use of the modifier `in` operator. + * + * foo in bar + * ^^^^^^^^^^ + * + * Type: ::PM_MATCH_PREDICATE_NODE + * + * @extends pm_node_t + */ +typedef struct pm_match_predicate_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * MatchPredicateNode#value + */ + struct pm_node *value; + + /** + * MatchPredicateNode#pattern + */ + struct pm_node *pattern; + + /** + * MatchPredicateNode#operator_loc + */ + pm_location_t operator_loc; +} pm_match_predicate_node_t; + +/** + * MatchRequiredNode + * + * Represents the use of the `=>` operator. + * + * foo => bar + * ^^^^^^^^^^ + * + * Type: ::PM_MATCH_REQUIRED_NODE + * + * @extends pm_node_t + */ +typedef struct pm_match_required_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * MatchRequiredNode#value + * + * Represents the left-hand side of the operator. + * + * foo => bar + * ^^^ + */ + struct pm_node *value; + + /** + * MatchRequiredNode#pattern + * + * Represents the right-hand side of the operator. The type of the node depends on the expression. + * + * Anything that looks like a local variable name (including `_`) will result in a `LocalVariableTargetNode`. + * + * foo => a # This is equivalent to writing `a = foo` + * ^ + * + * Using an explicit `Array` or combining expressions with `,` will result in a `ArrayPatternNode`. This can be preceded by a constant. + * + * foo => [a] + * ^^^ + * + * foo => a, b + * ^^^^ + * + * foo => Bar[a, b] + * ^^^^^^^^^ + * + * If the array pattern contains at least two wildcard matches, a `FindPatternNode` is created instead. + * + * foo => *, 1, *a + * ^^^^^ + * + * Using an explicit `Hash` or a constant with square brackets and hash keys in the square brackets will result in a `HashPatternNode`. + * + * foo => { a: 1, b: } + * + * foo => Bar[a: 1, b:] + * + * foo => Bar[**] + * + * To use any variable that needs run time evaluation, pinning is required. This results in a `PinnedVariableNode` + * + * foo => ^a + * ^^ + * + * Similar, any expression can be used with pinning. This results in a `PinnedExpressionNode`. + * + * foo => ^(a + 1) + * + * Anything else will result in the regular node for that expression, for example a `ConstantReadNode`. + * + * foo => CONST + */ + struct pm_node *pattern; + + /** + * MatchRequiredNode#operator_loc + * + * The location of the operator. + * + * foo => bar + * ^^ + */ + pm_location_t operator_loc; +} pm_match_required_node_t; + +/** + * MatchWriteNode + * + * Represents writing local variables using a regular expression match with named capture groups. + * + * /(?bar)/ =~ baz + * ^^^^^^^^^^^^^^^^^^^^ + * + * Type: ::PM_MATCH_WRITE_NODE + * + * @extends pm_node_t + */ +typedef struct pm_match_write_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * MatchWriteNode#call + */ + struct pm_call_node *call; + + /** + * MatchWriteNode#targets + */ + struct pm_node_list targets; +} pm_match_write_node_t; + +/** + * MissingNode + * + * Represents a node that is missing from the source and results in a syntax error. + * + * Type: ::PM_MISSING_NODE + * + * @extends pm_node_t + */ +typedef struct pm_missing_node { + /** The embedded base node. */ + pm_node_t base; + +} pm_missing_node_t; + +/** + * ModuleNode + * + * Represents a module declaration involving the `module` keyword. + * + * module Foo end + * ^^^^^^^^^^^^^^ + * + * Type: ::PM_MODULE_NODE + * + * @extends pm_node_t + */ +typedef struct pm_module_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * ModuleNode#locals + */ + pm_constant_id_list_t locals; + + /** + * ModuleNode#module_keyword_loc + */ + pm_location_t module_keyword_loc; + + /** + * ModuleNode#constant_path + */ + struct pm_node *constant_path; + + /** + * ModuleNode#body + */ + struct pm_node *body; + + /** + * ModuleNode#end_keyword_loc + */ + pm_location_t end_keyword_loc; + + /** + * ModuleNode#name + */ + pm_constant_id_t name; +} pm_module_node_t; + +/** + * MultiTargetNode + * + * Represents a multi-target expression. + * + * a, (b, c) = 1, 2, 3 + * ^^^^^^ + * + * This can be a part of `MultiWriteNode` as above, or the target of a `for` loop + * + * for a, b in [[1, 2], [3, 4]] + * ^^^^ + * + * Type: ::PM_MULTI_TARGET_NODE + * + * @extends pm_node_t + */ +typedef struct pm_multi_target_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * MultiTargetNode#lefts + * + * Represents the targets expressions before a splat node. + * + * a, (b, c, *) = 1, 2, 3, 4, 5 + * ^^^^ + * + * The splat node can be absent, in that case all target expressions are in the left field. + * + * a, (b, c) = 1, 2, 3, 4, 5 + * ^^^^ + */ + struct pm_node_list lefts; + + /** + * MultiTargetNode#rest + * + * Represents a splat node in the target expression. + * + * a, (b, *c) = 1, 2, 3, 4 + * ^^ + * + * The variable can be empty, this results in a `SplatNode` with a `nil` expression field. + * + * a, (b, *) = 1, 2, 3, 4 + * ^ + * + * If the `*` is omitted, this field will contain an `ImplicitRestNode` + * + * a, (b,) = 1, 2, 3, 4 + * ^ + */ + struct pm_node *rest; + + /** + * MultiTargetNode#rights + * + * Represents the targets expressions after a splat node. + * + * a, (*, b, c) = 1, 2, 3, 4, 5 + * ^^^^ + */ + struct pm_node_list rights; + + /** + * MultiTargetNode#lparen_loc + * + * The location of the opening parenthesis. + * + * a, (b, c) = 1, 2, 3 + * ^ + */ + pm_location_t lparen_loc; + + /** + * MultiTargetNode#rparen_loc + * + * The location of the closing parenthesis. + * + * a, (b, c) = 1, 2, 3 + * ^ + */ + pm_location_t rparen_loc; +} pm_multi_target_node_t; + +/** + * MultiWriteNode + * + * Represents a write to a multi-target expression. + * + * a, b, c = 1, 2, 3 + * ^^^^^^^^^^^^^^^^^ + * + * Type: ::PM_MULTI_WRITE_NODE + * + * @extends pm_node_t + */ +typedef struct pm_multi_write_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * MultiWriteNode#lefts + * + * Represents the targets expressions before a splat node. + * + * a, b, * = 1, 2, 3, 4, 5 + * ^^^^ + * + * The splat node can be absent, in that case all target expressions are in the left field. + * + * a, b, c = 1, 2, 3, 4, 5 + * ^^^^^^^ + */ + struct pm_node_list lefts; + + /** + * MultiWriteNode#rest + * + * Represents a splat node in the target expression. + * + * a, b, *c = 1, 2, 3, 4 + * ^^ + * + * The variable can be empty, this results in a `SplatNode` with a `nil` expression field. + * + * a, b, * = 1, 2, 3, 4 + * ^ + * + * If the `*` is omitted, this field will contain an `ImplicitRestNode` + * + * a, b, = 1, 2, 3, 4 + * ^ + */ + struct pm_node *rest; + + /** + * MultiWriteNode#rights + * + * Represents the targets expressions after a splat node. + * + * a, *, b, c = 1, 2, 3, 4, 5 + * ^^^^ + */ + struct pm_node_list rights; + + /** + * MultiWriteNode#lparen_loc + * + * The location of the opening parenthesis. + * + * (a, b, c) = 1, 2, 3 + * ^ + */ + pm_location_t lparen_loc; + + /** + * MultiWriteNode#rparen_loc + * + * The location of the closing parenthesis. + * + * (a, b, c) = 1, 2, 3 + * ^ + */ + pm_location_t rparen_loc; + + /** + * MultiWriteNode#operator_loc + * + * The location of the operator. + * + * a, b, c = 1, 2, 3 + * ^ + */ + pm_location_t operator_loc; + + /** + * MultiWriteNode#value + * + * The value to write to the targets. It can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression). + * + * a, b, c = 1, 2, 3 + * ^^^^^^^ + */ + struct pm_node *value; +} pm_multi_write_node_t; + +/** + * NextNode + * + * Represents the use of the `next` keyword. + * + * next 1 + * ^^^^^^ + * + * Type: ::PM_NEXT_NODE + * + * @extends pm_node_t + */ +typedef struct pm_next_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * NextNode#arguments + */ + struct pm_arguments_node *arguments; + + /** + * NextNode#keyword_loc + */ + pm_location_t keyword_loc; +} pm_next_node_t; + +/** + * NilNode + * + * Represents the use of the `nil` keyword. + * + * nil + * ^^^ + * + * Type: ::PM_NIL_NODE + * + * @extends pm_node_t + */ +typedef struct pm_nil_node { + /** The embedded base node. */ + pm_node_t base; + +} pm_nil_node_t; + +/** + * NoKeywordsParameterNode + * + * Represents the use of `**nil` inside method arguments. + * + * def a(**nil) + * ^^^^^ + * end + * + * Type: ::PM_NO_KEYWORDS_PARAMETER_NODE + * + * @extends pm_node_t + */ +typedef struct pm_no_keywords_parameter_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * NoKeywordsParameterNode#operator_loc + */ + pm_location_t operator_loc; + + /** + * NoKeywordsParameterNode#keyword_loc + */ + pm_location_t keyword_loc; +} pm_no_keywords_parameter_node_t; + +/** + * NumberedParametersNode + * + * Represents an implicit set of parameters through the use of numbered parameters within a block or lambda. + * + * -> { _1 + _2 } + * ^^^^^^^^^^^^^^ + * + * Type: ::PM_NUMBERED_PARAMETERS_NODE + * + * @extends pm_node_t + */ +typedef struct pm_numbered_parameters_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * NumberedParametersNode#maximum + */ + uint8_t maximum; +} pm_numbered_parameters_node_t; + +/** + * NumberedReferenceReadNode + * + * Represents reading a numbered reference to a capture in the previous match. + * + * $1 + * ^^ + * + * Type: ::PM_NUMBERED_REFERENCE_READ_NODE + * + * @extends pm_node_t + */ +typedef struct pm_numbered_reference_read_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * NumberedReferenceReadNode#number + * + * The (1-indexed, from the left) number of the capture group. Numbered references that are too large result in this value being `0`. + * + * $1 # number `1` + * + * $5432 # number `5432` + * + * $4294967296 # number `0` + */ + uint32_t number; +} pm_numbered_reference_read_node_t; + +/** + * OptionalKeywordParameterNode + * + * Represents an optional keyword parameter to a method, block, or lambda definition. + * + * def a(b: 1) + * ^^^^ + * end + * + * Type: ::PM_OPTIONAL_KEYWORD_PARAMETER_NODE + + * Flags (#pm_parameter_flags): + * * ::PM_PARAMETER_FLAGS_REPEATED_PARAMETER + * + * @extends pm_node_t + */ +typedef struct pm_optional_keyword_parameter_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * OptionalKeywordParameterNode#name + */ + pm_constant_id_t name; + + /** + * OptionalKeywordParameterNode#name_loc + */ + pm_location_t name_loc; + + /** + * OptionalKeywordParameterNode#value + */ + struct pm_node *value; +} pm_optional_keyword_parameter_node_t; + +/** + * OptionalParameterNode + * + * Represents an optional parameter to a method, block, or lambda definition. + * + * def a(b = 1) + * ^^^^^ + * end + * + * Type: ::PM_OPTIONAL_PARAMETER_NODE + + * Flags (#pm_parameter_flags): + * * ::PM_PARAMETER_FLAGS_REPEATED_PARAMETER + * + * @extends pm_node_t + */ +typedef struct pm_optional_parameter_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * OptionalParameterNode#name + */ + pm_constant_id_t name; + + /** + * OptionalParameterNode#name_loc + */ + pm_location_t name_loc; + + /** + * OptionalParameterNode#operator_loc + */ + pm_location_t operator_loc; + + /** + * OptionalParameterNode#value + */ + struct pm_node *value; +} pm_optional_parameter_node_t; + +/** + * OrNode + * + * Represents the use of the `||` operator or the `or` keyword. + * + * left or right + * ^^^^^^^^^^^^^ + * + * Type: ::PM_OR_NODE + * + * @extends pm_node_t + */ +typedef struct pm_or_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * OrNode#left + * + * Represents the left side of the expression. It can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression). + * + * left or right + * ^^^^ + * + * 1 || 2 + * ^ + */ + struct pm_node *left; + + /** + * OrNode#right + * + * Represents the right side of the expression. + * + * left || right + * ^^^^^ + * + * 1 or 2 + * ^ + */ + struct pm_node *right; + + /** + * OrNode#operator_loc + * + * The location of the `or` keyword or the `||` operator. + * + * left or right + * ^^ + */ + pm_location_t operator_loc; +} pm_or_node_t; + +/** + * ParametersNode + * + * Represents the list of parameters on a method, block, or lambda definition. + * + * def a(b, c, d) + * ^^^^^^^ + * end + * + * Type: ::PM_PARAMETERS_NODE + * + * @extends pm_node_t + */ +typedef struct pm_parameters_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * ParametersNode#requireds + */ + struct pm_node_list requireds; + + /** + * ParametersNode#optionals + */ + struct pm_node_list optionals; + + /** + * ParametersNode#rest + */ + struct pm_node *rest; + + /** + * ParametersNode#posts + */ + struct pm_node_list posts; + + /** + * ParametersNode#keywords + */ + struct pm_node_list keywords; + + /** + * ParametersNode#keyword_rest + */ + struct pm_node *keyword_rest; + + /** + * ParametersNode#block + */ + struct pm_block_parameter_node *block; +} pm_parameters_node_t; + +/** + * ParenthesesNode + * + * Represents a parenthesized expression + * + * (10 + 34) + * ^^^^^^^^^ + * + * Type: ::PM_PARENTHESES_NODE + + * Flags (#pm_parentheses_node_flags): + * * ::PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS + * + * @extends pm_node_t + */ +typedef struct pm_parentheses_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * ParenthesesNode#body + */ + struct pm_node *body; + + /** + * ParenthesesNode#opening_loc + */ + pm_location_t opening_loc; + + /** + * ParenthesesNode#closing_loc + */ + pm_location_t closing_loc; +} pm_parentheses_node_t; + +/** + * PinnedExpressionNode + * + * Represents the use of the `^` operator for pinning an expression in a pattern matching expression. + * + * foo in ^(bar) + * ^^^^^^ + * + * Type: ::PM_PINNED_EXPRESSION_NODE + * + * @extends pm_node_t + */ +typedef struct pm_pinned_expression_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * PinnedExpressionNode#expression + * + * The expression used in the pinned expression + * + * foo in ^(bar) + * ^^^ + */ + struct pm_node *expression; + + /** + * PinnedExpressionNode#operator_loc + * + * The location of the `^` operator + * + * foo in ^(bar) + * ^ + */ + pm_location_t operator_loc; + + /** + * PinnedExpressionNode#lparen_loc + * + * The location of the opening parenthesis. + * + * foo in ^(bar) + * ^ + */ + pm_location_t lparen_loc; + + /** + * PinnedExpressionNode#rparen_loc + * + * The location of the closing parenthesis. + * + * foo in ^(bar) + * ^ + */ + pm_location_t rparen_loc; +} pm_pinned_expression_node_t; + +/** + * PinnedVariableNode + * + * Represents the use of the `^` operator for pinning a variable in a pattern matching expression. + * + * foo in ^bar + * ^^^^ + * + * Type: ::PM_PINNED_VARIABLE_NODE + * + * @extends pm_node_t + */ +typedef struct pm_pinned_variable_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * PinnedVariableNode#variable + * + * The variable used in the pinned expression + * + * foo in ^bar + * ^^^ + */ + struct pm_node *variable; + + /** + * PinnedVariableNode#operator_loc + * + * The location of the `^` operator + * + * foo in ^bar + * ^ + */ + pm_location_t operator_loc; +} pm_pinned_variable_node_t; + +/** + * PostExecutionNode + * + * Represents the use of the `END` keyword. + * + * END { foo } + * ^^^^^^^^^^^ + * + * Type: ::PM_POST_EXECUTION_NODE + * + * @extends pm_node_t + */ +typedef struct pm_post_execution_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * PostExecutionNode#statements + */ + struct pm_statements_node *statements; + + /** + * PostExecutionNode#keyword_loc + */ + pm_location_t keyword_loc; + + /** + * PostExecutionNode#opening_loc + */ + pm_location_t opening_loc; + + /** + * PostExecutionNode#closing_loc + */ + pm_location_t closing_loc; +} pm_post_execution_node_t; + +/** + * PreExecutionNode + * + * Represents the use of the `BEGIN` keyword. + * + * BEGIN { foo } + * ^^^^^^^^^^^^^ + * + * Type: ::PM_PRE_EXECUTION_NODE + * + * @extends pm_node_t + */ +typedef struct pm_pre_execution_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * PreExecutionNode#statements + */ + struct pm_statements_node *statements; + + /** + * PreExecutionNode#keyword_loc + */ + pm_location_t keyword_loc; + + /** + * PreExecutionNode#opening_loc + */ + pm_location_t opening_loc; + + /** + * PreExecutionNode#closing_loc + */ + pm_location_t closing_loc; +} pm_pre_execution_node_t; + +/** + * ProgramNode + * + * The top level node of any parse tree. + * + * Type: ::PM_PROGRAM_NODE + * + * @extends pm_node_t + */ +typedef struct pm_program_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * ProgramNode#locals + */ + pm_constant_id_list_t locals; + + /** + * ProgramNode#statements + */ + struct pm_statements_node *statements; +} pm_program_node_t; + +/** + * RangeNode + * + * Represents the use of the `..` or `...` operators. + * + * 1..2 + * ^^^^ + * + * c if a =~ /left/ ... b =~ /right/ + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * + * Type: ::PM_RANGE_NODE + + * Flags (#pm_range_flags): + * * ::PM_RANGE_FLAGS_EXCLUDE_END + * + * @extends pm_node_t + */ +typedef struct pm_range_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * RangeNode#left + * + * The left-hand side of the range, if present. It can be either `nil` or any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression). + * + * 1... + * ^ + * + * hello...goodbye + * ^^^^^ + */ + struct pm_node *left; + + /** + * RangeNode#right + * + * The right-hand side of the range, if present. It can be either `nil` or any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression). + * + * ..5 + * ^ + * + * 1...foo + * ^^^ + * If neither right-hand or left-hand side was included, this will be a MissingNode. + */ + struct pm_node *right; + + /** + * RangeNode#operator_loc + * + * The location of the `..` or `...` operator. + */ + pm_location_t operator_loc; +} pm_range_node_t; + +/** + * RationalNode + * + * Represents a rational number literal. + * + * 1.0r + * ^^^^ + * + * Type: ::PM_RATIONAL_NODE + + * Flags (#pm_integer_base_flags): + * * ::PM_INTEGER_BASE_FLAGS_BINARY + * * ::PM_INTEGER_BASE_FLAGS_DECIMAL + * * ::PM_INTEGER_BASE_FLAGS_OCTAL + * * ::PM_INTEGER_BASE_FLAGS_HEXADECIMAL + * + * @extends pm_node_t + */ +typedef struct pm_rational_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * RationalNode#numerator + * + * The numerator of the rational number. + * + * 1.5r # numerator 3 + */ + pm_integer_t numerator; + + /** + * RationalNode#denominator + * + * The denominator of the rational number. + * + * 1.5r # denominator 2 + */ + pm_integer_t denominator; +} pm_rational_node_t; + +/** + * RedoNode + * + * Represents the use of the `redo` keyword. + * + * redo + * ^^^^ + * + * Type: ::PM_REDO_NODE + * + * @extends pm_node_t + */ +typedef struct pm_redo_node { + /** The embedded base node. */ + pm_node_t base; + +} pm_redo_node_t; + +/** + * RegularExpressionNode + * + * Represents a regular expression literal with no interpolation. + * + * /foo/i + * ^^^^^^ + * + * Type: ::PM_REGULAR_EXPRESSION_NODE + + * Flags (#pm_regular_expression_flags): + * * ::PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE + * * ::PM_REGULAR_EXPRESSION_FLAGS_EXTENDED + * * ::PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE + * * ::PM_REGULAR_EXPRESSION_FLAGS_ONCE + * * ::PM_REGULAR_EXPRESSION_FLAGS_EUC_JP + * * ::PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT + * * ::PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J + * * ::PM_REGULAR_EXPRESSION_FLAGS_UTF_8 + * * ::PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING + * * ::PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING + * * ::PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING + * + * @extends pm_node_t + */ +typedef struct pm_regular_expression_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * RegularExpressionNode#opening_loc + */ + pm_location_t opening_loc; + + /** + * RegularExpressionNode#content_loc + */ + pm_location_t content_loc; + + /** + * RegularExpressionNode#closing_loc + */ + pm_location_t closing_loc; + + /** + * RegularExpressionNode#unescaped + */ + pm_string_t unescaped; +} pm_regular_expression_node_t; + +/** + * RequiredKeywordParameterNode + * + * Represents a required keyword parameter to a method, block, or lambda definition. + * + * def a(b: ) + * ^^ + * end + * + * Type: ::PM_REQUIRED_KEYWORD_PARAMETER_NODE + + * Flags (#pm_parameter_flags): + * * ::PM_PARAMETER_FLAGS_REPEATED_PARAMETER + * + * @extends pm_node_t + */ +typedef struct pm_required_keyword_parameter_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * RequiredKeywordParameterNode#name + */ + pm_constant_id_t name; + + /** + * RequiredKeywordParameterNode#name_loc + */ + pm_location_t name_loc; +} pm_required_keyword_parameter_node_t; + +/** + * RequiredParameterNode + * + * Represents a required parameter to a method, block, or lambda definition. + * + * def a(b) + * ^ + * end + * + * Type: ::PM_REQUIRED_PARAMETER_NODE + + * Flags (#pm_parameter_flags): + * * ::PM_PARAMETER_FLAGS_REPEATED_PARAMETER + * + * @extends pm_node_t + */ +typedef struct pm_required_parameter_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * RequiredParameterNode#name + */ + pm_constant_id_t name; +} pm_required_parameter_node_t; + +/** + * RescueModifierNode + * + * Represents an expression modified with a rescue. + * + * foo rescue nil + * ^^^^^^^^^^^^^^ + * + * Type: ::PM_RESCUE_MODIFIER_NODE + * + * @extends pm_node_t + */ +typedef struct pm_rescue_modifier_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * RescueModifierNode#expression + */ + struct pm_node *expression; + + /** + * RescueModifierNode#keyword_loc + */ + pm_location_t keyword_loc; + + /** + * RescueModifierNode#rescue_expression + */ + struct pm_node *rescue_expression; +} pm_rescue_modifier_node_t; + +/** + * RescueNode + * + * Represents a rescue statement. + * + * begin + * rescue Foo, *splat, Bar => ex + * foo + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * end + * + * `Foo, *splat, Bar` are in the `exceptions` field. `ex` is in the `reference` field. + * + * Type: ::PM_RESCUE_NODE + * + * @extends pm_node_t + */ +typedef struct pm_rescue_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * RescueNode#keyword_loc + */ + pm_location_t keyword_loc; + + /** + * RescueNode#exceptions + */ + struct pm_node_list exceptions; + + /** + * RescueNode#operator_loc + */ + pm_location_t operator_loc; + + /** + * RescueNode#reference + */ + struct pm_node *reference; + + /** + * RescueNode#then_keyword_loc + */ + pm_location_t then_keyword_loc; + + /** + * RescueNode#statements + */ + struct pm_statements_node *statements; + + /** + * RescueNode#subsequent + */ + struct pm_rescue_node *subsequent; +} pm_rescue_node_t; + +/** + * RestParameterNode + * + * Represents a rest parameter to a method, block, or lambda definition. + * + * def a(*b) + * ^^ + * end + * + * Type: ::PM_REST_PARAMETER_NODE + + * Flags (#pm_parameter_flags): + * * ::PM_PARAMETER_FLAGS_REPEATED_PARAMETER + * + * @extends pm_node_t + */ +typedef struct pm_rest_parameter_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * RestParameterNode#name + */ + pm_constant_id_t name; + + /** + * RestParameterNode#name_loc + */ + pm_location_t name_loc; + + /** + * RestParameterNode#operator_loc + */ + pm_location_t operator_loc; +} pm_rest_parameter_node_t; + +/** + * RetryNode + * + * Represents the use of the `retry` keyword. + * + * retry + * ^^^^^ + * + * Type: ::PM_RETRY_NODE + * + * @extends pm_node_t + */ +typedef struct pm_retry_node { + /** The embedded base node. */ + pm_node_t base; + +} pm_retry_node_t; + +/** + * ReturnNode + * + * Represents the use of the `return` keyword. + * + * return 1 + * ^^^^^^^^ + * + * Type: ::PM_RETURN_NODE + * + * @extends pm_node_t + */ +typedef struct pm_return_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * ReturnNode#keyword_loc + */ + pm_location_t keyword_loc; + + /** + * ReturnNode#arguments + */ + struct pm_arguments_node *arguments; +} pm_return_node_t; + +/** + * SelfNode + * + * Represents the `self` keyword. + * + * self + * ^^^^ + * + * Type: ::PM_SELF_NODE + * + * @extends pm_node_t + */ +typedef struct pm_self_node { + /** The embedded base node. */ + pm_node_t base; + +} pm_self_node_t; + +/** + * ShareableConstantNode + * + * This node wraps a constant write to indicate that when the value is written, it should have its shareability state modified. + * + * # shareable_constant_value: literal + * C = { a: 1 } + * ^^^^^^^^^^^^ + * + * Type: ::PM_SHAREABLE_CONSTANT_NODE + + * Flags (#pm_shareable_constant_node_flags): + * * ::PM_SHAREABLE_CONSTANT_NODE_FLAGS_LITERAL + * * ::PM_SHAREABLE_CONSTANT_NODE_FLAGS_EXPERIMENTAL_EVERYTHING + * * ::PM_SHAREABLE_CONSTANT_NODE_FLAGS_EXPERIMENTAL_COPY + * + * @extends pm_node_t + */ +typedef struct pm_shareable_constant_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * ShareableConstantNode#write + * + * The constant write that should be modified with the shareability state. + */ + struct pm_node *write; +} pm_shareable_constant_node_t; + +/** + * SingletonClassNode + * + * Represents a singleton class declaration involving the `class` keyword. + * + * class << self end + * ^^^^^^^^^^^^^^^^^ + * + * Type: ::PM_SINGLETON_CLASS_NODE + * + * @extends pm_node_t + */ +typedef struct pm_singleton_class_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * SingletonClassNode#locals + */ + pm_constant_id_list_t locals; + + /** + * SingletonClassNode#class_keyword_loc + */ + pm_location_t class_keyword_loc; + + /** + * SingletonClassNode#operator_loc + */ + pm_location_t operator_loc; + + /** + * SingletonClassNode#expression + */ + struct pm_node *expression; + + /** + * SingletonClassNode#body + */ + struct pm_node *body; + + /** + * SingletonClassNode#end_keyword_loc + */ + pm_location_t end_keyword_loc; +} pm_singleton_class_node_t; + +/** + * SourceEncodingNode + * + * Represents the use of the `__ENCODING__` keyword. + * + * __ENCODING__ + * ^^^^^^^^^^^^ + * + * Type: ::PM_SOURCE_ENCODING_NODE + * + * @extends pm_node_t + */ +typedef struct pm_source_encoding_node { + /** The embedded base node. */ + pm_node_t base; + +} pm_source_encoding_node_t; + +/** + * SourceFileNode + * + * Represents the use of the `__FILE__` keyword. + * + * __FILE__ + * ^^^^^^^^ + * + * Type: ::PM_SOURCE_FILE_NODE + + * Flags (#pm_string_flags): + * * ::PM_STRING_FLAGS_FORCED_UTF8_ENCODING + * * ::PM_STRING_FLAGS_FORCED_BINARY_ENCODING + * * ::PM_STRING_FLAGS_FROZEN + * * ::PM_STRING_FLAGS_MUTABLE + * + * @extends pm_node_t + */ +typedef struct pm_source_file_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * SourceFileNode#filepath + * + * Represents the file path being parsed. This corresponds directly to the `filepath` option given to the various `Prism::parse*` APIs. + */ + pm_string_t filepath; +} pm_source_file_node_t; + +/** + * SourceLineNode + * + * Represents the use of the `__LINE__` keyword. + * + * __LINE__ + * ^^^^^^^^ + * + * Type: ::PM_SOURCE_LINE_NODE + * + * @extends pm_node_t + */ +typedef struct pm_source_line_node { + /** The embedded base node. */ + pm_node_t base; + +} pm_source_line_node_t; + +/** + * SplatNode + * + * Represents the use of the splat operator. + * + * [*a] + * ^^ + * + * Type: ::PM_SPLAT_NODE + * + * @extends pm_node_t + */ +typedef struct pm_splat_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * SplatNode#operator_loc + */ + pm_location_t operator_loc; + + /** + * SplatNode#expression + */ + struct pm_node *expression; +} pm_splat_node_t; + +/** + * StatementsNode + * + * Represents a set of statements contained within some scope. + * + * foo; bar; baz + * ^^^^^^^^^^^^^ + * + * Type: ::PM_STATEMENTS_NODE + * + * @extends pm_node_t + */ +typedef struct pm_statements_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * StatementsNode#body + */ + struct pm_node_list body; +} pm_statements_node_t; + +/** + * StringNode + * + * Represents a string literal, a string contained within a `%w` list, or plain string content within an interpolated string. + * + * "foo" + * ^^^^^ + * + * %w[foo] + * ^^^ + * + * "foo #{bar} baz" + * ^^^^ ^^^^ + * + * Type: ::PM_STRING_NODE + + * Flags (#pm_string_flags): + * * ::PM_STRING_FLAGS_FORCED_UTF8_ENCODING + * * ::PM_STRING_FLAGS_FORCED_BINARY_ENCODING + * * ::PM_STRING_FLAGS_FROZEN + * * ::PM_STRING_FLAGS_MUTABLE + * + * @extends pm_node_t + */ +typedef struct pm_string_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * StringNode#opening_loc + */ + pm_location_t opening_loc; + + /** + * StringNode#content_loc + */ + pm_location_t content_loc; + + /** + * StringNode#closing_loc + */ + pm_location_t closing_loc; + + /** + * StringNode#unescaped + */ + pm_string_t unescaped; +} pm_string_node_t; + +/** + * SuperNode + * + * Represents the use of the `super` keyword with parentheses or arguments. + * + * super() + * ^^^^^^^ + * + * super foo, bar + * ^^^^^^^^^^^^^^ + * + * Type: ::PM_SUPER_NODE + * + * @extends pm_node_t + */ +typedef struct pm_super_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * SuperNode#keyword_loc + */ + pm_location_t keyword_loc; + + /** + * SuperNode#lparen_loc + */ + pm_location_t lparen_loc; + + /** + * SuperNode#arguments + */ + struct pm_arguments_node *arguments; + + /** + * SuperNode#rparen_loc + */ + pm_location_t rparen_loc; + + /** + * SuperNode#block + */ + struct pm_node *block; +} pm_super_node_t; + +/** + * SymbolNode + * + * Represents a symbol literal or a symbol contained within a `%i` list. + * + * :foo + * ^^^^ + * + * %i[foo] + * ^^^ + * + * Type: ::PM_SYMBOL_NODE + + * Flags (#pm_symbol_flags): + * * ::PM_SYMBOL_FLAGS_FORCED_UTF8_ENCODING + * * ::PM_SYMBOL_FLAGS_FORCED_BINARY_ENCODING + * * ::PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING + * + * @extends pm_node_t + */ +typedef struct pm_symbol_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * SymbolNode#opening_loc + */ + pm_location_t opening_loc; + + /** + * SymbolNode#value_loc + */ + pm_location_t value_loc; + + /** + * SymbolNode#closing_loc + */ + pm_location_t closing_loc; + + /** + * SymbolNode#unescaped + */ + pm_string_t unescaped; +} pm_symbol_node_t; + +/** + * TrueNode + * + * Represents the use of the literal `true` keyword. + * + * true + * ^^^^ + * + * Type: ::PM_TRUE_NODE + * + * @extends pm_node_t + */ +typedef struct pm_true_node { + /** The embedded base node. */ + pm_node_t base; + +} pm_true_node_t; + +/** + * UndefNode + * + * Represents the use of the `undef` keyword. + * + * undef :foo, :bar, :baz + * ^^^^^^^^^^^^^^^^^^^^^^ + * + * Type: ::PM_UNDEF_NODE + * + * @extends pm_node_t + */ +typedef struct pm_undef_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * UndefNode#names + */ + struct pm_node_list names; + + /** + * UndefNode#keyword_loc + */ + pm_location_t keyword_loc; +} pm_undef_node_t; + +/** + * UnlessNode + * + * Represents the use of the `unless` keyword, either in the block form or the modifier form. + * + * bar unless foo + * ^^^^^^^^^^^^^^ + * + * unless foo then bar end + * ^^^^^^^^^^^^^^^^^^^^^^^ + * + * Type: ::PM_UNLESS_NODE + * + * @extends pm_node_t + */ +typedef struct pm_unless_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * UnlessNode#keyword_loc + * + * The location of the `unless` keyword. + * + * unless cond then bar end + * ^^^^^^ + * + * bar unless cond + * ^^^^^^ + */ + pm_location_t keyword_loc; + + /** + * UnlessNode#predicate + * + * The condition to be evaluated for the unless expression. It can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression). + * + * unless cond then bar end + * ^^^^ + * + * bar unless cond + * ^^^^ + */ + struct pm_node *predicate; + + /** + * UnlessNode#then_keyword_loc + * + * The location of the `then` keyword, if present. + * + * unless cond then bar end + * ^^^^ + */ + pm_location_t then_keyword_loc; + + /** + * UnlessNode#statements + * + * The body of statements that will executed if the unless condition is + * falsey. Will be `nil` if no body is provided. + * + * unless cond then bar end + * ^^^ + */ + struct pm_statements_node *statements; + + /** + * UnlessNode#else_clause + * + * The else clause of the unless expression, if present. + * + * unless cond then bar else baz end + * ^^^^^^^^ + */ + struct pm_else_node *else_clause; + + /** + * UnlessNode#end_keyword_loc + * + * The location of the `end` keyword, if present. + * + * unless cond then bar end + * ^^^ + */ + pm_location_t end_keyword_loc; +} pm_unless_node_t; + +/** + * UntilNode + * + * Represents the use of the `until` keyword, either in the block form or the modifier form. + * + * bar until foo + * ^^^^^^^^^^^^^ + * + * until foo do bar end + * ^^^^^^^^^^^^^^^^^^^^ + * + * Type: ::PM_UNTIL_NODE + + * Flags (#pm_loop_flags): + * * ::PM_LOOP_FLAGS_BEGIN_MODIFIER + * + * @extends pm_node_t + */ +typedef struct pm_until_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * UntilNode#keyword_loc + */ + pm_location_t keyword_loc; + + /** + * UntilNode#do_keyword_loc + */ + pm_location_t do_keyword_loc; + + /** + * UntilNode#closing_loc + */ + pm_location_t closing_loc; + + /** + * UntilNode#predicate + */ + struct pm_node *predicate; + + /** + * UntilNode#statements + */ + struct pm_statements_node *statements; +} pm_until_node_t; + +/** + * WhenNode + * + * Represents the use of the `when` keyword within a case statement. + * + * case true + * when true + * ^^^^^^^^^ + * end + * + * Type: ::PM_WHEN_NODE + * + * @extends pm_node_t + */ +typedef struct pm_when_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * WhenNode#keyword_loc + */ + pm_location_t keyword_loc; + + /** + * WhenNode#conditions + */ + struct pm_node_list conditions; + + /** + * WhenNode#then_keyword_loc + */ + pm_location_t then_keyword_loc; + + /** + * WhenNode#statements + */ + struct pm_statements_node *statements; +} pm_when_node_t; + +/** + * WhileNode + * + * Represents the use of the `while` keyword, either in the block form or the modifier form. + * + * bar while foo + * ^^^^^^^^^^^^^ + * + * while foo do bar end + * ^^^^^^^^^^^^^^^^^^^^ + * + * Type: ::PM_WHILE_NODE + + * Flags (#pm_loop_flags): + * * ::PM_LOOP_FLAGS_BEGIN_MODIFIER + * + * @extends pm_node_t + */ +typedef struct pm_while_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * WhileNode#keyword_loc + */ + pm_location_t keyword_loc; + + /** + * WhileNode#do_keyword_loc + */ + pm_location_t do_keyword_loc; + + /** + * WhileNode#closing_loc + */ + pm_location_t closing_loc; + + /** + * WhileNode#predicate + */ + struct pm_node *predicate; + + /** + * WhileNode#statements + */ + struct pm_statements_node *statements; +} pm_while_node_t; + +/** + * XStringNode + * + * Represents an xstring literal with no interpolation. + * + * `foo` + * ^^^^^ + * + * Type: ::PM_X_STRING_NODE + + * Flags (#pm_encoding_flags): + * * ::PM_ENCODING_FLAGS_FORCED_UTF8_ENCODING + * * ::PM_ENCODING_FLAGS_FORCED_BINARY_ENCODING + * + * @extends pm_node_t + */ +typedef struct pm_x_string_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * XStringNode#opening_loc + */ + pm_location_t opening_loc; + + /** + * XStringNode#content_loc + */ + pm_location_t content_loc; + + /** + * XStringNode#closing_loc + */ + pm_location_t closing_loc; + + /** + * XStringNode#unescaped + */ + pm_string_t unescaped; +} pm_x_string_node_t; + +/** + * YieldNode + * + * Represents the use of the `yield` keyword. + * + * yield 1 + * ^^^^^^^ + * + * Type: ::PM_YIELD_NODE + * + * @extends pm_node_t + */ +typedef struct pm_yield_node { + /** The embedded base node. */ + pm_node_t base; + + + /** + * YieldNode#keyword_loc + */ + pm_location_t keyword_loc; + + /** + * YieldNode#lparen_loc + */ + pm_location_t lparen_loc; + + /** + * YieldNode#arguments + */ + struct pm_arguments_node *arguments; + + /** + * YieldNode#rparen_loc + */ + pm_location_t rparen_loc; +} pm_yield_node_t; + +/** + * Flags for arguments nodes. + */ +typedef enum pm_arguments_node_flags { + /** if the arguments contain forwarding */ + PM_ARGUMENTS_NODE_FLAGS_CONTAINS_FORWARDING = 4, + + /** if the arguments contain keywords */ + PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS = 8, + + /** if the arguments contain a keyword splat */ + PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT = 16, + + /** if the arguments contain a splat */ + PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT = 32, + + /** if the arguments contain multiple splats */ + PM_ARGUMENTS_NODE_FLAGS_CONTAINS_MULTIPLE_SPLATS = 64, + + PM_ARGUMENTS_NODE_FLAGS_LAST, +} pm_arguments_node_flags_t; + +/** + * Flags for array nodes. + */ +typedef enum pm_array_node_flags { + /** if array contains splat nodes */ + PM_ARRAY_NODE_FLAGS_CONTAINS_SPLAT = 4, + + PM_ARRAY_NODE_FLAGS_LAST, +} pm_array_node_flags_t; + +/** + * Flags for call nodes. + */ +typedef enum pm_call_node_flags { + /** &. operator */ + PM_CALL_NODE_FLAGS_SAFE_NAVIGATION = 4, + + /** a call that could have been a local variable */ + PM_CALL_NODE_FLAGS_VARIABLE_CALL = 8, + + /** a call that is an attribute write, so the value being written should be returned */ + PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE = 16, + + /** a call that ignores method visibility */ + PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY = 32, + + PM_CALL_NODE_FLAGS_LAST, +} pm_call_node_flags_t; + +/** + * Flags for nodes that have unescaped content. + */ +typedef enum pm_encoding_flags { + /** internal bytes forced the encoding to UTF-8 */ + PM_ENCODING_FLAGS_FORCED_UTF8_ENCODING = 4, + + /** internal bytes forced the encoding to binary */ + PM_ENCODING_FLAGS_FORCED_BINARY_ENCODING = 8, + + PM_ENCODING_FLAGS_LAST, +} pm_encoding_flags_t; + +/** + * Flags for integer nodes that correspond to the base of the integer. + */ +typedef enum pm_integer_base_flags { + /** 0b prefix */ + PM_INTEGER_BASE_FLAGS_BINARY = 4, + + /** 0d or no prefix */ + PM_INTEGER_BASE_FLAGS_DECIMAL = 8, + + /** 0o or 0 prefix */ + PM_INTEGER_BASE_FLAGS_OCTAL = 16, + + /** 0x prefix */ + PM_INTEGER_BASE_FLAGS_HEXADECIMAL = 32, + + PM_INTEGER_BASE_FLAGS_LAST, +} pm_integer_base_flags_t; + +/** + * Flags for interpolated string nodes that indicated mutability if they are also marked as literals. + */ +typedef enum pm_interpolated_string_node_flags { + /** frozen by virtue of a `frozen_string_literal: true` comment or `--enable-frozen-string-literal`; only for adjacent string literals like `'a' 'b'` */ + PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN = 4, + + /** mutable by virtue of a `frozen_string_literal: false` comment or `--disable-frozen-string-literal`; only for adjacent string literals like `'a' 'b'` */ + PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE = 8, + + PM_INTERPOLATED_STRING_NODE_FLAGS_LAST, +} pm_interpolated_string_node_flags_t; + +/** + * Flags for keyword hash nodes. + */ +typedef enum pm_keyword_hash_node_flags { + /** a keyword hash which only has `AssocNode` elements all with symbol keys, which means the elements can be treated as keyword arguments */ + PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS = 4, + + PM_KEYWORD_HASH_NODE_FLAGS_LAST, +} pm_keyword_hash_node_flags_t; + +/** + * Flags for while and until loop nodes. + */ +typedef enum pm_loop_flags { + /** a loop after a begin statement, so the body is executed first before the condition */ + PM_LOOP_FLAGS_BEGIN_MODIFIER = 4, + + PM_LOOP_FLAGS_LAST, +} pm_loop_flags_t; + +/** + * Flags for parameter nodes. + */ +typedef enum pm_parameter_flags { + /** a parameter name that has been repeated in the method signature */ + PM_PARAMETER_FLAGS_REPEATED_PARAMETER = 4, + + PM_PARAMETER_FLAGS_LAST, +} pm_parameter_flags_t; + +/** + * Flags for parentheses nodes. + */ +typedef enum pm_parentheses_node_flags { + /** parentheses that contain multiple potentially void statements */ + PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS = 4, + + PM_PARENTHESES_NODE_FLAGS_LAST, +} pm_parentheses_node_flags_t; + +/** + * Flags for range and flip-flop nodes. + */ +typedef enum pm_range_flags { + /** ... operator */ + PM_RANGE_FLAGS_EXCLUDE_END = 4, + + PM_RANGE_FLAGS_LAST, +} pm_range_flags_t; + +/** + * Flags for regular expression and match last line nodes. + */ +typedef enum pm_regular_expression_flags { + /** i - ignores the case of characters when matching */ + PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE = 4, + + /** x - ignores whitespace and allows comments in regular expressions */ + PM_REGULAR_EXPRESSION_FLAGS_EXTENDED = 8, + + /** m - allows $ to match the end of lines within strings */ + PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE = 16, + + /** o - only interpolates values into the regular expression once */ + PM_REGULAR_EXPRESSION_FLAGS_ONCE = 32, + + /** e - forces the EUC-JP encoding */ + PM_REGULAR_EXPRESSION_FLAGS_EUC_JP = 64, + + /** n - forces the ASCII-8BIT encoding */ + PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT = 128, + + /** s - forces the Windows-31J encoding */ + PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J = 256, + + /** u - forces the UTF-8 encoding */ + PM_REGULAR_EXPRESSION_FLAGS_UTF_8 = 512, + + /** internal bytes forced the encoding to UTF-8 */ + PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING = 1024, + + /** internal bytes forced the encoding to binary */ + PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING = 2048, + + /** internal bytes forced the encoding to US-ASCII */ + PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING = 4096, + + PM_REGULAR_EXPRESSION_FLAGS_LAST, +} pm_regular_expression_flags_t; + +/** + * Flags for shareable constant nodes. + */ +typedef enum pm_shareable_constant_node_flags { + /** constant writes that should be modified with shareable constant value literal */ + PM_SHAREABLE_CONSTANT_NODE_FLAGS_LITERAL = 4, + + /** constant writes that should be modified with shareable constant value experimental everything */ + PM_SHAREABLE_CONSTANT_NODE_FLAGS_EXPERIMENTAL_EVERYTHING = 8, + + /** constant writes that should be modified with shareable constant value experimental copy */ + PM_SHAREABLE_CONSTANT_NODE_FLAGS_EXPERIMENTAL_COPY = 16, + + PM_SHAREABLE_CONSTANT_NODE_FLAGS_LAST, +} pm_shareable_constant_node_flags_t; + +/** + * Flags for string nodes. + */ +typedef enum pm_string_flags { + /** internal bytes forced the encoding to UTF-8 */ + PM_STRING_FLAGS_FORCED_UTF8_ENCODING = 4, + + /** internal bytes forced the encoding to binary */ + PM_STRING_FLAGS_FORCED_BINARY_ENCODING = 8, + + /** frozen by virtue of a `frozen_string_literal: true` comment or `--enable-frozen-string-literal` */ + PM_STRING_FLAGS_FROZEN = 16, + + /** mutable by virtue of a `frozen_string_literal: false` comment or `--disable-frozen-string-literal` */ + PM_STRING_FLAGS_MUTABLE = 32, + + PM_STRING_FLAGS_LAST, +} pm_string_flags_t; + +/** + * Flags for symbol nodes. + */ +typedef enum pm_symbol_flags { + /** internal bytes forced the encoding to UTF-8 */ + PM_SYMBOL_FLAGS_FORCED_UTF8_ENCODING = 4, + + /** internal bytes forced the encoding to binary */ + PM_SYMBOL_FLAGS_FORCED_BINARY_ENCODING = 8, + + /** internal bytes forced the encoding to US-ASCII */ + PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING = 16, + + PM_SYMBOL_FLAGS_LAST, +} pm_symbol_flags_t; + +/** + * When we're serializing to Java, we want to skip serializing the location + * fields as they won't be used by JRuby or TruffleRuby. This boolean allows us + * to specify that through the environment. It will never be true except for in + * those build systems. + */ +#define PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS 0 + +#endif diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/defines.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/defines.h new file mode 100644 index 0000000..e31429c --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/defines.h @@ -0,0 +1,260 @@ +/** + * @file defines.h + * + * Macro definitions used throughout the prism library. + * + * This file should be included first by any *.h or *.c in prism for consistency + * and to ensure that the macros are defined before they are used. + */ +#ifndef PRISM_DEFINES_H +#define PRISM_DEFINES_H + +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * We want to be able to use the PRI* macros for printing out integers, but on + * some platforms they aren't included unless this is already defined. + */ +#define __STDC_FORMAT_MACROS +// Include sys/types.h before inttypes.h to work around issue with +// certain versions of GCC and newlib which causes omission of PRIx64 +#include +#include + +/** + * When we are parsing using recursive descent, we want to protect against + * malicious payloads that could attempt to crash our parser. We do this by + * specifying a maximum depth to which we are allowed to recurse. + */ +#ifndef PRISM_DEPTH_MAXIMUM + #define PRISM_DEPTH_MAXIMUM 10000 +#endif + +/** + * By default, we compile with -fvisibility=hidden. When this is enabled, we + * need to mark certain functions as being publically-visible. This macro does + * that in a compiler-agnostic way. + */ +#ifndef PRISM_EXPORTED_FUNCTION +# ifdef PRISM_EXPORT_SYMBOLS +# ifdef _WIN32 +# define PRISM_EXPORTED_FUNCTION __declspec(dllexport) extern +# else +# define PRISM_EXPORTED_FUNCTION __attribute__((__visibility__("default"))) extern +# endif +# else +# define PRISM_EXPORTED_FUNCTION +# endif +#endif + +/** + * Certain compilers support specifying that a function accepts variadic + * parameters that look like printf format strings to provide a better developer + * experience when someone is using the function. This macro does that in a + * compiler-agnostic way. + */ +#if defined(__GNUC__) +# if defined(__MINGW_PRINTF_FORMAT) +# define PRISM_ATTRIBUTE_FORMAT(string_index, argument_index) __attribute__((format(__MINGW_PRINTF_FORMAT, string_index, argument_index))) +# else +# define PRISM_ATTRIBUTE_FORMAT(string_index, argument_index) __attribute__((format(printf, string_index, argument_index))) +# endif +#elif defined(__clang__) +# define PRISM_ATTRIBUTE_FORMAT(string_index, argument_index) __attribute__((__format__(__printf__, string_index, argument_index))) +#else +# define PRISM_ATTRIBUTE_FORMAT(string_index, argument_index) +#endif + +/** + * GCC will warn if you specify a function or parameter that is unused at + * runtime. This macro allows you to mark a function or parameter as unused in a + * compiler-agnostic way. + */ +#if defined(__GNUC__) +# define PRISM_ATTRIBUTE_UNUSED __attribute__((unused)) +#else +# define PRISM_ATTRIBUTE_UNUSED +#endif + +/** + * Old Visual Studio versions do not support the inline keyword, so we need to + * define it to be __inline. + */ +#if defined(_MSC_VER) && !defined(inline) +# define inline __inline +#endif + +/** + * Old Visual Studio versions before 2015 do not implement sprintf, but instead + * implement _snprintf. We standard that here. + */ +#if !defined(snprintf) && defined(_MSC_VER) && (_MSC_VER < 1900) +# define snprintf _snprintf +#endif + +/** + * A simple utility macro to concatenate two tokens together, necessary when one + * of the tokens is itself a macro. + */ +#define PM_CONCATENATE(left, right) left ## right + +/** + * We want to be able to use static assertions, but they weren't standardized + * until C11. As such, we polyfill it here by making a hacky typedef that will + * fail to compile due to a negative array size if the condition is false. + */ +#if defined(_Static_assert) +# define PM_STATIC_ASSERT(line, condition, message) _Static_assert(condition, message) +#else +# define PM_STATIC_ASSERT(line, condition, message) typedef char PM_CONCATENATE(static_assert_, line)[(condition) ? 1 : -1] +#endif + +/** + * In general, libc for embedded systems does not support memory-mapped files. + * If the target platform is POSIX or Windows, we can map a file in memory and + * read it in a more efficient manner. + */ +#ifdef _WIN32 +# define PRISM_HAS_MMAP +#else +# include +# ifdef _POSIX_MAPPED_FILES +# define PRISM_HAS_MMAP +# endif +#endif + +/** + * If PRISM_HAS_NO_FILESYSTEM is defined, then we want to exclude all filesystem + * related code from the library. All filesystem related code should be guarded + * by PRISM_HAS_FILESYSTEM. + */ +#ifndef PRISM_HAS_NO_FILESYSTEM +# define PRISM_HAS_FILESYSTEM +#endif + +/** + * isinf on POSIX systems it accepts a float, a double, or a long double. + * But mingw didn't provide an isinf macro, only an isinf function that only + * accepts floats, so we need to use _finite instead. + */ +#ifdef __MINGW64__ + #include + #define PRISM_ISINF(x) (!_finite(x)) +#else + #define PRISM_ISINF(x) isinf(x) +#endif + +/** + * If you build prism with a custom allocator, configure it with + * "-D PRISM_XALLOCATOR" to use your own allocator that defines xmalloc, + * xrealloc, xcalloc, and xfree. + * + * For example, your `prism_xallocator.h` file could look like this: + * + * ``` + * #ifndef PRISM_XALLOCATOR_H + * #define PRISM_XALLOCATOR_H + * #define xmalloc my_malloc + * #define xrealloc my_realloc + * #define xcalloc my_calloc + * #define xfree my_free + * #endif + * ``` + */ +#ifdef PRISM_XALLOCATOR + #include "prism_xallocator.h" +#else + #ifndef xmalloc + /** + * The malloc function that should be used. This can be overridden with + * the PRISM_XALLOCATOR define. + */ + #define xmalloc malloc + #endif + + #ifndef xrealloc + /** + * The realloc function that should be used. This can be overridden with + * the PRISM_XALLOCATOR define. + */ + #define xrealloc realloc + #endif + + #ifndef xcalloc + /** + * The calloc function that should be used. This can be overridden with + * the PRISM_XALLOCATOR define. + */ + #define xcalloc calloc + #endif + + #ifndef xfree + /** + * The free function that should be used. This can be overridden with the + * PRISM_XALLOCATOR define. + */ + #define xfree free + #endif +#endif + +/** + * If PRISM_BUILD_MINIMAL is defined, then we're going to define every possible + * switch that will turn off certain features of prism. + */ +#ifdef PRISM_BUILD_MINIMAL + /** Exclude the serialization API. */ + #define PRISM_EXCLUDE_SERIALIZATION + + /** Exclude the JSON serialization API. */ + #define PRISM_EXCLUDE_JSON + + /** Exclude the Array#pack parser API. */ + #define PRISM_EXCLUDE_PACK + + /** Exclude the prettyprint API. */ + #define PRISM_EXCLUDE_PRETTYPRINT + + /** Exclude the full set of encodings, using the minimal only. */ + #define PRISM_ENCODING_EXCLUDE_FULL +#endif + +/** + * Support PRISM_LIKELY and PRISM_UNLIKELY to help the compiler optimize its + * branch predication. + */ +#if defined(__GNUC__) || defined(__clang__) + /** The compiler should predicate that this branch will be taken. */ + #define PRISM_LIKELY(x) __builtin_expect(!!(x), 1) + + /** The compiler should predicate that this branch will not be taken. */ + #define PRISM_UNLIKELY(x) __builtin_expect(!!(x), 0) +#else + /** Void because this platform does not support branch prediction hints. */ + #define PRISM_LIKELY(x) (x) + + /** Void because this platform does not support branch prediction hints. */ + #define PRISM_UNLIKELY(x) (x) +#endif + +/** + * We use -Wimplicit-fallthrough to guard potentially unintended fall-through between cases of a switch. + * Use PRISM_FALLTHROUGH to explicitly annotate cases where the fallthrough is intentional. + */ +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L // C23 or later + #define PRISM_FALLTHROUGH [[fallthrough]]; +#elif defined(__GNUC__) || defined(__clang__) + #define PRISM_FALLTHROUGH __attribute__((fallthrough)); +#elif defined(_MSC_VER) + #define PRISM_FALLTHROUGH __fallthrough; +#else + #define PRISM_FALLTHROUGH +#endif + +#endif diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/diagnostic.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/diagnostic.h new file mode 100644 index 0000000..9bf3ade --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/diagnostic.h @@ -0,0 +1,458 @@ +/* :markup: markdown */ + +/*----------------------------------------------------------------------------*/ +/* This file is generated by the templates/template.rb script and should not */ +/* be modified manually. See */ +/* templates/include/prism/diagnostic.h.erb */ +/* if you are looking to modify the */ +/* template */ +/*----------------------------------------------------------------------------*/ + +/** + * @file diagnostic.h + * + * A list of diagnostics generated during parsing. + */ +#ifndef PRISM_DIAGNOSTIC_H +#define PRISM_DIAGNOSTIC_H + +#include "prism/ast.h" +#include "prism/defines.h" +#include "prism/util/pm_list.h" + +#include +#include +#include + +/** + * The diagnostic IDs of all of the diagnostics, used to communicate the types + * of errors between the parser and the user. + */ +typedef enum { + // These are the error diagnostics. + PM_ERR_ALIAS_ARGUMENT, + PM_ERR_ALIAS_ARGUMENT_NUMBERED_REFERENCE, + PM_ERR_AMPAMPEQ_MULTI_ASSIGN, + PM_ERR_ARGUMENT_AFTER_BLOCK, + PM_ERR_ARGUMENT_AFTER_FORWARDING_ELLIPSES, + PM_ERR_ARGUMENT_BARE_HASH, + PM_ERR_ARGUMENT_BLOCK_FORWARDING, + PM_ERR_ARGUMENT_BLOCK_MULTI, + PM_ERR_ARGUMENT_CONFLICT_AMPERSAND, + PM_ERR_ARGUMENT_CONFLICT_STAR, + PM_ERR_ARGUMENT_CONFLICT_STAR_STAR, + PM_ERR_ARGUMENT_FORMAL_CLASS, + PM_ERR_ARGUMENT_FORMAL_CONSTANT, + PM_ERR_ARGUMENT_FORMAL_GLOBAL, + PM_ERR_ARGUMENT_FORMAL_IVAR, + PM_ERR_ARGUMENT_FORWARDING_UNBOUND, + PM_ERR_ARGUMENT_NO_FORWARDING_AMPERSAND, + PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES, + PM_ERR_ARGUMENT_NO_FORWARDING_STAR, + PM_ERR_ARGUMENT_NO_FORWARDING_STAR_STAR, + PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT, + PM_ERR_ARGUMENT_SPLAT_AFTER_SPLAT, + PM_ERR_ARGUMENT_TERM_PAREN, + PM_ERR_ARGUMENT_UNEXPECTED_BLOCK, + PM_ERR_ARRAY_ELEMENT, + PM_ERR_ARRAY_EXPRESSION, + PM_ERR_ARRAY_EXPRESSION_AFTER_STAR, + PM_ERR_ARRAY_SEPARATOR, + PM_ERR_ARRAY_TERM, + PM_ERR_BEGIN_LONELY_ELSE, + PM_ERR_BEGIN_TERM, + PM_ERR_BEGIN_UPCASE_BRACE, + PM_ERR_BEGIN_UPCASE_TERM, + PM_ERR_BEGIN_UPCASE_TOPLEVEL, + PM_ERR_BLOCK_PARAM_LOCAL_VARIABLE, + PM_ERR_BLOCK_PARAM_PIPE_TERM, + PM_ERR_BLOCK_TERM_BRACE, + PM_ERR_BLOCK_TERM_END, + PM_ERR_CANNOT_PARSE_EXPRESSION, + PM_ERR_CANNOT_PARSE_STRING_PART, + PM_ERR_CASE_EXPRESSION_AFTER_CASE, + PM_ERR_CASE_EXPRESSION_AFTER_WHEN, + PM_ERR_CASE_MATCH_MISSING_PREDICATE, + PM_ERR_CASE_MISSING_CONDITIONS, + PM_ERR_CASE_TERM, + PM_ERR_CLASS_IN_METHOD, + PM_ERR_CLASS_NAME, + PM_ERR_CLASS_SUPERCLASS, + PM_ERR_CLASS_TERM, + PM_ERR_CLASS_UNEXPECTED_END, + PM_ERR_CLASS_VARIABLE_BARE, + PM_ERR_CONDITIONAL_ELSIF_PREDICATE, + PM_ERR_CONDITIONAL_IF_PREDICATE, + PM_ERR_CONDITIONAL_PREDICATE_TERM, + PM_ERR_CONDITIONAL_TERM, + PM_ERR_CONDITIONAL_TERM_ELSE, + PM_ERR_CONDITIONAL_UNLESS_PREDICATE, + PM_ERR_CONDITIONAL_UNTIL_PREDICATE, + PM_ERR_CONDITIONAL_WHILE_PREDICATE, + PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT, + PM_ERR_DEF_ENDLESS, + PM_ERR_DEF_ENDLESS_PARAMETERS, + PM_ERR_DEF_ENDLESS_SETTER, + PM_ERR_DEF_NAME, + PM_ERR_DEF_PARAMS_TERM, + PM_ERR_DEF_PARAMS_TERM_PAREN, + PM_ERR_DEF_RECEIVER, + PM_ERR_DEF_RECEIVER_TERM, + PM_ERR_DEF_TERM, + PM_ERR_DEFINED_EXPRESSION, + PM_ERR_EMBDOC_TERM, + PM_ERR_EMBEXPR_END, + PM_ERR_EMBVAR_INVALID, + PM_ERR_END_UPCASE_BRACE, + PM_ERR_END_UPCASE_TERM, + PM_ERR_ESCAPE_INVALID_CONTROL, + PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT, + PM_ERR_ESCAPE_INVALID_HEXADECIMAL, + PM_ERR_ESCAPE_INVALID_META, + PM_ERR_ESCAPE_INVALID_META_REPEAT, + PM_ERR_ESCAPE_INVALID_UNICODE, + PM_ERR_ESCAPE_INVALID_UNICODE_CM_FLAGS, + PM_ERR_ESCAPE_INVALID_UNICODE_LIST, + PM_ERR_ESCAPE_INVALID_UNICODE_LITERAL, + PM_ERR_ESCAPE_INVALID_UNICODE_LONG, + PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, + PM_ERR_ESCAPE_INVALID_UNICODE_TERM, + PM_ERR_EXPECT_ARGUMENT, + PM_ERR_EXPECT_EOL_AFTER_STATEMENT, + PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, + PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, + PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL, + PM_ERR_EXPECT_EXPRESSION_AFTER_LESS_LESS, + PM_ERR_EXPECT_EXPRESSION_AFTER_LPAREN, + PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, + PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, + PM_ERR_EXPECT_EXPRESSION_AFTER_QUESTION, + PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT, + PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, + PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, + PM_ERR_EXPECT_FOR_DELIMITER, + PM_ERR_EXPECT_IDENT_REQ_PARAMETER, + PM_ERR_EXPECT_IN_DELIMITER, + PM_ERR_EXPECT_LPAREN_AFTER_NOT_LPAREN, + PM_ERR_EXPECT_LPAREN_AFTER_NOT_OTHER, + PM_ERR_EXPECT_LPAREN_REQ_PARAMETER, + PM_ERR_EXPECT_MESSAGE, + PM_ERR_EXPECT_RBRACKET, + PM_ERR_EXPECT_RPAREN, + PM_ERR_EXPECT_RPAREN_AFTER_MULTI, + PM_ERR_EXPECT_RPAREN_REQ_PARAMETER, + PM_ERR_EXPECT_SINGLETON_CLASS_DELIMITER, + PM_ERR_EXPECT_STRING_CONTENT, + PM_ERR_EXPECT_WHEN_DELIMITER, + PM_ERR_EXPRESSION_BARE_HASH, + PM_ERR_EXPRESSION_NOT_WRITABLE, + PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING, + PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE, + PM_ERR_EXPRESSION_NOT_WRITABLE_FILE, + PM_ERR_EXPRESSION_NOT_WRITABLE_LINE, + PM_ERR_EXPRESSION_NOT_WRITABLE_NIL, + PM_ERR_EXPRESSION_NOT_WRITABLE_NUMBERED, + PM_ERR_EXPRESSION_NOT_WRITABLE_SELF, + PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE, + PM_ERR_FLOAT_PARSE, + PM_ERR_FOR_COLLECTION, + PM_ERR_FOR_IN, + PM_ERR_FOR_INDEX, + PM_ERR_FOR_TERM, + PM_ERR_GLOBAL_VARIABLE_BARE, + PM_ERR_HASH_EXPRESSION_AFTER_LABEL, + PM_ERR_HASH_KEY, + PM_ERR_HASH_ROCKET, + PM_ERR_HASH_TERM, + PM_ERR_HASH_VALUE, + PM_ERR_HEREDOC_IDENTIFIER, + PM_ERR_HEREDOC_TERM, + PM_ERR_INCOMPLETE_QUESTION_MARK, + PM_ERR_INCOMPLETE_VARIABLE_CLASS, + PM_ERR_INCOMPLETE_VARIABLE_CLASS_3_3, + PM_ERR_INCOMPLETE_VARIABLE_INSTANCE, + PM_ERR_INCOMPLETE_VARIABLE_INSTANCE_3_3, + PM_ERR_INSTANCE_VARIABLE_BARE, + PM_ERR_INVALID_BLOCK_EXIT, + PM_ERR_INVALID_CHARACTER, + PM_ERR_INVALID_COMMA, + PM_ERR_INVALID_ENCODING_MAGIC_COMMENT, + PM_ERR_INVALID_ESCAPE_CHARACTER, + PM_ERR_INVALID_FLOAT_EXPONENT, + PM_ERR_INVALID_LOCAL_VARIABLE_READ, + PM_ERR_INVALID_LOCAL_VARIABLE_WRITE, + PM_ERR_INVALID_MULTIBYTE_CHAR, + PM_ERR_INVALID_MULTIBYTE_CHARACTER, + PM_ERR_INVALID_MULTIBYTE_ESCAPE, + PM_ERR_INVALID_NUMBER_BINARY, + PM_ERR_INVALID_NUMBER_DECIMAL, + PM_ERR_INVALID_NUMBER_FRACTION, + PM_ERR_INVALID_NUMBER_HEXADECIMAL, + PM_ERR_INVALID_NUMBER_OCTAL, + PM_ERR_INVALID_NUMBER_UNDERSCORE_INNER, + PM_ERR_INVALID_NUMBER_UNDERSCORE_TRAILING, + PM_ERR_INVALID_PERCENT, + PM_ERR_INVALID_PERCENT_EOF, + PM_ERR_INVALID_PRINTABLE_CHARACTER, + PM_ERR_INVALID_RETRY_AFTER_ELSE, + PM_ERR_INVALID_RETRY_AFTER_ENSURE, + PM_ERR_INVALID_RETRY_WITHOUT_RESCUE, + PM_ERR_INVALID_SYMBOL, + PM_ERR_INVALID_VARIABLE_GLOBAL, + PM_ERR_INVALID_VARIABLE_GLOBAL_3_3, + PM_ERR_INVALID_YIELD, + PM_ERR_IT_NOT_ALLOWED_NUMBERED, + PM_ERR_IT_NOT_ALLOWED_ORDINARY, + PM_ERR_LAMBDA_OPEN, + PM_ERR_LAMBDA_TERM_BRACE, + PM_ERR_LAMBDA_TERM_END, + PM_ERR_LIST_I_LOWER_ELEMENT, + PM_ERR_LIST_I_LOWER_TERM, + PM_ERR_LIST_I_UPPER_ELEMENT, + PM_ERR_LIST_I_UPPER_TERM, + PM_ERR_LIST_W_LOWER_ELEMENT, + PM_ERR_LIST_W_LOWER_TERM, + PM_ERR_LIST_W_UPPER_ELEMENT, + PM_ERR_LIST_W_UPPER_TERM, + PM_ERR_MALLOC_FAILED, + PM_ERR_MIXED_ENCODING, + PM_ERR_MODULE_IN_METHOD, + PM_ERR_MODULE_NAME, + PM_ERR_MODULE_TERM, + PM_ERR_MULTI_ASSIGN_MULTI_SPLATS, + PM_ERR_MULTI_ASSIGN_UNEXPECTED_REST, + PM_ERR_NESTING_TOO_DEEP, + PM_ERR_NO_LOCAL_VARIABLE, + PM_ERR_NON_ASSOCIATIVE_OPERATOR, + PM_ERR_NOT_EXPRESSION, + PM_ERR_NUMBER_LITERAL_UNDERSCORE, + PM_ERR_NUMBERED_PARAMETER_INNER_BLOCK, + PM_ERR_NUMBERED_PARAMETER_IT, + PM_ERR_NUMBERED_PARAMETER_ORDINARY, + PM_ERR_NUMBERED_PARAMETER_OUTER_BLOCK, + PM_ERR_OPERATOR_MULTI_ASSIGN, + PM_ERR_OPERATOR_WRITE_ARGUMENTS, + PM_ERR_OPERATOR_WRITE_BLOCK, + PM_ERR_PARAMETER_ASSOC_SPLAT_MULTI, + PM_ERR_PARAMETER_BLOCK_MULTI, + PM_ERR_PARAMETER_CIRCULAR, + PM_ERR_PARAMETER_FORWARDING_AFTER_REST, + PM_ERR_PARAMETER_METHOD_NAME, + PM_ERR_PARAMETER_NAME_DUPLICATED, + PM_ERR_PARAMETER_NO_DEFAULT, + PM_ERR_PARAMETER_NO_DEFAULT_KW, + PM_ERR_PARAMETER_NUMBERED_RESERVED, + PM_ERR_PARAMETER_ORDER, + PM_ERR_PARAMETER_SPLAT_MULTI, + PM_ERR_PARAMETER_STAR, + PM_ERR_PARAMETER_UNEXPECTED_FWD, + PM_ERR_PARAMETER_UNEXPECTED_NO_KW, + PM_ERR_PARAMETER_WILD_LOOSE_COMMA, + PM_ERR_PATTERN_ARRAY_MULTIPLE_RESTS, + PM_ERR_PATTERN_CAPTURE_DUPLICATE, + PM_ERR_PATTERN_CAPTURE_IN_ALTERNATIVE, + PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, + PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA, + PM_ERR_PATTERN_EXPRESSION_AFTER_HROCKET, + PM_ERR_PATTERN_EXPRESSION_AFTER_IN, + PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, + PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, + PM_ERR_PATTERN_EXPRESSION_AFTER_PIN, + PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE, + PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, + PM_ERR_PATTERN_EXPRESSION_AFTER_REST, + PM_ERR_PATTERN_FIND_MISSING_INNER, + PM_ERR_PATTERN_HASH_IMPLICIT, + PM_ERR_PATTERN_HASH_KEY, + PM_ERR_PATTERN_HASH_KEY_DUPLICATE, + PM_ERR_PATTERN_HASH_KEY_INTERPOLATED, + PM_ERR_PATTERN_HASH_KEY_LABEL, + PM_ERR_PATTERN_HASH_KEY_LOCALS, + PM_ERR_PATTERN_IDENT_AFTER_HROCKET, + PM_ERR_PATTERN_LABEL_AFTER_COMMA, + PM_ERR_PATTERN_REST, + PM_ERR_PATTERN_TERM_BRACE, + PM_ERR_PATTERN_TERM_BRACKET, + PM_ERR_PATTERN_TERM_PAREN, + PM_ERR_PIPEPIPEEQ_MULTI_ASSIGN, + PM_ERR_REGEXP_ENCODING_OPTION_MISMATCH, + PM_ERR_REGEXP_INCOMPAT_CHAR_ENCODING, + PM_ERR_REGEXP_INVALID_UNICODE_RANGE, + PM_ERR_REGEXP_NON_ESCAPED_MBC, + PM_ERR_REGEXP_PARSE_ERROR, + PM_ERR_REGEXP_TERM, + PM_ERR_REGEXP_UNKNOWN_OPTIONS, + PM_ERR_REGEXP_UTF8_CHAR_NON_UTF8_REGEXP, + PM_ERR_RESCUE_EXPRESSION, + PM_ERR_RESCUE_MODIFIER_VALUE, + PM_ERR_RESCUE_TERM, + PM_ERR_RESCUE_VARIABLE, + PM_ERR_RETURN_INVALID, + PM_ERR_SCRIPT_NOT_FOUND, + PM_ERR_SINGLETON_FOR_LITERALS, + PM_ERR_STATEMENT_ALIAS, + PM_ERR_STATEMENT_POSTEXE_END, + PM_ERR_STATEMENT_PREEXE_BEGIN, + PM_ERR_STATEMENT_UNDEF, + PM_ERR_STRING_CONCATENATION, + PM_ERR_STRING_INTERPOLATED_TERM, + PM_ERR_STRING_LITERAL_EOF, + PM_ERR_STRING_LITERAL_TERM, + PM_ERR_SYMBOL_INVALID, + PM_ERR_SYMBOL_TERM_DYNAMIC, + PM_ERR_SYMBOL_TERM_INTERPOLATED, + PM_ERR_TERNARY_COLON, + PM_ERR_TERNARY_EXPRESSION_FALSE, + PM_ERR_TERNARY_EXPRESSION_TRUE, + PM_ERR_UNARY_DISALLOWED, + PM_ERR_UNARY_RECEIVER, + PM_ERR_UNDEF_ARGUMENT, + PM_ERR_UNEXPECTED_BLOCK_ARGUMENT, + PM_ERR_UNEXPECTED_INDEX_BLOCK, + PM_ERR_UNEXPECTED_INDEX_KEYWORDS, + PM_ERR_UNEXPECTED_LABEL, + PM_ERR_UNEXPECTED_MULTI_WRITE, + PM_ERR_UNEXPECTED_PARAMETER_DEFAULT_VALUE, + PM_ERR_UNEXPECTED_RANGE_OPERATOR, + PM_ERR_UNEXPECTED_SAFE_NAVIGATION, + PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT, + PM_ERR_UNEXPECTED_TOKEN_IGNORE, + PM_ERR_UNTIL_TERM, + PM_ERR_VOID_EXPRESSION, + PM_ERR_WHILE_TERM, + PM_ERR_WRITE_TARGET_IN_METHOD, + PM_ERR_WRITE_TARGET_READONLY, + PM_ERR_WRITE_TARGET_UNEXPECTED, + PM_ERR_XSTRING_TERM, + + // These are the warning diagnostics. + PM_WARN_AMBIGUOUS_BINARY_OPERATOR, + PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_MINUS, + PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_PLUS, + PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND, + PM_WARN_AMBIGUOUS_PREFIX_STAR, + PM_WARN_AMBIGUOUS_PREFIX_STAR_STAR, + PM_WARN_AMBIGUOUS_SLASH, + PM_WARN_COMPARISON_AFTER_COMPARISON, + PM_WARN_DOT_DOT_DOT_EOL, + PM_WARN_EQUAL_IN_CONDITIONAL, + PM_WARN_EQUAL_IN_CONDITIONAL_3_3, + PM_WARN_END_IN_METHOD, + PM_WARN_DUPLICATED_HASH_KEY, + PM_WARN_DUPLICATED_WHEN_CLAUSE, + PM_WARN_FLOAT_OUT_OF_RANGE, + PM_WARN_IGNORED_FROZEN_STRING_LITERAL, + PM_WARN_INDENTATION_MISMATCH, + PM_WARN_INTEGER_IN_FLIP_FLOP, + PM_WARN_INVALID_CHARACTER, + PM_WARN_INVALID_MAGIC_COMMENT_VALUE, + PM_WARN_INVALID_NUMBERED_REFERENCE, + PM_WARN_KEYWORD_EOL, + PM_WARN_LITERAL_IN_CONDITION_DEFAULT, + PM_WARN_LITERAL_IN_CONDITION_VERBOSE, + PM_WARN_SHAREABLE_CONSTANT_VALUE_LINE, + PM_WARN_SHEBANG_CARRIAGE_RETURN, + PM_WARN_UNEXPECTED_CARRIAGE_RETURN, + PM_WARN_UNREACHABLE_STATEMENT, + PM_WARN_UNUSED_LOCAL_VARIABLE, + PM_WARN_VOID_STATEMENT, +} pm_diagnostic_id_t; + +/** + * This struct represents a diagnostic generated during parsing. + * + * @extends pm_list_node_t + */ +typedef struct { + /** The embedded base node. */ + pm_list_node_t node; + + /** The location of the diagnostic in the source. */ + pm_location_t location; + + /** The ID of the diagnostic. */ + pm_diagnostic_id_t diag_id; + + /** The message associated with the diagnostic. */ + const char *message; + + /** + * Whether or not the memory related to the message of this diagnostic is + * owned by this diagnostic. If it is, it needs to be freed when the + * diagnostic is freed. + */ + bool owned; + + /** + * The level of the diagnostic, see `pm_error_level_t` and + * `pm_warning_level_t` for possible values. + */ + uint8_t level; +} pm_diagnostic_t; + +/** + * The levels of errors generated during parsing. + */ +typedef enum { + /** For errors that should raise a syntax error. */ + PM_ERROR_LEVEL_SYNTAX = 0, + + /** For errors that should raise an argument error. */ + PM_ERROR_LEVEL_ARGUMENT = 1, + + /** For errors that should raise a load error. */ + PM_ERROR_LEVEL_LOAD = 2 +} pm_error_level_t; + +/** + * The levels of warnings generated during parsing. + */ +typedef enum { + /** For warnings which should be emitted if $VERBOSE != nil. */ + PM_WARNING_LEVEL_DEFAULT = 0, + + /** For warnings which should be emitted if $VERBOSE == true. */ + PM_WARNING_LEVEL_VERBOSE = 1 +} pm_warning_level_t; + +/** + * Get the human-readable name of the given diagnostic ID. + * + * @param diag_id The diagnostic ID. + * @return The human-readable name of the diagnostic ID. + */ +const char * pm_diagnostic_id_human(pm_diagnostic_id_t diag_id); + +/** + * Append a diagnostic to the given list of diagnostics that is using shared + * memory for its message. + * + * @param list The list to append to. + * @param start The start of the diagnostic. + * @param end The end of the diagnostic. + * @param diag_id The diagnostic ID. + * @return Whether the diagnostic was successfully appended. + */ +bool pm_diagnostic_list_append(pm_list_t *list, const uint8_t *start, const uint8_t *end, pm_diagnostic_id_t diag_id); + +/** + * Append a diagnostic to the given list of diagnostics that is using a format + * string for its message. + * + * @param list The list to append to. + * @param start The start of the diagnostic. + * @param end The end of the diagnostic. + * @param diag_id The diagnostic ID. + * @param ... The arguments to the format string for the message. + * @return Whether the diagnostic was successfully appended. + */ +bool pm_diagnostic_list_append_format(pm_list_t *list, const uint8_t *start, const uint8_t *end, pm_diagnostic_id_t diag_id, ...); + +/** + * Deallocate the internal state of the given diagnostic list. + * + * @param list The list to deallocate. + */ +void pm_diagnostic_list_free(pm_list_t *list); + +#endif diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/encoding.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/encoding.h new file mode 100644 index 0000000..5f77248 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/encoding.h @@ -0,0 +1,283 @@ +/** + * @file encoding.h + * + * The encoding interface and implementations used by the parser. + */ +#ifndef PRISM_ENCODING_H +#define PRISM_ENCODING_H + +#include "prism/defines.h" +#include "prism/util/pm_strncasecmp.h" + +#include +#include +#include +#include + +/** + * This struct defines the functions necessary to implement the encoding + * interface so we can determine how many bytes the subsequent character takes. + * Each callback should return the number of bytes, or 0 if the next bytes are + * invalid for the encoding and type. + */ +typedef struct { + /** + * Return the number of bytes that the next character takes if it is valid + * in the encoding. Does not read more than n bytes. It is assumed that n is + * at least 1. + */ + size_t (*char_width)(const uint8_t *b, ptrdiff_t n); + + /** + * Return the number of bytes that the next character takes if it is valid + * in the encoding and is alphabetical. Does not read more than n bytes. It + * is assumed that n is at least 1. + */ + size_t (*alpha_char)(const uint8_t *b, ptrdiff_t n); + + /** + * Return the number of bytes that the next character takes if it is valid + * in the encoding and is alphanumeric. Does not read more than n bytes. It + * is assumed that n is at least 1. + */ + size_t (*alnum_char)(const uint8_t *b, ptrdiff_t n); + + /** + * Return true if the next character is valid in the encoding and is an + * uppercase character. Does not read more than n bytes. It is assumed that + * n is at least 1. + */ + bool (*isupper_char)(const uint8_t *b, ptrdiff_t n); + + /** + * The name of the encoding. This should correspond to a value that can be + * passed to Encoding.find in Ruby. + */ + const char *name; + + /** + * Return true if the encoding is a multibyte encoding. + */ + bool multibyte; +} pm_encoding_t; + +/** + * All of the lookup tables use the first bit of each embedded byte to indicate + * whether the codepoint is alphabetical. + */ +#define PRISM_ENCODING_ALPHABETIC_BIT 1 << 0 + +/** + * All of the lookup tables use the second bit of each embedded byte to indicate + * whether the codepoint is alphanumeric. + */ +#define PRISM_ENCODING_ALPHANUMERIC_BIT 1 << 1 + +/** + * All of the lookup tables use the third bit of each embedded byte to indicate + * whether the codepoint is uppercase. + */ +#define PRISM_ENCODING_UPPERCASE_BIT 1 << 2 + +/** + * Return the size of the next character in the UTF-8 encoding. + * + * @param b The bytes to read. + * @param n The number of bytes that can be read. + * @returns The number of bytes that the next character takes if it is valid in + * the encoding, or 0 if it is not. + */ +size_t pm_encoding_utf_8_char_width(const uint8_t *b, ptrdiff_t n); + +/** + * Return the size of the next character in the UTF-8 encoding if it is an + * alphabetical character. + * + * @param b The bytes to read. + * @param n The number of bytes that can be read. + * @returns The number of bytes that the next character takes if it is valid in + * the encoding, or 0 if it is not. + */ +size_t pm_encoding_utf_8_alpha_char(const uint8_t *b, ptrdiff_t n); + +/** + * Return the size of the next character in the UTF-8 encoding if it is an + * alphanumeric character. + * + * @param b The bytes to read. + * @param n The number of bytes that can be read. + * @returns The number of bytes that the next character takes if it is valid in + * the encoding, or 0 if it is not. + */ +size_t pm_encoding_utf_8_alnum_char(const uint8_t *b, ptrdiff_t n); + +/** + * Return true if the next character in the UTF-8 encoding if it is an uppercase + * character. + * + * @param b The bytes to read. + * @param n The number of bytes that can be read. + * @returns True if the next character is valid in the encoding and is an + * uppercase character, or false if it is not. + */ +bool pm_encoding_utf_8_isupper_char(const uint8_t *b, ptrdiff_t n); + +/** + * This lookup table is referenced in both the UTF-8 encoding file and the + * parser directly in order to speed up the default encoding processing. It is + * used to indicate whether a character is alphabetical, alphanumeric, or + * uppercase in unicode mappings. + */ +extern const uint8_t pm_encoding_unicode_table[256]; + +/** + * These are all of the encodings that prism supports. + */ +typedef enum { + PM_ENCODING_UTF_8 = 0, + PM_ENCODING_US_ASCII, + PM_ENCODING_ASCII_8BIT, + PM_ENCODING_EUC_JP, + PM_ENCODING_WINDOWS_31J, + +// We optionally support excluding the full set of encodings to only support the +// minimum necessary to process Ruby code without encoding comments. +#ifndef PRISM_ENCODING_EXCLUDE_FULL + PM_ENCODING_BIG5, + PM_ENCODING_BIG5_HKSCS, + PM_ENCODING_BIG5_UAO, + PM_ENCODING_CESU_8, + PM_ENCODING_CP51932, + PM_ENCODING_CP850, + PM_ENCODING_CP852, + PM_ENCODING_CP855, + PM_ENCODING_CP949, + PM_ENCODING_CP950, + PM_ENCODING_CP951, + PM_ENCODING_EMACS_MULE, + PM_ENCODING_EUC_JP_MS, + PM_ENCODING_EUC_JIS_2004, + PM_ENCODING_EUC_KR, + PM_ENCODING_EUC_TW, + PM_ENCODING_GB12345, + PM_ENCODING_GB18030, + PM_ENCODING_GB1988, + PM_ENCODING_GB2312, + PM_ENCODING_GBK, + PM_ENCODING_IBM437, + PM_ENCODING_IBM720, + PM_ENCODING_IBM737, + PM_ENCODING_IBM775, + PM_ENCODING_IBM852, + PM_ENCODING_IBM855, + PM_ENCODING_IBM857, + PM_ENCODING_IBM860, + PM_ENCODING_IBM861, + PM_ENCODING_IBM862, + PM_ENCODING_IBM863, + PM_ENCODING_IBM864, + PM_ENCODING_IBM865, + PM_ENCODING_IBM866, + PM_ENCODING_IBM869, + PM_ENCODING_ISO_8859_1, + PM_ENCODING_ISO_8859_2, + PM_ENCODING_ISO_8859_3, + PM_ENCODING_ISO_8859_4, + PM_ENCODING_ISO_8859_5, + PM_ENCODING_ISO_8859_6, + PM_ENCODING_ISO_8859_7, + PM_ENCODING_ISO_8859_8, + PM_ENCODING_ISO_8859_9, + PM_ENCODING_ISO_8859_10, + PM_ENCODING_ISO_8859_11, + PM_ENCODING_ISO_8859_13, + PM_ENCODING_ISO_8859_14, + PM_ENCODING_ISO_8859_15, + PM_ENCODING_ISO_8859_16, + PM_ENCODING_KOI8_R, + PM_ENCODING_KOI8_U, + PM_ENCODING_MAC_CENT_EURO, + PM_ENCODING_MAC_CROATIAN, + PM_ENCODING_MAC_CYRILLIC, + PM_ENCODING_MAC_GREEK, + PM_ENCODING_MAC_ICELAND, + PM_ENCODING_MAC_JAPANESE, + PM_ENCODING_MAC_ROMAN, + PM_ENCODING_MAC_ROMANIA, + PM_ENCODING_MAC_THAI, + PM_ENCODING_MAC_TURKISH, + PM_ENCODING_MAC_UKRAINE, + PM_ENCODING_SHIFT_JIS, + PM_ENCODING_SJIS_DOCOMO, + PM_ENCODING_SJIS_KDDI, + PM_ENCODING_SJIS_SOFTBANK, + PM_ENCODING_STATELESS_ISO_2022_JP, + PM_ENCODING_STATELESS_ISO_2022_JP_KDDI, + PM_ENCODING_TIS_620, + PM_ENCODING_UTF8_MAC, + PM_ENCODING_UTF8_DOCOMO, + PM_ENCODING_UTF8_KDDI, + PM_ENCODING_UTF8_SOFTBANK, + PM_ENCODING_WINDOWS_1250, + PM_ENCODING_WINDOWS_1251, + PM_ENCODING_WINDOWS_1252, + PM_ENCODING_WINDOWS_1253, + PM_ENCODING_WINDOWS_1254, + PM_ENCODING_WINDOWS_1255, + PM_ENCODING_WINDOWS_1256, + PM_ENCODING_WINDOWS_1257, + PM_ENCODING_WINDOWS_1258, + PM_ENCODING_WINDOWS_874, +#endif + + PM_ENCODING_MAXIMUM +} pm_encoding_type_t; + +/** + * This is the table of all of the encodings that prism supports. + */ +extern const pm_encoding_t pm_encodings[PM_ENCODING_MAXIMUM]; + +/** + * This is the default UTF-8 encoding. We need a reference to it to quickly + * create parsers. + */ +#define PM_ENCODING_UTF_8_ENTRY (&pm_encodings[PM_ENCODING_UTF_8]) + +/** + * This is the US-ASCII encoding. We need a reference to it to be able to + * compare against it when a string is being created because it could possibly + * need to fall back to ASCII-8BIT. + */ +#define PM_ENCODING_US_ASCII_ENTRY (&pm_encodings[PM_ENCODING_US_ASCII]) + +/** + * This is the ASCII-8BIT encoding. We need a reference to it so that pm_strpbrk + * can compare against it because invalid multibyte characters are not a thing + * in this encoding. It is also needed for handling Regexp encoding flags. + */ +#define PM_ENCODING_ASCII_8BIT_ENTRY (&pm_encodings[PM_ENCODING_ASCII_8BIT]) + +/** + * This is the EUC-JP encoding. We need a reference to it to quickly process + * regular expression modifiers. + */ +#define PM_ENCODING_EUC_JP_ENTRY (&pm_encodings[PM_ENCODING_EUC_JP]) + +/** + * This is the Windows-31J encoding. We need a reference to it to quickly + * process regular expression modifiers. + */ +#define PM_ENCODING_WINDOWS_31J_ENTRY (&pm_encodings[PM_ENCODING_WINDOWS_31J]) + +/** + * Parse the given name of an encoding and return a pointer to the corresponding + * encoding struct if one can be found, otherwise return NULL. + * + * @param start A pointer to the first byte of the name. + * @param end A pointer to the last byte of the name. + * @returns A pointer to the encoding struct if one is found, otherwise NULL. + */ +const pm_encoding_t * pm_encoding_find(const uint8_t *start, const uint8_t *end); + +#endif diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/extension.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/extension.h new file mode 100644 index 0000000..70017a4 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/extension.h @@ -0,0 +1,19 @@ +#ifndef PRISM_EXT_NODE_H +#define PRISM_EXT_NODE_H + +#define EXPECTED_PRISM_VERSION "1.6.0" + +#include +#include +#include "prism.h" + +VALUE pm_source_new(const pm_parser_t *parser, rb_encoding *encoding, bool freeze); +VALUE pm_token_new(const pm_parser_t *parser, const pm_token_t *token, rb_encoding *encoding, VALUE source, bool freeze); +VALUE pm_ast_new(const pm_parser_t *parser, const pm_node_t *node, rb_encoding *encoding, VALUE source, bool freeze); +VALUE pm_integer_new(const pm_integer_t *integer); + +void Init_prism_api_node(void); +void Init_prism_pack(void); +RUBY_FUNC_EXPORTED void Init_prism(void); + +#endif diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/node.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/node.h new file mode 100644 index 0000000..e8686a3 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/node.h @@ -0,0 +1,129 @@ +/** + * @file node.h + * + * Functions related to nodes in the AST. + */ +#ifndef PRISM_NODE_H +#define PRISM_NODE_H + +#include "prism/defines.h" +#include "prism/parser.h" +#include "prism/util/pm_buffer.h" + +/** + * Loop through each node in the node list, writing each node to the given + * pm_node_t pointer. + */ +#define PM_NODE_LIST_FOREACH(list, index, node) \ + for (size_t index = 0; index < (list)->size && ((node) = (list)->nodes[index]); index++) + +/** + * Append a new node onto the end of the node list. + * + * @param list The list to append to. + * @param node The node to append. + */ +void pm_node_list_append(pm_node_list_t *list, pm_node_t *node); + +/** + * Prepend a new node onto the beginning of the node list. + * + * @param list The list to prepend to. + * @param node The node to prepend. + */ +void pm_node_list_prepend(pm_node_list_t *list, pm_node_t *node); + +/** + * Concatenate the given node list onto the end of the other node list. + * + * @param list The list to concatenate onto. + * @param other The list to concatenate. + */ +void pm_node_list_concat(pm_node_list_t *list, pm_node_list_t *other); + +/** + * Free the internal memory associated with the given node list. + * + * @param list The list to free. + */ +void pm_node_list_free(pm_node_list_t *list); + +/** + * Deallocate a node and all of its children. + * + * @param parser The parser that owns the node. + * @param node The node to deallocate. + */ +PRISM_EXPORTED_FUNCTION void pm_node_destroy(pm_parser_t *parser, struct pm_node *node); + +/** + * Returns a string representation of the given node type. + * + * @param node_type The node type to convert to a string. + * @return A string representation of the given node type. + */ +PRISM_EXPORTED_FUNCTION const char * pm_node_type_to_str(pm_node_type_t node_type); + +/** + * Visit each of the nodes in this subtree using the given visitor callback. The + * callback function will be called for each node in the subtree. If it returns + * false, then that node's children will not be visited. If it returns true, + * then the children will be visited. The data parameter is treated as an opaque + * pointer and is passed to the visitor callback for consumers to use as they + * see fit. + * + * As an example: + * + * ```c + * #include "prism.h" + * + * bool visit(const pm_node_t *node, void *data) { + * size_t *indent = (size_t *) data; + * for (size_t i = 0; i < *indent * 2; i++) putc(' ', stdout); + * printf("%s\n", pm_node_type_to_str(node->type)); + * + * size_t next_indent = *indent + 1; + * size_t *next_data = &next_indent; + * pm_visit_child_nodes(node, visit, next_data); + * + * return false; + * } + * + * int main(void) { + * const char *source = "1 + 2; 3 + 4"; + * size_t size = strlen(source); + * + * pm_parser_t parser; + * pm_options_t options = { 0 }; + * pm_parser_init(&parser, (const uint8_t *) source, size, &options); + * + * size_t indent = 0; + * pm_node_t *node = pm_parse(&parser); + * + * size_t *data = &indent; + * pm_visit_node(node, visit, data); + * + * pm_node_destroy(&parser, node); + * pm_parser_free(&parser); + * return EXIT_SUCCESS; + * } + * ``` + * + * @param node The root node to start visiting from. + * @param visitor The callback to call for each node in the subtree. + * @param data An opaque pointer that is passed to the visitor callback. + */ +PRISM_EXPORTED_FUNCTION void pm_visit_node(const pm_node_t *node, bool (*visitor)(const pm_node_t *node, void *data), void *data); + +/** + * Visit the children of the given node with the given callback. This is the + * default behavior for walking the tree that is called from pm_visit_node if + * the callback returns true. + * + * @param node The node to visit the children of. + * @param visitor The callback to call for each child node. + * @param data An opaque pointer that is passed to the visitor callback. + */ +PRISM_EXPORTED_FUNCTION void pm_visit_child_nodes(const pm_node_t *node, bool (*visitor)(const pm_node_t *node, void *data), void *data); + +#endif diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/options.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/options.h new file mode 100644 index 0000000..a663c97 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/options.h @@ -0,0 +1,485 @@ +/** + * @file options.h + * + * The options that can be passed to parsing. + */ +#ifndef PRISM_OPTIONS_H +#define PRISM_OPTIONS_H + +#include "prism/defines.h" +#include "prism/util/pm_char.h" +#include "prism/util/pm_string.h" + +#include +#include +#include + +/** + * String literals should be made frozen. + */ +#define PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED ((int8_t) -1) + +/** + * String literals may be frozen or mutable depending on the implementation + * default. + */ +#define PM_OPTIONS_FROZEN_STRING_LITERAL_UNSET ((int8_t) 0) + +/** + * String literals should be made mutable. + */ +#define PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED ((int8_t) 1) + +/** + * A scope of locals surrounding the code that is being parsed. + */ +typedef struct pm_options_scope { + /** The number of locals in the scope. */ + size_t locals_count; + + /** The names of the locals in the scope. */ + pm_string_t *locals; + + /** Flags for the set of forwarding parameters in this scope. */ + uint8_t forwarding; +} pm_options_scope_t; + +/** The default value for parameters. */ +static const uint8_t PM_OPTIONS_SCOPE_FORWARDING_NONE = 0x0; + +/** When the scope is fowarding with the * parameter. */ +static const uint8_t PM_OPTIONS_SCOPE_FORWARDING_POSITIONALS = 0x1; + +/** When the scope is fowarding with the ** parameter. */ +static const uint8_t PM_OPTIONS_SCOPE_FORWARDING_KEYWORDS = 0x2; + +/** When the scope is fowarding with the & parameter. */ +static const uint8_t PM_OPTIONS_SCOPE_FORWARDING_BLOCK = 0x4; + +/** When the scope is fowarding with the ... parameter. */ +static const uint8_t PM_OPTIONS_SCOPE_FORWARDING_ALL = 0x8; + +// Forward declaration needed by the callback typedef. +struct pm_options; + +/** + * The callback called when additional switches are found in a shebang comment + * that need to be processed by the runtime. + * + * @param options The options struct that may be updated by this callback. + * Certain fields will be checked for changes, specifically encoding, + * command_line, and frozen_string_literal. + * @param source The source of the shebang comment. + * @param length The length of the source. + * @param shebang_callback_data Any additional data that should be passed along + * to the callback. + */ +typedef void (*pm_options_shebang_callback_t)(struct pm_options *options, const uint8_t *source, size_t length, void *shebang_callback_data); + +/** + * The version of Ruby syntax that we should be parsing with. This is used to + * allow consumers to specify which behavior they want in case they need to + * parse in the same way as a specific version of CRuby would have. + */ +typedef enum { + /** If an explicit version is not provided, the current version of prism will be used. */ + PM_OPTIONS_VERSION_UNSET = 0, + + /** The vendored version of prism in CRuby 3.3.x. */ + PM_OPTIONS_VERSION_CRUBY_3_3 = 1, + + /** The vendored version of prism in CRuby 3.4.x. */ + PM_OPTIONS_VERSION_CRUBY_3_4 = 2, + + /** The vendored version of prism in CRuby 4.0.x. */ + PM_OPTIONS_VERSION_CRUBY_3_5 = 3, + + /** The vendored version of prism in CRuby 4.0.x. */ + PM_OPTIONS_VERSION_CRUBY_4_0 = 3, + + /** The current version of prism. */ + PM_OPTIONS_VERSION_LATEST = PM_OPTIONS_VERSION_CRUBY_4_0 +} pm_options_version_t; + +/** + * The options that can be passed to the parser. + */ +typedef struct pm_options { + /** + * The callback to call when additional switches are found in a shebang + * comment. + */ + pm_options_shebang_callback_t shebang_callback; + + /** + * Any additional data that should be passed along to the shebang callback + * if one was set. + */ + void *shebang_callback_data; + + /** The name of the file that is currently being parsed. */ + pm_string_t filepath; + + /** + * The line within the file that the parse starts on. This value is + * 1-indexed. + */ + int32_t line; + + /** + * The name of the encoding that the source file is in. Note that this must + * correspond to a name that can be found with Encoding.find in Ruby. + */ + pm_string_t encoding; + + /** + * The number of scopes surrounding the code that is being parsed. + */ + size_t scopes_count; + + /** + * The scopes surrounding the code that is being parsed. For most parses + * this will be NULL, but for evals it will be the locals that are in scope + * surrounding the eval. Scopes are ordered from the outermost scope to the + * innermost one. + */ + pm_options_scope_t *scopes; + + /** + * The version of prism that we should be parsing with. This is used to + * allow consumers to specify which behavior they want in case they need to + * parse exactly as a specific version of CRuby. + */ + pm_options_version_t version; + + /** A bitset of the various options that were set on the command line. */ + uint8_t command_line; + + /** + * Whether or not the frozen string literal option has been set. + * May be: + * - PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED + * - PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED + * - PM_OPTIONS_FROZEN_STRING_LITERAL_UNSET + */ + int8_t frozen_string_literal; + + /** + * Whether or not the encoding magic comments should be respected. This is a + * niche use-case where you want to parse a file with a specific encoding + * but ignore any encoding magic comments at the top of the file. + */ + bool encoding_locked; + + /** + * When the file being parsed is the main script, the shebang will be + * considered for command-line flags (or for implicit -x). The caller needs + * to pass this information to the parser so that it can behave correctly. + */ + bool main_script; + + /** + * When the file being parsed is considered a "partial" script, jumps will + * not be marked as errors if they are not contained within loops/blocks. + * This is used in the case that you're parsing a script that you know will + * be embedded inside another script later, but you do not have that context + * yet. For example, when parsing an ERB template that will be evaluated + * inside another script. + */ + bool partial_script; + + /** + * Whether or not the parser should freeze the nodes that it creates. This + * makes it possible to have a deeply frozen AST that is safe to share + * between concurrency primitives. + */ + bool freeze; +} pm_options_t; + +/** + * A bit representing whether or not the command line -a option was set. -a + * splits the input line $_ into $F. + */ +static const uint8_t PM_OPTIONS_COMMAND_LINE_A = 0x1; + +/** + * A bit representing whether or not the command line -e option was set. -e + * allow the user to specify a script to be executed. This is necessary for + * prism to know because certain warnings are not generated when -e is used. + */ +static const uint8_t PM_OPTIONS_COMMAND_LINE_E = 0x2; + +/** + * A bit representing whether or not the command line -l option was set. -l + * chomps the input line by default. + */ +static const uint8_t PM_OPTIONS_COMMAND_LINE_L = 0x4; + +/** + * A bit representing whether or not the command line -n option was set. -n + * wraps the script in a while gets loop. + */ +static const uint8_t PM_OPTIONS_COMMAND_LINE_N = 0x8; + +/** + * A bit representing whether or not the command line -p option was set. -p + * prints the value of $_ at the end of each loop. + */ +static const uint8_t PM_OPTIONS_COMMAND_LINE_P = 0x10; + +/** + * A bit representing whether or not the command line -x option was set. -x + * searches the input file for a shebang that matches the current Ruby engine. + */ +static const uint8_t PM_OPTIONS_COMMAND_LINE_X = 0x20; + +/** + * Set the shebang callback option on the given options struct. + * + * @param options The options struct to set the shebang callback on. + * @param shebang_callback The shebang callback to set. + * @param shebang_callback_data Any additional data that should be passed along + * to the callback. + * + * \public \memberof pm_options + */ +PRISM_EXPORTED_FUNCTION void pm_options_shebang_callback_set(pm_options_t *options, pm_options_shebang_callback_t shebang_callback, void *shebang_callback_data); + +/** + * Set the filepath option on the given options struct. + * + * @param options The options struct to set the filepath on. + * @param filepath The filepath to set. + * + * \public \memberof pm_options + */ +PRISM_EXPORTED_FUNCTION void pm_options_filepath_set(pm_options_t *options, const char *filepath); + +/** + * Set the line option on the given options struct. + * + * @param options The options struct to set the line on. + * @param line The line to set. + * + * \public \memberof pm_options + */ +PRISM_EXPORTED_FUNCTION void pm_options_line_set(pm_options_t *options, int32_t line); + +/** + * Set the encoding option on the given options struct. + * + * @param options The options struct to set the encoding on. + * @param encoding The encoding to set. + * + * \public \memberof pm_options + */ +PRISM_EXPORTED_FUNCTION void pm_options_encoding_set(pm_options_t *options, const char *encoding); + +/** + * Set the encoding_locked option on the given options struct. + * + * @param options The options struct to set the encoding_locked value on. + * @param encoding_locked The encoding_locked value to set. + * + * \public \memberof pm_options + */ +PRISM_EXPORTED_FUNCTION void pm_options_encoding_locked_set(pm_options_t *options, bool encoding_locked); + +/** + * Set the frozen string literal option on the given options struct. + * + * @param options The options struct to set the frozen string literal value on. + * @param frozen_string_literal The frozen string literal value to set. + * + * \public \memberof pm_options + */ +PRISM_EXPORTED_FUNCTION void pm_options_frozen_string_literal_set(pm_options_t *options, bool frozen_string_literal); + +/** + * Sets the command line option on the given options struct. + * + * @param options The options struct to set the command line option on. + * @param command_line The command_line value to set. + * + * \public \memberof pm_options + */ +PRISM_EXPORTED_FUNCTION void pm_options_command_line_set(pm_options_t *options, uint8_t command_line); + +/** + * Set the version option on the given options struct by parsing the given + * string. If the string contains an invalid option, this returns false. + * Otherwise, it returns true. + * + * @param options The options struct to set the version on. + * @param version The version to set. + * @param length The length of the version string. + * @return Whether or not the version was parsed successfully. + * + * \public \memberof pm_options + */ +PRISM_EXPORTED_FUNCTION bool pm_options_version_set(pm_options_t *options, const char *version, size_t length); + +/** + * Set the main script option on the given options struct. + * + * @param options The options struct to set the main script value on. + * @param main_script The main script value to set. + * + * \public \memberof pm_options + */ +PRISM_EXPORTED_FUNCTION void pm_options_main_script_set(pm_options_t *options, bool main_script); + +/** + * Set the partial script option on the given options struct. + * + * @param options The options struct to set the partial script value on. + * @param partial_script The partial script value to set. + * + * \public \memberof pm_options + */ +PRISM_EXPORTED_FUNCTION void pm_options_partial_script_set(pm_options_t *options, bool partial_script); + +/** + * Set the freeze option on the given options struct. + * + * @param options The options struct to set the freeze value on. + * @param freeze The freeze value to set. + * + * \public \memberof pm_options + */ +PRISM_EXPORTED_FUNCTION void pm_options_freeze_set(pm_options_t *options, bool freeze); + +/** + * Allocate and zero out the scopes array on the given options struct. + * + * @param options The options struct to initialize the scopes array on. + * @param scopes_count The number of scopes to allocate. + * @return Whether or not the scopes array was initialized successfully. + * + * \public \memberof pm_options + */ +PRISM_EXPORTED_FUNCTION bool pm_options_scopes_init(pm_options_t *options, size_t scopes_count); + +/** + * Return a pointer to the scope at the given index within the given options. + * + * @param options The options struct to get the scope from. + * @param index The index of the scope to get. + * @return A pointer to the scope at the given index. + * + * \public \memberof pm_options + */ +PRISM_EXPORTED_FUNCTION const pm_options_scope_t * pm_options_scope_get(const pm_options_t *options, size_t index); + +/** + * Create a new options scope struct. This will hold a set of locals that are in + * scope surrounding the code that is being parsed. + * + * @param scope The scope struct to initialize. + * @param locals_count The number of locals to allocate. + * @return Whether or not the scope was initialized successfully. + * + * \public \memberof pm_options + */ +PRISM_EXPORTED_FUNCTION bool pm_options_scope_init(pm_options_scope_t *scope, size_t locals_count); + +/** + * Return a pointer to the local at the given index within the given scope. + * + * @param scope The scope struct to get the local from. + * @param index The index of the local to get. + * @return A pointer to the local at the given index. + * + * \public \memberof pm_options + */ +PRISM_EXPORTED_FUNCTION const pm_string_t * pm_options_scope_local_get(const pm_options_scope_t *scope, size_t index); + +/** + * Set the forwarding option on the given scope struct. + * + * @param scope The scope struct to set the forwarding on. + * @param forwarding The forwarding value to set. + * + * \public \memberof pm_options + */ +PRISM_EXPORTED_FUNCTION void pm_options_scope_forwarding_set(pm_options_scope_t *scope, uint8_t forwarding); + +/** + * Free the internal memory associated with the options. + * + * @param options The options struct whose internal memory should be freed. + * + * \public \memberof pm_options + */ +PRISM_EXPORTED_FUNCTION void pm_options_free(pm_options_t *options); + +/** + * Deserialize an options struct from the given binary string. This is used to + * pass options to the parser from an FFI call so that consumers of the library + * from an FFI perspective don't have to worry about the structure of our + * options structs. Since the source of these calls will be from Ruby + * implementation internals we assume it is from a trusted source. + * + * `data` is assumed to be a valid pointer pointing to well-formed data. The + * layout of this data should be the same every time, and is described below: + * + * | # bytes | field | + * | ------- | -------------------------- | + * | `4` | the length of the filepath | + * | ... | the filepath bytes | + * | `4` | the line number | + * | `4` | the length the encoding | + * | ... | the encoding bytes | + * | `1` | frozen string literal | + * | `1` | -p command line option | + * | `1` | -n command line option | + * | `1` | -l command line option | + * | `1` | -a command line option | + * | `1` | the version | + * | `1` | encoding locked | + * | `1` | main script | + * | `1` | partial script | + * | `1` | freeze | + * | `4` | the number of scopes | + * | ... | the scopes | + * + * The version field is an enum, so it should be one of the following values: + * + * | value | version | + * | ----- | ------------------------- | + * | `0` | use the latest version of prism | + * | `1` | use the version of prism that is vendored in CRuby 3.3.0 | + * + * Each scope is laid out as follows: + * + * | # bytes | field | + * | ------- | -------------------------- | + * | `4` | the number of locals | + * | `1` | the forwarding flags | + * | ... | the locals | + * + * Each local is laid out as follows: + * + * | # bytes | field | + * | ------- | -------------------------- | + * | `4` | the length of the local | + * | ... | the local bytes | + * + * Some additional things to note about this layout: + * + * * The filepath can have a length of 0, in which case we'll consider it an + * empty string. + * * The line number should be 0-indexed. + * * The encoding can have a length of 0, in which case we'll use the default + * encoding (UTF-8). If it's not 0, it should correspond to a name of an + * encoding that can be passed to `Encoding.find` in Ruby. + * * The frozen string literal, encoding locked, main script, and partial script + * fields are booleans, so their values should be either 0 or 1. + * * The number of scopes can be 0. + * + * @param options The options struct to deserialize into. + * @param data The binary string to deserialize from. + */ +void pm_options_read(pm_options_t *options, const char *data); + +#endif diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/pack.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/pack.h new file mode 100644 index 0000000..0b0b4b1 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/pack.h @@ -0,0 +1,163 @@ +/** + * @file pack.h + * + * A pack template string parser. + */ +#ifndef PRISM_PACK_H +#define PRISM_PACK_H + +#include "prism/defines.h" + +// We optionally support parsing String#pack templates. For systems that don't +// want or need this functionality, it can be turned off with the +// PRISM_EXCLUDE_PACK define. +#ifdef PRISM_EXCLUDE_PACK + +void pm_pack_parse(void); + +#else + +#include +#include + +/** The version of the pack template language that we are parsing. */ +typedef enum pm_pack_version { + PM_PACK_VERSION_3_2_0 +} pm_pack_version; + +/** The type of pack template we are parsing. */ +typedef enum pm_pack_variant { + PM_PACK_VARIANT_PACK, + PM_PACK_VARIANT_UNPACK +} pm_pack_variant; + +/** A directive within the pack template. */ +typedef enum pm_pack_type { + PM_PACK_SPACE, + PM_PACK_COMMENT, + PM_PACK_INTEGER, + PM_PACK_UTF8, + PM_PACK_BER, + PM_PACK_FLOAT, + PM_PACK_STRING_SPACE_PADDED, + PM_PACK_STRING_NULL_PADDED, + PM_PACK_STRING_NULL_TERMINATED, + PM_PACK_STRING_MSB, + PM_PACK_STRING_LSB, + PM_PACK_STRING_HEX_HIGH, + PM_PACK_STRING_HEX_LOW, + PM_PACK_STRING_UU, + PM_PACK_STRING_MIME, + PM_PACK_STRING_BASE64, + PM_PACK_STRING_FIXED, + PM_PACK_STRING_POINTER, + PM_PACK_MOVE, + PM_PACK_BACK, + PM_PACK_NULL, + PM_PACK_END +} pm_pack_type; + +/** The signness of a pack directive. */ +typedef enum pm_pack_signed { + PM_PACK_UNSIGNED, + PM_PACK_SIGNED, + PM_PACK_SIGNED_NA +} pm_pack_signed; + +/** The endianness of a pack directive. */ +typedef enum pm_pack_endian { + PM_PACK_AGNOSTIC_ENDIAN, + PM_PACK_LITTLE_ENDIAN, // aka 'VAX', or 'V' + PM_PACK_BIG_ENDIAN, // aka 'network', or 'N' + PM_PACK_NATIVE_ENDIAN, + PM_PACK_ENDIAN_NA +} pm_pack_endian; + +/** The size of an integer pack directive. */ +typedef enum pm_pack_size { + PM_PACK_SIZE_SHORT, + PM_PACK_SIZE_INT, + PM_PACK_SIZE_LONG, + PM_PACK_SIZE_LONG_LONG, + PM_PACK_SIZE_8, + PM_PACK_SIZE_16, + PM_PACK_SIZE_32, + PM_PACK_SIZE_64, + PM_PACK_SIZE_P, + PM_PACK_SIZE_NA +} pm_pack_size; + +/** The type of length of a pack directive. */ +typedef enum pm_pack_length_type { + PM_PACK_LENGTH_FIXED, + PM_PACK_LENGTH_MAX, + PM_PACK_LENGTH_RELATIVE, // special case for unpack @* + PM_PACK_LENGTH_NA +} pm_pack_length_type; + +/** The type of encoding for a pack template string. */ +typedef enum pm_pack_encoding { + PM_PACK_ENCODING_START, + PM_PACK_ENCODING_ASCII_8BIT, + PM_PACK_ENCODING_US_ASCII, + PM_PACK_ENCODING_UTF_8 +} pm_pack_encoding; + +/** The result of parsing a pack template. */ +typedef enum pm_pack_result { + PM_PACK_OK, + PM_PACK_ERROR_UNSUPPORTED_DIRECTIVE, + PM_PACK_ERROR_UNKNOWN_DIRECTIVE, + PM_PACK_ERROR_LENGTH_TOO_BIG, + PM_PACK_ERROR_BANG_NOT_ALLOWED, + PM_PACK_ERROR_DOUBLE_ENDIAN +} pm_pack_result; + +/** + * Parse a single directive from a pack or unpack format string. + * + * @param variant (in) pack or unpack + * @param format (in, out) the start of the next directive to parse on calling, + * and advanced beyond the parsed directive on return, or as much of it as + * was consumed until an error was encountered + * @param format_end (in) the end of the format string + * @param type (out) the type of the directive + * @param signed_type (out) whether the value is signed + * @param endian (out) the endianness of the value + * @param size (out) the size of the value + * @param length_type (out) what kind of length is specified + * @param length (out) the length of the directive + * @param encoding (in, out) takes the current encoding of the string which + * would result from parsing the whole format string, and returns a possibly + * changed directive - the encoding should be `PM_PACK_ENCODING_START` when + * pm_pack_parse is called for the first directive in a format string + * + * @return `PM_PACK_OK` on success or `PM_PACK_ERROR_*` on error + * @note Consult Ruby documentation for the meaning of directives. + */ +PRISM_EXPORTED_FUNCTION pm_pack_result +pm_pack_parse( + pm_pack_variant variant, + const char **format, + const char *format_end, + pm_pack_type *type, + pm_pack_signed *signed_type, + pm_pack_endian *endian, + pm_pack_size *size, + pm_pack_length_type *length_type, + uint64_t *length, + pm_pack_encoding *encoding +); + +/** + * Prism abstracts sizes away from the native system - this converts an abstract + * size to a native size. + * + * @param size The abstract size to convert. + * @return The native size. + */ +PRISM_EXPORTED_FUNCTION size_t pm_size_to_native(pm_pack_size size); + +#endif + +#endif diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/parser.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/parser.h new file mode 100644 index 0000000..95d7aac --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/parser.h @@ -0,0 +1,936 @@ +/** + * @file parser.h + * + * The parser used to parse Ruby source. + */ +#ifndef PRISM_PARSER_H +#define PRISM_PARSER_H + +#include "prism/defines.h" +#include "prism/ast.h" +#include "prism/encoding.h" +#include "prism/options.h" +#include "prism/static_literals.h" +#include "prism/util/pm_constant_pool.h" +#include "prism/util/pm_list.h" +#include "prism/util/pm_newline_list.h" +#include "prism/util/pm_string.h" + +#include + +/** + * This enum provides various bits that represent different kinds of states that + * the lexer can track. This is used to determine which kind of token to return + * based on the context of the parser. + */ +typedef enum { + PM_LEX_STATE_BIT_BEG, + PM_LEX_STATE_BIT_END, + PM_LEX_STATE_BIT_ENDARG, + PM_LEX_STATE_BIT_ENDFN, + PM_LEX_STATE_BIT_ARG, + PM_LEX_STATE_BIT_CMDARG, + PM_LEX_STATE_BIT_MID, + PM_LEX_STATE_BIT_FNAME, + PM_LEX_STATE_BIT_DOT, + PM_LEX_STATE_BIT_CLASS, + PM_LEX_STATE_BIT_LABEL, + PM_LEX_STATE_BIT_LABELED, + PM_LEX_STATE_BIT_FITEM +} pm_lex_state_bit_t; + +/** + * This enum combines the various bits from the above enum into individual + * values that represent the various states of the lexer. + */ +typedef enum { + PM_LEX_STATE_NONE = 0, + PM_LEX_STATE_BEG = (1 << PM_LEX_STATE_BIT_BEG), + PM_LEX_STATE_END = (1 << PM_LEX_STATE_BIT_END), + PM_LEX_STATE_ENDARG = (1 << PM_LEX_STATE_BIT_ENDARG), + PM_LEX_STATE_ENDFN = (1 << PM_LEX_STATE_BIT_ENDFN), + PM_LEX_STATE_ARG = (1 << PM_LEX_STATE_BIT_ARG), + PM_LEX_STATE_CMDARG = (1 << PM_LEX_STATE_BIT_CMDARG), + PM_LEX_STATE_MID = (1 << PM_LEX_STATE_BIT_MID), + PM_LEX_STATE_FNAME = (1 << PM_LEX_STATE_BIT_FNAME), + PM_LEX_STATE_DOT = (1 << PM_LEX_STATE_BIT_DOT), + PM_LEX_STATE_CLASS = (1 << PM_LEX_STATE_BIT_CLASS), + PM_LEX_STATE_LABEL = (1 << PM_LEX_STATE_BIT_LABEL), + PM_LEX_STATE_LABELED = (1 << PM_LEX_STATE_BIT_LABELED), + PM_LEX_STATE_FITEM = (1 << PM_LEX_STATE_BIT_FITEM), + PM_LEX_STATE_BEG_ANY = PM_LEX_STATE_BEG | PM_LEX_STATE_MID | PM_LEX_STATE_CLASS, + PM_LEX_STATE_ARG_ANY = PM_LEX_STATE_ARG | PM_LEX_STATE_CMDARG, + PM_LEX_STATE_END_ANY = PM_LEX_STATE_END | PM_LEX_STATE_ENDARG | PM_LEX_STATE_ENDFN +} pm_lex_state_t; + +/** + * The type of quote that a heredoc uses. + */ +typedef enum { + PM_HEREDOC_QUOTE_NONE, + PM_HEREDOC_QUOTE_SINGLE = '\'', + PM_HEREDOC_QUOTE_DOUBLE = '"', + PM_HEREDOC_QUOTE_BACKTICK = '`', +} pm_heredoc_quote_t; + +/** + * The type of indentation that a heredoc uses. + */ +typedef enum { + PM_HEREDOC_INDENT_NONE, + PM_HEREDOC_INDENT_DASH, + PM_HEREDOC_INDENT_TILDE, +} pm_heredoc_indent_t; + +/** + * All of the information necessary to store to lexing a heredoc. + */ +typedef struct { + /** A pointer to the start of the heredoc identifier. */ + const uint8_t *ident_start; + + /** The length of the heredoc identifier. */ + size_t ident_length; + + /** The type of quote that the heredoc uses. */ + pm_heredoc_quote_t quote; + + /** The type of indentation that the heredoc uses. */ + pm_heredoc_indent_t indent; +} pm_heredoc_lex_mode_t; + +/** + * When lexing Ruby source, the lexer has a small amount of state to tell which + * kind of token it is currently lexing. For example, when we find the start of + * a string, the first token that we return is a TOKEN_STRING_BEGIN token. After + * that the lexer is now in the PM_LEX_STRING mode, and will return tokens that + * are found as part of a string. + */ +typedef struct pm_lex_mode { + /** The type of this lex mode. */ + enum { + /** This state is used when any given token is being lexed. */ + PM_LEX_DEFAULT, + + /** + * This state is used when we're lexing as normal but inside an embedded + * expression of a string. + */ + PM_LEX_EMBEXPR, + + /** + * This state is used when we're lexing a variable that is embedded + * directly inside of a string with the # shorthand. + */ + PM_LEX_EMBVAR, + + /** This state is used when you are inside the content of a heredoc. */ + PM_LEX_HEREDOC, + + /** + * This state is used when we are lexing a list of tokens, as in a %w + * word list literal or a %i symbol list literal. + */ + PM_LEX_LIST, + + /** + * This state is used when a regular expression has been begun and we + * are looking for the terminator. + */ + PM_LEX_REGEXP, + + /** + * This state is used when we are lexing a string or a string-like + * token, as in string content with either quote or an xstring. + */ + PM_LEX_STRING + } mode; + + /** The data associated with this type of lex mode. */ + union { + struct { + /** This keeps track of the nesting level of the list. */ + size_t nesting; + + /** Whether or not interpolation is allowed in this list. */ + bool interpolation; + + /** + * When lexing a list, it takes into account balancing the + * terminator if the terminator is one of (), [], {}, or <>. + */ + uint8_t incrementor; + + /** This is the terminator of the list literal. */ + uint8_t terminator; + + /** + * This is the character set that should be used to delimit the + * tokens within the list. + */ + uint8_t breakpoints[11]; + } list; + + struct { + /** + * This keeps track of the nesting level of the regular expression. + */ + size_t nesting; + + /** + * When lexing a regular expression, it takes into account balancing + * the terminator if the terminator is one of (), [], {}, or <>. + */ + uint8_t incrementor; + + /** This is the terminator of the regular expression. */ + uint8_t terminator; + + /** + * This is the character set that should be used to delimit the + * tokens within the regular expression. + */ + uint8_t breakpoints[7]; + } regexp; + + struct { + /** This keeps track of the nesting level of the string. */ + size_t nesting; + + /** Whether or not interpolation is allowed in this string. */ + bool interpolation; + + /** + * Whether or not at the end of the string we should allow a :, + * which would indicate this was a dynamic symbol instead of a + * string. + */ + bool label_allowed; + + /** + * When lexing a string, it takes into account balancing the + * terminator if the terminator is one of (), [], {}, or <>. + */ + uint8_t incrementor; + + /** + * This is the terminator of the string. It is typically either a + * single or double quote. + */ + uint8_t terminator; + + /** + * This is the character set that should be used to delimit the + * tokens within the string. + */ + uint8_t breakpoints[7]; + } string; + + struct { + /** + * All of the data necessary to lex a heredoc. + */ + pm_heredoc_lex_mode_t base; + + /** + * This is the pointer to the character where lexing should resume + * once the heredoc has been completely processed. + */ + const uint8_t *next_start; + + /** + * This is used to track the amount of common whitespace on each + * line so that we know how much to dedent each line in the case of + * a tilde heredoc. + */ + size_t *common_whitespace; + + /** True if the previous token ended with a line continuation. */ + bool line_continuation; + } heredoc; + } as; + + /** The previous lex state so that it knows how to pop. */ + struct pm_lex_mode *prev; +} pm_lex_mode_t; + +/** + * We pre-allocate a certain number of lex states in order to avoid having to + * call malloc too many times while parsing. You really shouldn't need more than + * this because you only really nest deeply when doing string interpolation. + */ +#define PM_LEX_STACK_SIZE 4 + +/** + * The parser used to parse Ruby source. + */ +typedef struct pm_parser pm_parser_t; + +/** + * While parsing, we keep track of a stack of contexts. This is helpful for + * error recovery so that we can pop back to a previous context when we hit a + * token that is understood by a parent context but not by the current context. + */ +typedef enum { + /** a null context, used for returning a value from a function */ + PM_CONTEXT_NONE = 0, + + /** a begin statement */ + PM_CONTEXT_BEGIN, + + /** an ensure statement with an explicit begin */ + PM_CONTEXT_BEGIN_ENSURE, + + /** a rescue else statement with an explicit begin */ + PM_CONTEXT_BEGIN_ELSE, + + /** a rescue statement with an explicit begin */ + PM_CONTEXT_BEGIN_RESCUE, + + /** expressions in block arguments using braces */ + PM_CONTEXT_BLOCK_BRACES, + + /** expressions in block arguments using do..end */ + PM_CONTEXT_BLOCK_KEYWORDS, + + /** an ensure statement within a do..end block */ + PM_CONTEXT_BLOCK_ENSURE, + + /** a rescue else statement within a do..end block */ + PM_CONTEXT_BLOCK_ELSE, + + /** expressions in block parameters `foo do |...| end ` */ + PM_CONTEXT_BLOCK_PARAMETERS, + + /** a rescue statement within a do..end block */ + PM_CONTEXT_BLOCK_RESCUE, + + /** a case when statements */ + PM_CONTEXT_CASE_WHEN, + + /** a case in statements */ + PM_CONTEXT_CASE_IN, + + /** a class declaration */ + PM_CONTEXT_CLASS, + + /** an ensure statement within a class statement */ + PM_CONTEXT_CLASS_ENSURE, + + /** a rescue else statement within a class statement */ + PM_CONTEXT_CLASS_ELSE, + + /** a rescue statement within a class statement */ + PM_CONTEXT_CLASS_RESCUE, + + /** a method definition */ + PM_CONTEXT_DEF, + + /** an ensure statement within a method definition */ + PM_CONTEXT_DEF_ENSURE, + + /** a rescue else statement within a method definition */ + PM_CONTEXT_DEF_ELSE, + + /** a rescue statement within a method definition */ + PM_CONTEXT_DEF_RESCUE, + + /** a method definition's parameters */ + PM_CONTEXT_DEF_PARAMS, + + /** a defined? expression */ + PM_CONTEXT_DEFINED, + + /** a method definition's default parameter */ + PM_CONTEXT_DEFAULT_PARAMS, + + /** an else clause */ + PM_CONTEXT_ELSE, + + /** an elsif clause */ + PM_CONTEXT_ELSIF, + + /** an interpolated expression */ + PM_CONTEXT_EMBEXPR, + + /** a for loop */ + PM_CONTEXT_FOR, + + /** a for loop's index */ + PM_CONTEXT_FOR_INDEX, + + /** an if statement */ + PM_CONTEXT_IF, + + /** a lambda expression with braces */ + PM_CONTEXT_LAMBDA_BRACES, + + /** a lambda expression with do..end */ + PM_CONTEXT_LAMBDA_DO_END, + + /** an ensure statement within a lambda expression */ + PM_CONTEXT_LAMBDA_ENSURE, + + /** a rescue else statement within a lambda expression */ + PM_CONTEXT_LAMBDA_ELSE, + + /** a rescue statement within a lambda expression */ + PM_CONTEXT_LAMBDA_RESCUE, + + /** the predicate clause of a loop statement */ + PM_CONTEXT_LOOP_PREDICATE, + + /** the top level context */ + PM_CONTEXT_MAIN, + + /** a module declaration */ + PM_CONTEXT_MODULE, + + /** an ensure statement within a module statement */ + PM_CONTEXT_MODULE_ENSURE, + + /** a rescue else statement within a module statement */ + PM_CONTEXT_MODULE_ELSE, + + /** a rescue statement within a module statement */ + PM_CONTEXT_MODULE_RESCUE, + + /** a multiple target expression */ + PM_CONTEXT_MULTI_TARGET, + + /** a parenthesized expression */ + PM_CONTEXT_PARENS, + + /** an END block */ + PM_CONTEXT_POSTEXE, + + /** a predicate inside an if/elsif/unless statement */ + PM_CONTEXT_PREDICATE, + + /** a BEGIN block */ + PM_CONTEXT_PREEXE, + + /** a modifier rescue clause */ + PM_CONTEXT_RESCUE_MODIFIER, + + /** a singleton class definition */ + PM_CONTEXT_SCLASS, + + /** an ensure statement with a singleton class */ + PM_CONTEXT_SCLASS_ENSURE, + + /** a rescue else statement with a singleton class */ + PM_CONTEXT_SCLASS_ELSE, + + /** a rescue statement with a singleton class */ + PM_CONTEXT_SCLASS_RESCUE, + + /** a ternary expression */ + PM_CONTEXT_TERNARY, + + /** an unless statement */ + PM_CONTEXT_UNLESS, + + /** an until statement */ + PM_CONTEXT_UNTIL, + + /** a while statement */ + PM_CONTEXT_WHILE, +} pm_context_t; + +/** This is a node in a linked list of contexts. */ +typedef struct pm_context_node { + /** The context that this node represents. */ + pm_context_t context; + + /** A pointer to the previous context in the linked list. */ + struct pm_context_node *prev; +} pm_context_node_t; + +/** This is the type of a comment that we've found while parsing. */ +typedef enum { + PM_COMMENT_INLINE, + PM_COMMENT_EMBDOC +} pm_comment_type_t; + +/** + * This is a node in the linked list of comments that we've found while parsing. + * + * @extends pm_list_node_t + */ +typedef struct pm_comment { + /** The embedded base node. */ + pm_list_node_t node; + + /** The location of the comment in the source. */ + pm_location_t location; + + /** The type of comment that we've found. */ + pm_comment_type_t type; +} pm_comment_t; + +/** + * This is a node in the linked list of magic comments that we've found while + * parsing. + * + * @extends pm_list_node_t + */ +typedef struct { + /** The embedded base node. */ + pm_list_node_t node; + + /** A pointer to the start of the key in the source. */ + const uint8_t *key_start; + + /** A pointer to the start of the value in the source. */ + const uint8_t *value_start; + + /** The length of the key in the source. */ + uint32_t key_length; + + /** The length of the value in the source. */ + uint32_t value_length; +} pm_magic_comment_t; + +/** + * When the encoding that is being used to parse the source is changed by prism, + * we provide the ability here to call out to a user-defined function. + */ +typedef void (*pm_encoding_changed_callback_t)(pm_parser_t *parser); + +/** + * When you are lexing through a file, the lexer needs all of the information + * that the parser additionally provides (for example, the local table). So if + * you want to properly lex Ruby, you need to actually lex it in the context of + * the parser. In order to provide this functionality, we optionally allow a + * struct to be attached to the parser that calls back out to a user-provided + * callback when each token is lexed. + */ +typedef struct { + /** + * This opaque pointer is used to provide whatever information the user + * deemed necessary to the callback. In our case we use it to pass the array + * that the tokens get appended into. + */ + void *data; + + /** + * This is the callback that is called when a token is lexed. It is passed + * the opaque data pointer, the parser, and the token that was lexed. + */ + void (*callback)(void *data, pm_parser_t *parser, pm_token_t *token); +} pm_lex_callback_t; + +/** The type of shareable constant value that can be set. */ +typedef uint8_t pm_shareable_constant_value_t; +static const pm_shareable_constant_value_t PM_SCOPE_SHAREABLE_CONSTANT_NONE = 0x0; +static const pm_shareable_constant_value_t PM_SCOPE_SHAREABLE_CONSTANT_LITERAL = PM_SHAREABLE_CONSTANT_NODE_FLAGS_LITERAL; +static const pm_shareable_constant_value_t PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_EVERYTHING = PM_SHAREABLE_CONSTANT_NODE_FLAGS_EXPERIMENTAL_EVERYTHING; +static const pm_shareable_constant_value_t PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_COPY = PM_SHAREABLE_CONSTANT_NODE_FLAGS_EXPERIMENTAL_COPY; + +/** + * This tracks an individual local variable in a certain lexical context, as + * well as the number of times is it read. + */ +typedef struct { + /** The name of the local variable. */ + pm_constant_id_t name; + + /** The location of the local variable in the source. */ + pm_location_t location; + + /** The index of the local variable in the local table. */ + uint32_t index; + + /** The number of times the local variable is read. */ + uint32_t reads; + + /** The hash of the local variable. */ + uint32_t hash; +} pm_local_t; + +/** + * This is a set of local variables in a certain lexical context (method, class, + * module, etc.). We need to track how many times these variables are read in + * order to warn if they only get written. + */ +typedef struct pm_locals { + /** The number of local variables in the set. */ + uint32_t size; + + /** The capacity of the local variables set. */ + uint32_t capacity; + + /** The nullable allocated memory for the local variables in the set. */ + pm_local_t *locals; +} pm_locals_t; + +/** The flags about scope parameters that can be set. */ +typedef uint8_t pm_scope_parameters_t; +static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_NONE = 0x0; +static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_FORWARDING_POSITIONALS = 0x1; +static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_FORWARDING_KEYWORDS = 0x2; +static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_FORWARDING_BLOCK = 0x4; +static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_FORWARDING_ALL = 0x8; +static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED = 0x10; +static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_NUMBERED_INNER = 0x20; +static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_NUMBERED_FOUND = 0x40; + +/** + * This struct represents a node in a linked list of scopes. Some scopes can see + * into their parent scopes, while others cannot. + */ +typedef struct pm_scope { + /** A pointer to the previous scope in the linked list. */ + struct pm_scope *previous; + + /** The IDs of the locals in the given scope. */ + pm_locals_t locals; + + /** + * This is a list of the implicit parameters contained within the block. + * These will be processed after the block is parsed to determine the kind + * of parameters node that should be used and to check if any errors need to + * be added. + */ + pm_node_list_t implicit_parameters; + + /** + * This is a bitfield that indicates the parameters that are being used in + * this scope. It is a combination of the PM_SCOPE_PARAMETERS_* constants. + * There are three different kinds of parameters that can be used in a + * scope: + * + * - Ordinary parameters (e.g., def foo(bar); end) + * - Numbered parameters (e.g., def foo; _1; end) + * - The it parameter (e.g., def foo; it; end) + * + * If ordinary parameters are being used, then certain parameters can be + * forwarded to another method/structure. Those are indicated by four + * additional bits in the params field. For example, some combinations of: + * + * - def foo(*); end + * - def foo(**); end + * - def foo(&); end + * - def foo(...); end + */ + pm_scope_parameters_t parameters; + + /** + * The current state of constant shareability for this scope. This is + * changed by magic shareable_constant_value comments. + */ + pm_shareable_constant_value_t shareable_constant; + + /** + * A boolean indicating whether or not this scope can see into its parent. + * If closed is true, then the scope cannot see into its parent. + */ + bool closed; +} pm_scope_t; + +/** + * A struct that represents a stack of boolean values. + */ +typedef uint32_t pm_state_stack_t; + +/** + * This struct represents the overall parser. It contains a reference to the + * source file, as well as pointers that indicate where in the source it's + * currently parsing. It also contains the most recent and current token that + * it's considering. + */ +struct pm_parser { + /** + * The next node identifier that will be assigned. This is a unique + * identifier used to track nodes such that the syntax tree can be dropped + * but the node can be found through another parse. + */ + uint32_t node_id; + + /** The current state of the lexer. */ + pm_lex_state_t lex_state; + + /** Tracks the current nesting of (), [], and {}. */ + int enclosure_nesting; + + /** + * Used to temporarily track the nesting of enclosures to determine if a { + * is the beginning of a lambda following the parameters of a lambda. + */ + int lambda_enclosure_nesting; + + /** + * Used to track the nesting of braces to ensure we get the correct value + * when we are interpolating blocks with braces. + */ + int brace_nesting; + + /** + * The stack used to determine if a do keyword belongs to the predicate of a + * while, until, or for loop. + */ + pm_state_stack_t do_loop_stack; + + /** + * The stack used to determine if a do keyword belongs to the beginning of a + * block. + */ + pm_state_stack_t accepts_block_stack; + + /** A stack of lex modes. */ + struct { + /** The current mode of the lexer. */ + pm_lex_mode_t *current; + + /** The stack of lexer modes. */ + pm_lex_mode_t stack[PM_LEX_STACK_SIZE]; + + /** The current index into the lexer mode stack. */ + size_t index; + } lex_modes; + + /** The pointer to the start of the source. */ + const uint8_t *start; + + /** The pointer to the end of the source. */ + const uint8_t *end; + + /** The previous token we were considering. */ + pm_token_t previous; + + /** The current token we're considering. */ + pm_token_t current; + + /** + * This is a special field set on the parser when we need the parser to jump + * to a specific location when lexing the next token, as opposed to just + * using the end of the previous token. Normally this is NULL. + */ + const uint8_t *next_start; + + /** + * This field indicates the end of a heredoc whose identifier was found on + * the current line. If another heredoc is found on the same line, then this + * will be moved forward to the end of that heredoc. If no heredocs are + * found on a line then this is NULL. + */ + const uint8_t *heredoc_end; + + /** The list of comments that have been found while parsing. */ + pm_list_t comment_list; + + /** The list of magic comments that have been found while parsing. */ + pm_list_t magic_comment_list; + + /** + * An optional location that represents the location of the __END__ marker + * and the rest of the content of the file. This content is loaded into the + * DATA constant when the file being parsed is the main file being executed. + */ + pm_location_t data_loc; + + /** The list of warnings that have been found while parsing. */ + pm_list_t warning_list; + + /** The list of errors that have been found while parsing. */ + pm_list_t error_list; + + /** The current local scope. */ + pm_scope_t *current_scope; + + /** The current parsing context. */ + pm_context_node_t *current_context; + + /** + * The hash keys for the hash that is currently being parsed. This is not + * usually necessary because it can pass it down the various call chains, + * but in the event that you're parsing a hash that is being directly + * pushed into another hash with **, we need to share the hash keys so that + * we can warn for the nested hash as well. + */ + pm_static_literals_t *current_hash_keys; + + /** + * The encoding functions for the current file is attached to the parser as + * it's parsing so that it can change with a magic comment. + */ + const pm_encoding_t *encoding; + + /** + * When the encoding that is being used to parse the source is changed by + * prism, we provide the ability here to call out to a user-defined + * function. + */ + pm_encoding_changed_callback_t encoding_changed_callback; + + /** + * This pointer indicates where a comment must start if it is to be + * considered an encoding comment. + */ + const uint8_t *encoding_comment_start; + + /** + * This is an optional callback that can be attached to the parser that will + * be called whenever a new token is lexed by the parser. + */ + pm_lex_callback_t *lex_callback; + + /** + * This is the path of the file being parsed. We use the filepath when + * constructing SourceFileNodes. + */ + pm_string_t filepath; + + /** + * This constant pool keeps all of the constants defined throughout the file + * so that we can reference them later. + */ + pm_constant_pool_t constant_pool; + + /** This is the list of newline offsets in the source file. */ + pm_newline_list_t newline_list; + + /** + * We want to add a flag to integer nodes that indicates their base. We only + * want to parse these once, but we don't have space on the token itself to + * communicate this information. So we store it here and pass it through + * when we find tokens that we need it for. + */ + pm_node_flags_t integer_base; + + /** + * This string is used to pass information from the lexer to the parser. It + * is particularly necessary because of escape sequences. + */ + pm_string_t current_string; + + /** + * The line number at the start of the parse. This will be used to offset + * the line numbers of all of the locations. + */ + int32_t start_line; + + /** + * When a string-like expression is being lexed, any byte or escape sequence + * that resolves to a value whose top bit is set (i.e., >= 0x80) will + * explicitly set the encoding to the same encoding as the source. + * Alternatively, if a unicode escape sequence is used (e.g., \\u{80}) that + * resolves to a value whose top bit is set, then the encoding will be + * explicitly set to UTF-8. + * + * The _next_ time this happens, if the encoding that is about to become the + * explicitly set encoding does not match the previously set explicit + * encoding, a mixed encoding error will be emitted. + * + * When the expression is finished being lexed, the explicit encoding + * controls the encoding of the expression. For the most part this means + * that the expression will either be encoded in the source encoding or + * UTF-8. This holds for all encodings except US-ASCII. If the source is + * US-ASCII and an explicit encoding was set that was _not_ UTF-8, then the + * expression will be encoded as ASCII-8BIT. + * + * Note that if the expression is a list, different elements within the same + * list can have different encodings, so this will get reset between each + * element. Furthermore all of this only applies to lists that support + * interpolation, because otherwise escapes that could change the encoding + * are ignored. + * + * At first glance, it may make more sense for this to live on the lexer + * mode, but we need it here to communicate back to the parser for character + * literals that do not push a new lexer mode. + */ + const pm_encoding_t *explicit_encoding; + + /** + * When parsing block exits (e.g., break, next, redo), we need to validate + * that they are in correct contexts. For the most part we can do this by + * looking at our parent contexts. However, modifier while and until + * expressions can change that context to make block exits valid. In these + * cases, we need to keep track of the block exits and then validate them + * after the expression has been parsed. + * + * We use a pointer here because we don't want to keep a whole list attached + * since this will only be used in the context of begin/end expressions. + */ + pm_node_list_t *current_block_exits; + + /** The version of prism that we should use to parse. */ + pm_options_version_t version; + + /** The command line flags given from the options. */ + uint8_t command_line; + + /** + * Whether or not we have found a frozen_string_literal magic comment with + * a true or false value. + * May be: + * - PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED + * - PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED + * - PM_OPTIONS_FROZEN_STRING_LITERAL_UNSET + */ + int8_t frozen_string_literal; + + /** + * Whether or not we are parsing an eval string. This impacts whether or not + * we should evaluate if block exits/yields are valid. + */ + bool parsing_eval; + + /** + * Whether or not we are parsing a "partial" script, which is a script that + * will be evaluated in the context of another script, so we should not + * check jumps (next/break/etc.) for validity. + */ + bool partial_script; + + /** Whether or not we're at the beginning of a command. */ + bool command_start; + + /** Whether or not we're currently recovering from a syntax error. */ + bool recovering; + + /** + * This is very specialized behavior for when you want to parse in a context + * that does not respect encoding comments. Its main use case is translating + * into the whitequark/parser AST which re-encodes source files in UTF-8 + * before they are parsed and ignores encoding comments. + */ + bool encoding_locked; + + /** + * Whether or not the encoding has been changed by a magic comment. We use + * this to provide a fast path for the lexer instead of going through the + * function pointer. + */ + bool encoding_changed; + + /** + * This flag indicates that we are currently parsing a pattern matching + * expression and impacts that calculation of newlines. + */ + bool pattern_matching_newlines; + + /** This flag indicates that we are currently parsing a keyword argument. */ + bool in_keyword_arg; + + /** + * Whether or not the parser has seen a token that has semantic meaning + * (i.e., a token that is not a comment or whitespace). + */ + bool semantic_token_seen; + + /** + * True if the current regular expression being lexed contains only ASCII + * characters. + */ + bool current_regular_expression_ascii_only; + + /** + * By default, Ruby always warns about mismatched indentation. This can be + * toggled with a magic comment. + */ + bool warn_mismatched_indentation; +}; + +#endif diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/prettyprint.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/prettyprint.h new file mode 100644 index 0000000..5a52b2b --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/prettyprint.h @@ -0,0 +1,34 @@ +/** + * @file prettyprint.h + * + * An AST node pretty-printer. + */ +#ifndef PRISM_PRETTYPRINT_H +#define PRISM_PRETTYPRINT_H + +#include "prism/defines.h" + +#ifdef PRISM_EXCLUDE_PRETTYPRINT + +void pm_prettyprint(void); + +#else + +#include + +#include "prism/ast.h" +#include "prism/parser.h" +#include "prism/util/pm_buffer.h" + +/** + * Pretty-prints the AST represented by the given node to the given buffer. + * + * @param output_buffer The buffer to write the pretty-printed AST to. + * @param parser The parser that parsed the AST. + * @param node The root node of the AST to pretty-print. + */ +PRISM_EXPORTED_FUNCTION void pm_prettyprint(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm_node_t *node); + +#endif + +#endif diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/prism.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/prism.h new file mode 100644 index 0000000..dc31f26 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/prism.h @@ -0,0 +1,408 @@ +/** + * @file prism.h + * + * The main header file for the prism parser. + */ +#ifndef PRISM_H +#define PRISM_H + +#include "prism/defines.h" +#include "prism/util/pm_buffer.h" +#include "prism/util/pm_char.h" +#include "prism/util/pm_integer.h" +#include "prism/util/pm_memchr.h" +#include "prism/util/pm_strncasecmp.h" +#include "prism/util/pm_strpbrk.h" +#include "prism/ast.h" +#include "prism/diagnostic.h" +#include "prism/node.h" +#include "prism/options.h" +#include "prism/pack.h" +#include "prism/parser.h" +#include "prism/prettyprint.h" +#include "prism/regexp.h" +#include "prism/static_literals.h" +#include "prism/version.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef _WIN32 +#include +#endif + +/** + * The prism version and the serialization format. + * + * @returns The prism version as a constant string. + */ +PRISM_EXPORTED_FUNCTION const char * pm_version(void); + +/** + * Initialize a parser with the given start and end pointers. + * + * The resulting parser must eventually be freed with `pm_parser_free()`. + * + * @param parser The parser to initialize. + * @param source The source to parse. + * @param size The size of the source. + * @param options The optional options to use when parsing. These options must + * live for the whole lifetime of this parser. + * + * \public \memberof pm_parser + */ +PRISM_EXPORTED_FUNCTION void pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm_options_t *options); + +/** + * Register a callback that will be called whenever prism changes the encoding + * it is using to parse based on the magic comment. + * + * @param parser The parser to register the callback with. + * @param callback The callback to register. + * + * \public \memberof pm_parser + */ +PRISM_EXPORTED_FUNCTION void pm_parser_register_encoding_changed_callback(pm_parser_t *parser, pm_encoding_changed_callback_t callback); + +/** + * Free any memory associated with the given parser. + * + * This does not free the `pm_options_t` object that was used to initialize the + * parser. + * + * @param parser The parser to free. + * + * \public \memberof pm_parser + */ +PRISM_EXPORTED_FUNCTION void pm_parser_free(pm_parser_t *parser); + +/** + * Initiate the parser with the given parser. + * + * @param parser The parser to use. + * @return The AST representing the source. + * + * \public \memberof pm_parser + */ +PRISM_EXPORTED_FUNCTION pm_node_t * pm_parse(pm_parser_t *parser); + +/** + * This function is used in pm_parse_stream() to retrieve a line of input from a + * stream. It closely mirrors that of fgets so that fgets can be used as the + * default implementation. + */ +typedef char * (pm_parse_stream_fgets_t)(char *string, int size, void *stream); + +/** + * This function is used in pm_parse_stream to check whether a stream is EOF. + * It closely mirrors that of feof so that feof can be used as the + * default implementation. + */ +typedef int (pm_parse_stream_feof_t)(void *stream); + +/** + * Parse a stream of Ruby source and return the tree. + * + * @param parser The parser to use. + * @param buffer The buffer to use. + * @param stream The stream to parse. + * @param stream_fgets The function to use to read from the stream. + * @param stream_feof The function to use to determine if the stream has hit eof. + * @param options The optional options to use when parsing. + * @return The AST representing the source. + * + * \public \memberof pm_parser + */ +PRISM_EXPORTED_FUNCTION pm_node_t * pm_parse_stream(pm_parser_t *parser, pm_buffer_t *buffer, void *stream, pm_parse_stream_fgets_t *stream_fgets, pm_parse_stream_feof_t *stream_feof, const pm_options_t *options); + +// We optionally support serializing to a binary string. For systems that don't +// want or need this functionality, it can be turned off with the +// PRISM_EXCLUDE_SERIALIZATION define. +#ifndef PRISM_EXCLUDE_SERIALIZATION + +/** + * Parse and serialize the AST represented by the source that is read out of the + * given stream into to the given buffer. + * + * @param buffer The buffer to serialize to. + * @param stream The stream to parse. + * @param stream_fgets The function to use to read from the stream. + * @param stream_feof The function to use to tell if the stream has hit eof. + * @param data The optional data to pass to the parser. + */ +PRISM_EXPORTED_FUNCTION void pm_serialize_parse_stream(pm_buffer_t *buffer, void *stream, pm_parse_stream_fgets_t *stream_fgets, pm_parse_stream_feof_t *stream_feof, const char *data); + +/** + * Serialize the given list of comments to the given buffer. + * + * @param parser The parser to serialize. + * @param list The list of comments to serialize. + * @param buffer The buffer to serialize to. + */ +void pm_serialize_comment_list(pm_parser_t *parser, pm_list_t *list, pm_buffer_t *buffer); + +/** + * Serialize the name of the encoding to the buffer. + * + * @param encoding The encoding to serialize. + * @param buffer The buffer to serialize to. + */ +void pm_serialize_encoding(const pm_encoding_t *encoding, pm_buffer_t *buffer); + +/** + * Serialize the encoding, metadata, nodes, and constant pool. + * + * @param parser The parser to serialize. + * @param node The node to serialize. + * @param buffer The buffer to serialize to. + */ +void pm_serialize_content(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer); + +/** + * Serialize the AST represented by the given node to the given buffer. + * + * @param parser The parser to serialize. + * @param node The node to serialize. + * @param buffer The buffer to serialize to. + */ +PRISM_EXPORTED_FUNCTION void pm_serialize(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer); + +/** + * Parse the given source to the AST and dump the AST to the given buffer. + * + * @param buffer The buffer to serialize to. + * @param source The source to parse. + * @param size The size of the source. + * @param data The optional data to pass to the parser. + */ +PRISM_EXPORTED_FUNCTION void pm_serialize_parse(pm_buffer_t *buffer, const uint8_t *source, size_t size, const char *data); + +/** + * Parse and serialize the comments in the given source to the given buffer. + * + * @param buffer The buffer to serialize to. + * @param source The source to parse. + * @param size The size of the source. + * @param data The optional data to pass to the parser. + */ +PRISM_EXPORTED_FUNCTION void pm_serialize_parse_comments(pm_buffer_t *buffer, const uint8_t *source, size_t size, const char *data); + +/** + * Lex the given source and serialize to the given buffer. + * + * @param source The source to lex. + * @param size The size of the source. + * @param buffer The buffer to serialize to. + * @param data The optional data to pass to the lexer. + */ +PRISM_EXPORTED_FUNCTION void pm_serialize_lex(pm_buffer_t *buffer, const uint8_t *source, size_t size, const char *data); + +/** + * Parse and serialize both the AST and the tokens represented by the given + * source to the given buffer. + * + * @param buffer The buffer to serialize to. + * @param source The source to parse. + * @param size The size of the source. + * @param data The optional data to pass to the parser. + */ +PRISM_EXPORTED_FUNCTION void pm_serialize_parse_lex(pm_buffer_t *buffer, const uint8_t *source, size_t size, const char *data); + +#endif + +/** + * Parse the source and return true if it parses without errors or warnings. + * + * @param source The source to parse. + * @param size The size of the source. + * @param data The optional data to pass to the parser. + * @return True if the source parses without errors or warnings. + */ +PRISM_EXPORTED_FUNCTION bool pm_parse_success_p(const uint8_t *source, size_t size, const char *data); + +/** + * Returns a string representation of the given token type. + * + * @param token_type The token type to convert to a string. + * @return A string representation of the given token type. + */ +PRISM_EXPORTED_FUNCTION const char * pm_token_type_name(pm_token_type_t token_type); + +/** + * Returns the human name of the given token type. + * + * @param token_type The token type to convert to a human name. + * @return The human name of the given token type. + */ +const char * pm_token_type_human(pm_token_type_t token_type); + +// We optionally support dumping to JSON. For systems that don't want or need +// this functionality, it can be turned off with the PRISM_EXCLUDE_JSON define. +#ifndef PRISM_EXCLUDE_JSON + +/** + * Dump JSON to the given buffer. + * + * @param buffer The buffer to serialize to. + * @param parser The parser that parsed the node. + * @param node The node to serialize. + */ +PRISM_EXPORTED_FUNCTION void pm_dump_json(pm_buffer_t *buffer, const pm_parser_t *parser, const pm_node_t *node); + +#endif + +/** + * Represents the results of a slice query. + */ +typedef enum { + /** Returned if the encoding given to a slice query was invalid. */ + PM_STRING_QUERY_ERROR = -1, + + /** Returned if the result of the slice query is false. */ + PM_STRING_QUERY_FALSE, + + /** Returned if the result of the slice query is true. */ + PM_STRING_QUERY_TRUE +} pm_string_query_t; + +/** + * Check that the slice is a valid local variable name. + * + * @param source The source to check. + * @param length The length of the source. + * @param encoding_name The name of the encoding of the source. + * @return PM_STRING_QUERY_TRUE if the query is true, PM_STRING_QUERY_FALSE if + * the query is false, and PM_STRING_QUERY_ERROR if the encoding was invalid. + */ +PRISM_EXPORTED_FUNCTION pm_string_query_t pm_string_query_local(const uint8_t *source, size_t length, const char *encoding_name); + +/** + * Check that the slice is a valid constant name. + * + * @param source The source to check. + * @param length The length of the source. + * @param encoding_name The name of the encoding of the source. + * @return PM_STRING_QUERY_TRUE if the query is true, PM_STRING_QUERY_FALSE if + * the query is false, and PM_STRING_QUERY_ERROR if the encoding was invalid. + */ +PRISM_EXPORTED_FUNCTION pm_string_query_t pm_string_query_constant(const uint8_t *source, size_t length, const char *encoding_name); + +/** + * Check that the slice is a valid method name. + * + * @param source The source to check. + * @param length The length of the source. + * @param encoding_name The name of the encoding of the source. + * @return PM_STRING_QUERY_TRUE if the query is true, PM_STRING_QUERY_FALSE if + * the query is false, and PM_STRING_QUERY_ERROR if the encoding was invalid. + */ +PRISM_EXPORTED_FUNCTION pm_string_query_t pm_string_query_method_name(const uint8_t *source, size_t length, const char *encoding_name); + +/** + * @mainpage + * + * Prism is a parser for the Ruby programming language. It is designed to be + * portable, error tolerant, and maintainable. It is written in C99 and has no + * dependencies. It is currently being integrated into + * [CRuby](https://github.com/ruby/ruby), + * [JRuby](https://github.com/jruby/jruby), + * [TruffleRuby](https://github.com/oracle/truffleruby), + * [Sorbet](https://github.com/sorbet/sorbet), and + * [Syntax Tree](https://github.com/ruby-syntax-tree/syntax_tree). + * + * @section getting-started Getting started + * + * If you're vendoring this project and compiling it statically then as long as + * you have a C99 compiler you will be fine. If you're linking against it as + * shared library, then you should compile with `-fvisibility=hidden` and + * `-DPRISM_EXPORT_SYMBOLS` to tell prism to make only its public interface + * visible. + * + * @section parsing Parsing + * + * In order to parse Ruby code, the structures and functions that you're going + * to want to use and be aware of are: + * + * * `pm_parser_t` - the main parser structure + * * `pm_parser_init()` - initialize a parser + * * `pm_parse()` - parse and return the root node + * * `pm_node_destroy()` - deallocate the root node returned by `pm_parse()` + * * `pm_parser_free()` - free the internal memory of the parser + * + * Putting all of this together would look something like: + * + * ```c + * void parse(const uint8_t *source, size_t length) { + * pm_parser_t parser; + * pm_parser_init(&parser, source, length, NULL); + * + * pm_node_t *root = pm_parse(&parser); + * printf("PARSED!\n"); + * + * pm_node_destroy(&parser, root); + * pm_parser_free(&parser); + * } + * ``` + * + * All of the nodes "inherit" from `pm_node_t` by embedding those structures + * as their first member. This means you can downcast and upcast any node in the + * tree to a `pm_node_t`. + * + * @section serializing Serializing + * + * Prism provides the ability to serialize the AST and its related metadata into + * a binary format. This format is designed to be portable to different + * languages and runtimes so that you only need to make one FFI call in order to + * parse Ruby code. The structures and functions that you're going to want to + * use and be aware of are: + * + * * `pm_buffer_t` - a small buffer object that will hold the serialized AST + * * `pm_buffer_free()` - free the memory associated with the buffer + * * `pm_serialize()` - serialize the AST into a buffer + * * `pm_serialize_parse()` - parse and serialize the AST into a buffer + * + * Putting all of this together would look something like: + * + * ```c + * void serialize(const uint8_t *source, size_t length) { + * pm_buffer_t buffer = { 0 }; + * + * pm_serialize_parse(&buffer, source, length, NULL); + * printf("SERIALIZED!\n"); + * + * pm_buffer_free(&buffer); + * } + * ``` + * + * @section inspecting Inspecting + * + * Prism provides the ability to inspect the AST by pretty-printing nodes. You + * can do this with the `pm_prettyprint()` function, which you would use like: + * + * ```c + * void prettyprint(const uint8_t *source, size_t length) { + * pm_parser_t parser; + * pm_parser_init(&parser, source, length, NULL); + * + * pm_node_t *root = pm_parse(&parser); + * pm_buffer_t buffer = { 0 }; + * + * pm_prettyprint(&buffer, &parser, root); + * printf("%*.s\n", (int) buffer.length, buffer.value); + * + * pm_buffer_free(&buffer); + * pm_node_destroy(&parser, root); + * pm_parser_free(&parser); + * } + * ``` + */ + +#endif diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/regexp.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/regexp.h new file mode 100644 index 0000000..5366b5a --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/regexp.h @@ -0,0 +1,43 @@ +/** + * @file regexp.h + * + * A regular expression parser. + */ +#ifndef PRISM_REGEXP_H +#define PRISM_REGEXP_H + +#include "prism/defines.h" +#include "prism/parser.h" +#include "prism/encoding.h" +#include "prism/util/pm_memchr.h" +#include "prism/util/pm_string.h" + +#include +#include +#include + +/** + * This callback is called by pm_regexp_parse() when a named capture group is found. + */ +typedef void (*pm_regexp_name_callback_t)(const pm_string_t *name, void *data); + +/** + * This callback is called by pm_regexp_parse() when a parse error is found. + */ +typedef void (*pm_regexp_error_callback_t)(const uint8_t *start, const uint8_t *end, const char *message, void *data); + +/** + * Parse a regular expression. + * + * @param parser The parser that is currently being used. + * @param source The source code to parse. + * @param size The size of the source code. + * @param extended_mode Whether to parse the regular expression in extended mode. + * @param name_callback The optional callback to call when a named capture group is found. + * @param name_data The optional data to pass to the name callback. + * @param error_callback The callback to call when a parse error is found. + * @param error_data The data to pass to the error callback. + */ +PRISM_EXPORTED_FUNCTION void pm_regexp_parse(pm_parser_t *parser, const uint8_t *source, size_t size, bool extended_mode, pm_regexp_name_callback_t name_callback, void *name_data, pm_regexp_error_callback_t error_callback, void *error_data); + +#endif diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/static_literals.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/static_literals.h new file mode 100644 index 0000000..bd29761 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/static_literals.h @@ -0,0 +1,121 @@ +/** + * @file static_literals.h + * + * A set of static literal nodes that can be checked for duplicates. + */ +#ifndef PRISM_STATIC_LITERALS_H +#define PRISM_STATIC_LITERALS_H + +#include "prism/defines.h" +#include "prism/ast.h" +#include "prism/util/pm_newline_list.h" + +#include +#include + +/** + * An internal hash table for a set of nodes. + */ +typedef struct { + /** The array of nodes in the hash table. */ + pm_node_t **nodes; + + /** The size of the hash table. */ + uint32_t size; + + /** The space that has been allocated in the hash table. */ + uint32_t capacity; +} pm_node_hash_t; + +/** + * Certain sets of nodes (hash keys and when clauses) check for duplicate nodes + * to alert the user of potential issues. To do this, we keep a set of the nodes + * that have been seen so far, and compare whenever we find a new node. + * + * We bucket the nodes based on their type to minimize the number of comparisons + * that need to be performed. + */ +typedef struct { + /** + * This is the set of IntegerNode and SourceLineNode instances. + */ + pm_node_hash_t integer_nodes; + + /** + * This is the set of FloatNode instances. + */ + pm_node_hash_t float_nodes; + + /** + * This is the set of RationalNode and ImaginaryNode instances. + */ + pm_node_hash_t number_nodes; + + /** + * This is the set of StringNode and SourceFileNode instances. + */ + pm_node_hash_t string_nodes; + + /** + * This is the set of RegularExpressionNode instances. + */ + pm_node_hash_t regexp_nodes; + + /** + * This is the set of SymbolNode instances. + */ + pm_node_hash_t symbol_nodes; + + /** + * A pointer to the last TrueNode instance that was inserted, or NULL. + */ + pm_node_t *true_node; + + /** + * A pointer to the last FalseNode instance that was inserted, or NULL. + */ + pm_node_t *false_node; + + /** + * A pointer to the last NilNode instance that was inserted, or NULL. + */ + pm_node_t *nil_node; + + /** + * A pointer to the last SourceEncodingNode instance that was inserted, or + * NULL. + */ + pm_node_t *source_encoding_node; +} pm_static_literals_t; + +/** + * Add a node to the set of static literals. + * + * @param newline_list The list of newline offsets to use to calculate lines. + * @param start_line The line number that the parser starts on. + * @param literals The set of static literals to add the node to. + * @param node The node to add to the set. + * @param replace Whether to replace the previous node if one already exists. + * @return A pointer to the node that is being overwritten, if there is one. + */ +pm_node_t * pm_static_literals_add(const pm_newline_list_t *newline_list, int32_t start_line, pm_static_literals_t *literals, pm_node_t *node, bool replace); + +/** + * Free the internal memory associated with the given static literals set. + * + * @param literals The set of static literals to free. + */ +void pm_static_literals_free(pm_static_literals_t *literals); + +/** + * Create a string-based representation of the given static literal. + * + * @param buffer The buffer to write the string to. + * @param newline_list The list of newline offsets to use to calculate lines. + * @param start_line The line number that the parser starts on. + * @param encoding_name The name of the encoding of the source being parsed. + * @param node The node to create a string representation of. + */ +void pm_static_literal_inspect(pm_buffer_t *buffer, const pm_newline_list_t *newline_list, int32_t start_line, const char *encoding_name, const pm_node_t *node); + +#endif diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/util/pm_buffer.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/util/pm_buffer.h new file mode 100644 index 0000000..cb80f8b --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/util/pm_buffer.h @@ -0,0 +1,236 @@ +/** + * @file pm_buffer.h + * + * A wrapper around a contiguous block of allocated memory. + */ +#ifndef PRISM_BUFFER_H +#define PRISM_BUFFER_H + +#include "prism/defines.h" +#include "prism/util/pm_char.h" + +#include +#include +#include +#include +#include + +/** + * A pm_buffer_t is a simple memory buffer that stores data in a contiguous + * block of memory. + */ +typedef struct { + /** The length of the buffer in bytes. */ + size_t length; + + /** The capacity of the buffer in bytes that has been allocated. */ + size_t capacity; + + /** A pointer to the start of the buffer. */ + char *value; +} pm_buffer_t; + +/** + * Return the size of the pm_buffer_t struct. + * + * @returns The size of the pm_buffer_t struct. + */ +PRISM_EXPORTED_FUNCTION size_t pm_buffer_sizeof(void); + +/** + * Initialize a pm_buffer_t with the given capacity. + * + * @param buffer The buffer to initialize. + * @param capacity The capacity of the buffer. + * @returns True if the buffer was initialized successfully, false otherwise. + */ +bool pm_buffer_init_capacity(pm_buffer_t *buffer, size_t capacity); + +/** + * Initialize a pm_buffer_t with its default values. + * + * @param buffer The buffer to initialize. + * @returns True if the buffer was initialized successfully, false otherwise. + * + * \public \memberof pm_buffer_t + */ +PRISM_EXPORTED_FUNCTION bool pm_buffer_init(pm_buffer_t *buffer); + +/** + * Return the value of the buffer. + * + * @param buffer The buffer to get the value of. + * @returns The value of the buffer. + * + * \public \memberof pm_buffer_t + */ +PRISM_EXPORTED_FUNCTION char * pm_buffer_value(const pm_buffer_t *buffer); + +/** + * Return the length of the buffer. + * + * @param buffer The buffer to get the length of. + * @returns The length of the buffer. + * + * \public \memberof pm_buffer_t + */ +PRISM_EXPORTED_FUNCTION size_t pm_buffer_length(const pm_buffer_t *buffer); + +/** + * Append the given amount of space as zeroes to the buffer. + * + * @param buffer The buffer to append to. + * @param length The amount of space to append and zero. + */ +void pm_buffer_append_zeroes(pm_buffer_t *buffer, size_t length); + +/** + * Append a formatted string to the buffer. + * + * @param buffer The buffer to append to. + * @param format The format string to append. + * @param ... The arguments to the format string. + */ +void pm_buffer_append_format(pm_buffer_t *buffer, const char *format, ...) PRISM_ATTRIBUTE_FORMAT(2, 3); + +/** + * Append a string to the buffer. + * + * @param buffer The buffer to append to. + * @param value The string to append. + * @param length The length of the string to append. + */ +void pm_buffer_append_string(pm_buffer_t *buffer, const char *value, size_t length); + +/** + * Append a list of bytes to the buffer. + * + * @param buffer The buffer to append to. + * @param value The bytes to append. + * @param length The length of the bytes to append. + */ +void pm_buffer_append_bytes(pm_buffer_t *buffer, const uint8_t *value, size_t length); + +/** + * Append a single byte to the buffer. + * + * @param buffer The buffer to append to. + * @param value The byte to append. + */ +void pm_buffer_append_byte(pm_buffer_t *buffer, uint8_t value); + +/** + * Append a 32-bit unsigned integer to the buffer as a variable-length integer. + * + * @param buffer The buffer to append to. + * @param value The integer to append. + */ +void pm_buffer_append_varuint(pm_buffer_t *buffer, uint32_t value); + +/** + * Append a 32-bit signed integer to the buffer as a variable-length integer. + * + * @param buffer The buffer to append to. + * @param value The integer to append. + */ +void pm_buffer_append_varsint(pm_buffer_t *buffer, int32_t value); + +/** + * Append a double to the buffer. + * + * @param buffer The buffer to append to. + * @param value The double to append. + */ +void pm_buffer_append_double(pm_buffer_t *buffer, double value); + +/** + * Append a unicode codepoint to the buffer. + * + * @param buffer The buffer to append to. + * @param value The character to append. + * @returns True if the codepoint was valid and appended successfully, false + * otherwise. + */ +bool pm_buffer_append_unicode_codepoint(pm_buffer_t *buffer, uint32_t value); + +/** + * The different types of escaping that can be performed by the buffer when + * appending a slice of Ruby source code. + */ +typedef enum { + PM_BUFFER_ESCAPING_RUBY, + PM_BUFFER_ESCAPING_JSON +} pm_buffer_escaping_t; + +/** + * Append a slice of source code to the buffer. + * + * @param buffer The buffer to append to. + * @param source The source code to append. + * @param length The length of the source code to append. + * @param escaping The type of escaping to perform. + */ +void pm_buffer_append_source(pm_buffer_t *buffer, const uint8_t *source, size_t length, pm_buffer_escaping_t escaping); + +/** + * Prepend the given string to the buffer. + * + * @param buffer The buffer to prepend to. + * @param value The string to prepend. + * @param length The length of the string to prepend. + */ +void pm_buffer_prepend_string(pm_buffer_t *buffer, const char *value, size_t length); + +/** + * Concatenate one buffer onto another. + * + * @param destination The buffer to concatenate onto. + * @param source The buffer to concatenate. + */ +void pm_buffer_concat(pm_buffer_t *destination, const pm_buffer_t *source); + +/** + * Clear the buffer by reducing its size to 0. This does not free the allocated + * memory, but it does allow the buffer to be reused. + * + * @param buffer The buffer to clear. + */ +void pm_buffer_clear(pm_buffer_t *buffer); + +/** + * Strip the whitespace from the end of the buffer. + * + * @param buffer The buffer to strip. + */ +void pm_buffer_rstrip(pm_buffer_t *buffer); + +/** + * Checks if the buffer includes the given value. + * + * @param buffer The buffer to check. + * @param value The value to check for. + * @returns The index of the first occurrence of the value in the buffer, or + * SIZE_MAX if the value is not found. + */ +size_t pm_buffer_index(const pm_buffer_t *buffer, char value); + +/** + * Insert the given string into the buffer at the given index. + * + * @param buffer The buffer to insert into. + * @param index The index to insert at. + * @param value The string to insert. + * @param length The length of the string to insert. + */ +void pm_buffer_insert(pm_buffer_t *buffer, size_t index, const char *value, size_t length); + +/** + * Free the memory associated with the buffer. + * + * @param buffer The buffer to free. + * + * \public \memberof pm_buffer_t + */ +PRISM_EXPORTED_FUNCTION void pm_buffer_free(pm_buffer_t *buffer); + +#endif diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/util/pm_char.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/util/pm_char.h new file mode 100644 index 0000000..deeafd6 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/util/pm_char.h @@ -0,0 +1,204 @@ +/** + * @file pm_char.h + * + * Functions for working with characters and strings. + */ +#ifndef PRISM_CHAR_H +#define PRISM_CHAR_H + +#include "prism/defines.h" +#include "prism/util/pm_newline_list.h" + +#include +#include + +/** + * Returns the number of characters at the start of the string that are + * whitespace. Disallows searching past the given maximum number of characters. + * + * @param string The string to search. + * @param length The maximum number of characters to search. + * @return The number of characters at the start of the string that are + * whitespace. + */ +size_t pm_strspn_whitespace(const uint8_t *string, ptrdiff_t length); + +/** + * Returns the number of characters at the start of the string that are + * whitespace while also tracking the location of each newline. Disallows + * searching past the given maximum number of characters. + * + * @param string The string to search. + * @param length The maximum number of characters to search. + * @param newline_list The list of newlines to populate. + * @return The number of characters at the start of the string that are + * whitespace. + */ +size_t pm_strspn_whitespace_newlines(const uint8_t *string, ptrdiff_t length, pm_newline_list_t *newline_list); + +/** + * Returns the number of characters at the start of the string that are inline + * whitespace. Disallows searching past the given maximum number of characters. + * + * @param string The string to search. + * @param length The maximum number of characters to search. + * @return The number of characters at the start of the string that are inline + * whitespace. + */ +size_t pm_strspn_inline_whitespace(const uint8_t *string, ptrdiff_t length); + +/** + * Returns the number of characters at the start of the string that are decimal + * digits. Disallows searching past the given maximum number of characters. + * + * @param string The string to search. + * @param length The maximum number of characters to search. + * @return The number of characters at the start of the string that are decimal + * digits. + */ +size_t pm_strspn_decimal_digit(const uint8_t *string, ptrdiff_t length); + +/** + * Returns the number of characters at the start of the string that are + * hexadecimal digits. Disallows searching past the given maximum number of + * characters. + * + * @param string The string to search. + * @param length The maximum number of characters to search. + * @return The number of characters at the start of the string that are + * hexadecimal digits. + */ +size_t pm_strspn_hexadecimal_digit(const uint8_t *string, ptrdiff_t length); + +/** + * Returns the number of characters at the start of the string that are octal + * digits or underscores. Disallows searching past the given maximum number of + * characters. + * + * If multiple underscores are found in a row or if an underscore is + * found at the end of the number, then the invalid pointer is set to the index + * of the first invalid underscore. + * + * @param string The string to search. + * @param length The maximum number of characters to search. + * @param invalid The pointer to set to the index of the first invalid + * underscore. + * @return The number of characters at the start of the string that are octal + * digits or underscores. + */ +size_t pm_strspn_octal_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid); + +/** + * Returns the number of characters at the start of the string that are decimal + * digits or underscores. Disallows searching past the given maximum number of + * characters. + * + * If multiple underscores are found in a row or if an underscore is + * found at the end of the number, then the invalid pointer is set to the index + * of the first invalid underscore. + * + * @param string The string to search. + * @param length The maximum number of characters to search. + * @param invalid The pointer to set to the index of the first invalid + * underscore. + * @return The number of characters at the start of the string that are decimal + * digits or underscores. + */ +size_t pm_strspn_decimal_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid); + +/** + * Returns the number of characters at the start of the string that are + * hexadecimal digits or underscores. Disallows searching past the given maximum + * number of characters. + * + * If multiple underscores are found in a row or if an underscore is + * found at the end of the number, then the invalid pointer is set to the index + * of the first invalid underscore. + * + * @param string The string to search. + * @param length The maximum number of characters to search. + * @param invalid The pointer to set to the index of the first invalid + * underscore. + * @return The number of characters at the start of the string that are + * hexadecimal digits or underscores. + */ +size_t pm_strspn_hexadecimal_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid); + +/** + * Returns the number of characters at the start of the string that are regexp + * options. Disallows searching past the given maximum number of characters. + * + * @param string The string to search. + * @param length The maximum number of characters to search. + * @return The number of characters at the start of the string that are regexp + * options. + */ +size_t pm_strspn_regexp_option(const uint8_t *string, ptrdiff_t length); + +/** + * Returns the number of characters at the start of the string that are binary + * digits or underscores. Disallows searching past the given maximum number of + * characters. + * + * If multiple underscores are found in a row or if an underscore is + * found at the end of the number, then the invalid pointer is set to the index + * of the first invalid underscore. + * + * @param string The string to search. + * @param length The maximum number of characters to search. + * @param invalid The pointer to set to the index of the first invalid + * underscore. + * @return The number of characters at the start of the string that are binary + * digits or underscores. + */ +size_t pm_strspn_binary_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid); + +/** + * Returns true if the given character is a whitespace character. + * + * @param b The character to check. + * @return True if the given character is a whitespace character. + */ +bool pm_char_is_whitespace(const uint8_t b); + +/** + * Returns true if the given character is an inline whitespace character. + * + * @param b The character to check. + * @return True if the given character is an inline whitespace character. + */ +bool pm_char_is_inline_whitespace(const uint8_t b); + +/** + * Returns true if the given character is a binary digit. + * + * @param b The character to check. + * @return True if the given character is a binary digit. + */ +bool pm_char_is_binary_digit(const uint8_t b); + +/** + * Returns true if the given character is an octal digit. + * + * @param b The character to check. + * @return True if the given character is an octal digit. + */ +bool pm_char_is_octal_digit(const uint8_t b); + +/** + * Returns true if the given character is a decimal digit. + * + * @param b The character to check. + * @return True if the given character is a decimal digit. + */ +bool pm_char_is_decimal_digit(const uint8_t b); + +/** + * Returns true if the given character is a hexadecimal digit. + * + * @param b The character to check. + * @return True if the given character is a hexadecimal digit. + */ +bool pm_char_is_hexadecimal_digit(const uint8_t b); + +#endif diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/util/pm_constant_pool.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/util/pm_constant_pool.h new file mode 100644 index 0000000..6df23f8 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/util/pm_constant_pool.h @@ -0,0 +1,218 @@ +/** + * @file pm_constant_pool.h + * + * A data structure that stores a set of strings. + * + * Each string is assigned a unique id, which can be used to compare strings for + * equality. This comparison ends up being much faster than strcmp, since it + * only requires a single integer comparison. + */ +#ifndef PRISM_CONSTANT_POOL_H +#define PRISM_CONSTANT_POOL_H + +#include "prism/defines.h" + +#include +#include +#include +#include +#include + +/** + * When we allocate constants into the pool, we reserve 0 to mean that the slot + * is not yet filled. This constant is reused in other places to indicate the + * lack of a constant id. + */ +#define PM_CONSTANT_ID_UNSET 0 + +/** + * A constant id is a unique identifier for a constant in the constant pool. + */ +typedef uint32_t pm_constant_id_t; + +/** + * A list of constant IDs. Usually used to represent a set of locals. + */ +typedef struct { + /** The number of constant ids in the list. */ + size_t size; + + /** The number of constant ids that have been allocated in the list. */ + size_t capacity; + + /** The constant ids in the list. */ + pm_constant_id_t *ids; +} pm_constant_id_list_t; + +/** + * Initialize a list of constant ids. + * + * @param list The list to initialize. + */ +void pm_constant_id_list_init(pm_constant_id_list_t *list); + +/** + * Initialize a list of constant ids with a given capacity. + * + * @param list The list to initialize. + * @param capacity The initial capacity of the list. + */ +void pm_constant_id_list_init_capacity(pm_constant_id_list_t *list, size_t capacity); + +/** + * Append a constant id to a list of constant ids. Returns false if any + * potential reallocations fail. + * + * @param list The list to append to. + * @param id The id to append. + * @return Whether the append succeeded. + */ +bool pm_constant_id_list_append(pm_constant_id_list_t *list, pm_constant_id_t id); + +/** + * Insert a constant id into a list of constant ids at the specified index. + * + * @param list The list to insert into. + * @param index The index at which to insert. + * @param id The id to insert. + */ +void pm_constant_id_list_insert(pm_constant_id_list_t *list, size_t index, pm_constant_id_t id); + +/** + * Checks if the current constant id list includes the given constant id. + * + * @param list The list to check. + * @param id The id to check for. + * @return Whether the list includes the given id. + */ +bool pm_constant_id_list_includes(pm_constant_id_list_t *list, pm_constant_id_t id); + +/** + * Free the memory associated with a list of constant ids. + * + * @param list The list to free. + */ +void pm_constant_id_list_free(pm_constant_id_list_t *list); + +/** + * The type of bucket in the constant pool hash map. This determines how the + * bucket should be freed. + */ +typedef unsigned int pm_constant_pool_bucket_type_t; + +/** By default, each constant is a slice of the source. */ +static const pm_constant_pool_bucket_type_t PM_CONSTANT_POOL_BUCKET_DEFAULT = 0; + +/** An owned constant is one for which memory has been allocated. */ +static const pm_constant_pool_bucket_type_t PM_CONSTANT_POOL_BUCKET_OWNED = 1; + +/** A constant constant is known at compile time. */ +static const pm_constant_pool_bucket_type_t PM_CONSTANT_POOL_BUCKET_CONSTANT = 2; + +/** A bucket in the hash map. */ +typedef struct { + /** The incremental ID used for indexing back into the pool. */ + unsigned int id: 30; + + /** The type of the bucket, which determines how to free it. */ + pm_constant_pool_bucket_type_t type: 2; + + /** The hash of the bucket. */ + uint32_t hash; +} pm_constant_pool_bucket_t; + +/** A constant in the pool which effectively stores a string. */ +typedef struct { + /** A pointer to the start of the string. */ + const uint8_t *start; + + /** The length of the string. */ + size_t length; +} pm_constant_t; + +/** The overall constant pool, which stores constants found while parsing. */ +typedef struct { + /** The buckets in the hash map. */ + pm_constant_pool_bucket_t *buckets; + + /** The constants that are stored in the buckets. */ + pm_constant_t *constants; + + /** The number of buckets in the hash map. */ + uint32_t size; + + /** The number of buckets that have been allocated in the hash map. */ + uint32_t capacity; +} pm_constant_pool_t; + +/** + * Initialize a new constant pool with a given capacity. + * + * @param pool The pool to initialize. + * @param capacity The initial capacity of the pool. + * @return Whether the initialization succeeded. + */ +bool pm_constant_pool_init(pm_constant_pool_t *pool, uint32_t capacity); + +/** + * Return a pointer to the constant indicated by the given constant id. + * + * @param pool The pool to get the constant from. + * @param constant_id The id of the constant to get. + * @return A pointer to the constant. + */ +pm_constant_t * pm_constant_pool_id_to_constant(const pm_constant_pool_t *pool, pm_constant_id_t constant_id); + +/** + * Find a constant in a constant pool. Returns the id of the constant, or 0 if + * the constant is not found. + * + * @param pool The pool to find the constant in. + * @param start A pointer to the start of the constant. + * @param length The length of the constant. + * @return The id of the constant. + */ +pm_constant_id_t pm_constant_pool_find(const pm_constant_pool_t *pool, const uint8_t *start, size_t length); + +/** + * Insert a constant into a constant pool that is a slice of a source string. + * Returns the id of the constant, or 0 if any potential calls to resize fail. + * + * @param pool The pool to insert the constant into. + * @param start A pointer to the start of the constant. + * @param length The length of the constant. + * @return The id of the constant. + */ +pm_constant_id_t pm_constant_pool_insert_shared(pm_constant_pool_t *pool, const uint8_t *start, size_t length); + +/** + * Insert a constant into a constant pool from memory that is now owned by the + * constant pool. Returns the id of the constant, or 0 if any potential calls to + * resize fail. + * + * @param pool The pool to insert the constant into. + * @param start A pointer to the start of the constant. + * @param length The length of the constant. + * @return The id of the constant. + */ +pm_constant_id_t pm_constant_pool_insert_owned(pm_constant_pool_t *pool, uint8_t *start, size_t length); + +/** + * Insert a constant into a constant pool from memory that is constant. Returns + * the id of the constant, or 0 if any potential calls to resize fail. + * + * @param pool The pool to insert the constant into. + * @param start A pointer to the start of the constant. + * @param length The length of the constant. + * @return The id of the constant. + */ +pm_constant_id_t pm_constant_pool_insert_constant(pm_constant_pool_t *pool, const uint8_t *start, size_t length); + +/** + * Free the memory associated with a constant pool. + * + * @param pool The pool to free. + */ +void pm_constant_pool_free(pm_constant_pool_t *pool); + +#endif diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/util/pm_integer.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/util/pm_integer.h new file mode 100644 index 0000000..304665e --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/util/pm_integer.h @@ -0,0 +1,130 @@ +/** + * @file pm_integer.h + * + * This module provides functions for working with arbitrary-sized integers. + */ +#ifndef PRISM_NUMBER_H +#define PRISM_NUMBER_H + +#include "prism/defines.h" +#include "prism/util/pm_buffer.h" + +#include +#include +#include +#include + +/** + * A structure represents an arbitrary-sized integer. + */ +typedef struct { + /** + * The number of allocated values. length is set to 0 if the integer fits + * into uint32_t. + */ + size_t length; + + /** + * List of 32-bit integers. Set to NULL if the integer fits into uint32_t. + */ + uint32_t *values; + + /** + * Embedded value for small integer. This value is set to 0 if the value + * does not fit into uint32_t. + */ + uint32_t value; + + /** + * Whether or not the integer is negative. It is stored this way so that a + * zeroed pm_integer_t is always positive zero. + */ + bool negative; +} pm_integer_t; + +/** + * An enum controlling the base of an integer. It is expected that the base is + * already known before parsing the integer, even though it could be derived + * from the string itself. + */ +typedef enum { + /** The default decimal base, with no prefix. Leading 0s will be ignored. */ + PM_INTEGER_BASE_DEFAULT, + + /** The binary base, indicated by a 0b or 0B prefix. */ + PM_INTEGER_BASE_BINARY, + + /** The octal base, indicated by a 0, 0o, or 0O prefix. */ + PM_INTEGER_BASE_OCTAL, + + /** The decimal base, indicated by a 0d, 0D, or empty prefix. */ + PM_INTEGER_BASE_DECIMAL, + + /** The hexadecimal base, indicated by a 0x or 0X prefix. */ + PM_INTEGER_BASE_HEXADECIMAL, + + /** + * An unknown base, in which case pm_integer_parse will derive it based on + * the content of the string. This is less efficient and does more + * comparisons, so if callers know the base ahead of time, they should use + * that instead. + */ + PM_INTEGER_BASE_UNKNOWN +} pm_integer_base_t; + +/** + * Parse an integer from a string. This assumes that the format of the integer + * has already been validated, as internal validation checks are not performed + * here. + * + * @param integer The integer to parse into. + * @param base The base of the integer. + * @param start The start of the string. + * @param end The end of the string. + */ +void pm_integer_parse(pm_integer_t *integer, pm_integer_base_t base, const uint8_t *start, const uint8_t *end); + +/** + * Compare two integers. This function returns -1 if the left integer is less + * than the right integer, 0 if they are equal, and 1 if the left integer is + * greater than the right integer. + * + * @param left The left integer to compare. + * @param right The right integer to compare. + * @return The result of the comparison. + */ +int pm_integer_compare(const pm_integer_t *left, const pm_integer_t *right); + +/** + * Reduce a ratio of integers to its simplest form. + * + * If either the numerator or denominator do not fit into a 32-bit integer, then + * this function is a no-op. In the future, we may consider reducing even the + * larger numbers, but for now we're going to keep it simple. + * + * @param numerator The numerator of the ratio. + * @param denominator The denominator of the ratio. + */ +void pm_integers_reduce(pm_integer_t *numerator, pm_integer_t *denominator); + +/** + * Convert an integer to a decimal string. + * + * @param buffer The buffer to append the string to. + * @param integer The integer to convert to a string. + * + * \public \memberof pm_integer_t + */ +PRISM_EXPORTED_FUNCTION void pm_integer_string(pm_buffer_t *buffer, const pm_integer_t *integer); + +/** + * Free the internal memory of an integer. This memory will only be allocated if + * the integer exceeds the size of a single node in the linked list. + * + * @param integer The integer to free. + * + * \public \memberof pm_integer_t + */ +PRISM_EXPORTED_FUNCTION void pm_integer_free(pm_integer_t *integer); + +#endif diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/util/pm_list.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/util/pm_list.h new file mode 100644 index 0000000..f544bb2 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/util/pm_list.h @@ -0,0 +1,103 @@ +/** + * @file pm_list.h + * + * An abstract linked list. + */ +#ifndef PRISM_LIST_H +#define PRISM_LIST_H + +#include "prism/defines.h" + +#include +#include +#include +#include + +/** + * This struct represents an abstract linked list that provides common + * functionality. It is meant to be used any time a linked list is necessary to + * store data. + * + * The linked list itself operates off a set of pointers. Because the pointers + * are not necessarily sequential, they can be of any size. We use this fact to + * allow the consumer of this linked list to extend the node struct to include + * any data they want. This is done by using the pm_list_node_t as the first + * member of the struct. + * + * For example, if we want to store a list of integers, we can do the following: + * + * ```c + * typedef struct { + * pm_list_node_t node; + * int value; + * } pm_int_node_t; + * + * pm_list_t list = { 0 }; + * pm_int_node_t *node = xmalloc(sizeof(pm_int_node_t)); + * node->value = 5; + * + * pm_list_append(&list, &node->node); + * ``` + * + * The pm_list_t struct is used to represent the overall linked list. It + * contains a pointer to the head and tail of the list. This allows for easy + * iteration and appending of new nodes. + */ +typedef struct pm_list_node { + /** A pointer to the next node in the list. */ + struct pm_list_node *next; +} pm_list_node_t; + +/** + * This represents the overall linked list. It keeps a pointer to the head and + * tail so that iteration is easy and pushing new nodes is easy. + */ +typedef struct { + /** The size of the list. */ + size_t size; + + /** A pointer to the head of the list. */ + pm_list_node_t *head; + + /** A pointer to the tail of the list. */ + pm_list_node_t *tail; +} pm_list_t; + +/** + * Returns true if the given list is empty. + * + * @param list The list to check. + * @return True if the given list is empty, otherwise false. + * + * \public \memberof pm_list_t + */ +PRISM_EXPORTED_FUNCTION bool pm_list_empty_p(pm_list_t *list); + +/** + * Returns the size of the list. + * + * @param list The list to check. + * @return The size of the list. + * + * \public \memberof pm_list_t + */ +PRISM_EXPORTED_FUNCTION size_t pm_list_size(pm_list_t *list); + +/** + * Append a node to the given list. + * + * @param list The list to append to. + * @param node The node to append. + */ +void pm_list_append(pm_list_t *list, pm_list_node_t *node); + +/** + * Deallocate the internal state of the given list. + * + * @param list The list to free. + * + * \public \memberof pm_list_t + */ +PRISM_EXPORTED_FUNCTION void pm_list_free(pm_list_t *list); + +#endif diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/util/pm_memchr.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/util/pm_memchr.h new file mode 100644 index 0000000..e0671ea --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/util/pm_memchr.h @@ -0,0 +1,29 @@ +/** + * @file pm_memchr.h + * + * A custom memchr implementation. + */ +#ifndef PRISM_MEMCHR_H +#define PRISM_MEMCHR_H + +#include "prism/defines.h" +#include "prism/encoding.h" + +#include + +/** + * We need to roll our own memchr to handle cases where the encoding changes and + * we need to search for a character in a buffer that could be the trailing byte + * of a multibyte character. + * + * @param source The source string. + * @param character The character to search for. + * @param number The maximum number of bytes to search. + * @param encoding_changed Whether the encoding changed. + * @param encoding A pointer to the encoding. + * @return A pointer to the first occurrence of the character in the source + * string, or NULL if no such character exists. + */ +void * pm_memchr(const void *source, int character, size_t number, bool encoding_changed, const pm_encoding_t *encoding); + +#endif diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/util/pm_newline_list.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/util/pm_newline_list.h new file mode 100644 index 0000000..406abe8 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/util/pm_newline_list.h @@ -0,0 +1,113 @@ +/** + * @file pm_newline_list.h + * + * A list of byte offsets of newlines in a string. + * + * When compiling the syntax tree, it's necessary to know the line and column + * of many nodes. This is necessary to support things like error messages, + * tracepoints, etc. + * + * It's possible that we could store the start line, start column, end line, and + * end column on every node in addition to the offsets that we already store, + * but that would be quite a lot of memory overhead. + */ +#ifndef PRISM_NEWLINE_LIST_H +#define PRISM_NEWLINE_LIST_H + +#include "prism/defines.h" + +#include +#include +#include +#include + +/** + * A list of offsets of newlines in a string. The offsets are assumed to be + * sorted/inserted in ascending order. + */ +typedef struct { + /** A pointer to the start of the source string. */ + const uint8_t *start; + + /** The number of offsets in the list. */ + size_t size; + + /** The capacity of the list that has been allocated. */ + size_t capacity; + + /** The list of offsets. */ + size_t *offsets; +} pm_newline_list_t; + +/** + * A line and column in a string. + */ +typedef struct { + /** The line number. */ + int32_t line; + + /** The column number. */ + uint32_t column; +} pm_line_column_t; + +/** + * Initialize a new newline list with the given capacity. Returns true if the + * allocation of the offsets succeeds, otherwise returns false. + * + * @param list The list to initialize. + * @param start A pointer to the start of the source string. + * @param capacity The initial capacity of the list. + * @return True if the allocation of the offsets succeeds, otherwise false. + */ +bool pm_newline_list_init(pm_newline_list_t *list, const uint8_t *start, size_t capacity); + +/** + * Clear out the newlines that have been appended to the list. + * + * @param list The list to clear. + */ +void +pm_newline_list_clear(pm_newline_list_t *list); + +/** + * Append a new offset to the newline list. Returns true if the reallocation of + * the offsets succeeds (if one was necessary), otherwise returns false. + * + * @param list The list to append to. + * @param cursor A pointer to the offset to append. + * @return True if the reallocation of the offsets succeeds (if one was + * necessary), otherwise false. + */ +bool pm_newline_list_append(pm_newline_list_t *list, const uint8_t *cursor); + +/** + * Returns the line of the given offset. If the offset is not in the list, the + * line of the closest offset less than the given offset is returned. + * + * @param list The list to search. + * @param cursor A pointer to the offset to search for. + * @param start_line The line to start counting from. + * @return The line of the given offset. + */ +int32_t pm_newline_list_line(const pm_newline_list_t *list, const uint8_t *cursor, int32_t start_line); + +/** + * Returns the line and column of the given offset. If the offset is not in the + * list, the line and column of the closest offset less than the given offset + * are returned. + * + * @param list The list to search. + * @param cursor A pointer to the offset to search for. + * @param start_line The line to start counting from. + * @return The line and column of the given offset. + */ +pm_line_column_t pm_newline_list_line_column(const pm_newline_list_t *list, const uint8_t *cursor, int32_t start_line); + +/** + * Free the internal memory allocated for the newline list. + * + * @param list The list to free. + */ +void pm_newline_list_free(pm_newline_list_t *list); + +#endif diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/util/pm_string.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/util/pm_string.h new file mode 100644 index 0000000..d8456ff --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/util/pm_string.h @@ -0,0 +1,200 @@ +/** + * @file pm_string.h + * + * A generic string type that can have various ownership semantics. + */ +#ifndef PRISM_STRING_H +#define PRISM_STRING_H + +#include "prism/defines.h" + +#include +#include +#include +#include +#include +#include + +// The following headers are necessary to read files using demand paging. +#ifdef _WIN32 +#include +#elif defined(_POSIX_MAPPED_FILES) +#include +#include +#include +#elif defined(PRISM_HAS_FILESYSTEM) +#include +#include +#endif + +/** + * A generic string type that can have various ownership semantics. + */ +typedef struct { + /** A pointer to the start of the string. */ + const uint8_t *source; + + /** The length of the string in bytes of memory. */ + size_t length; + + /** The type of the string. This field determines how the string should be freed. */ + enum { + /** This string is a constant string, and should not be freed. */ + PM_STRING_CONSTANT, + + /** This is a slice of another string, and should not be freed. */ + PM_STRING_SHARED, + + /** This string owns its memory, and should be freed using `pm_string_free()`. */ + PM_STRING_OWNED, + +#ifdef PRISM_HAS_MMAP + /** This string is a memory-mapped file, and should be freed using `pm_string_free()`. */ + PM_STRING_MAPPED +#endif + } type; +} pm_string_t; + +/** + * Returns the size of the pm_string_t struct. This is necessary to allocate the + * correct amount of memory in the FFI backend. + * + * @return The size of the pm_string_t struct. + */ +PRISM_EXPORTED_FUNCTION size_t pm_string_sizeof(void); + +/** + * Defines an empty string. This is useful for initializing a string that will + * be filled in later. + */ +#define PM_STRING_EMPTY ((pm_string_t) { .type = PM_STRING_CONSTANT, .source = NULL, .length = 0 }) + +/** + * Initialize a shared string that is based on initial input. + * + * @param string The string to initialize. + * @param start The start of the string. + * @param end The end of the string. + */ +void pm_string_shared_init(pm_string_t *string, const uint8_t *start, const uint8_t *end); + +/** + * Initialize an owned string that is responsible for freeing allocated memory. + * + * @param string The string to initialize. + * @param source The source of the string. + * @param length The length of the string. + */ +void pm_string_owned_init(pm_string_t *string, uint8_t *source, size_t length); + +/** + * Initialize a constant string that doesn't own its memory source. + * + * @param string The string to initialize. + * @param source The source of the string. + * @param length The length of the string. + */ +void pm_string_constant_init(pm_string_t *string, const char *source, size_t length); + +/** + * Represents the result of calling pm_string_mapped_init or + * pm_string_file_init. We need this additional information because there is + * not a platform-agnostic way to indicate that the file that was attempted to + * be opened was a directory. + */ +typedef enum { + /** Indicates that the string was successfully initialized. */ + PM_STRING_INIT_SUCCESS = 0, + /** + * Indicates a generic error from a string_*_init function, where the type + * of error should be read from `errno` or `GetLastError()`. + */ + PM_STRING_INIT_ERROR_GENERIC = 1, + /** + * Indicates that the file that was attempted to be opened was a directory. + */ + PM_STRING_INIT_ERROR_DIRECTORY = 2 +} pm_string_init_result_t; + +/** + * Read the file indicated by the filepath parameter into source and load its + * contents and size into the given `pm_string_t`. The given `pm_string_t` + * should be freed using `pm_string_free` when it is no longer used. + * + * We want to use demand paging as much as possible in order to avoid having to + * read the entire file into memory (which could be detrimental to performance + * for large files). This means that if we're on windows we'll use + * `MapViewOfFile`, on POSIX systems that have access to `mmap` we'll use + * `mmap`, and on other POSIX systems we'll use `read`. + * + * @param string The string to initialize. + * @param filepath The filepath to read. + * @return The success of the read, indicated by the value of the enum. + * + * \public \memberof pm_string_t + */ +PRISM_EXPORTED_FUNCTION pm_string_init_result_t pm_string_mapped_init(pm_string_t *string, const char *filepath); + +/** + * Read the file indicated by the filepath parameter into source and load its + * contents and size into the given `pm_string_t`. The given `pm_string_t` + * should be freed using `pm_string_free` when it is no longer used. + * + * @param string The string to initialize. + * @param filepath The filepath to read. + * @return The success of the read, indicated by the value of the enum. + * + * \public \memberof pm_string_t + */ +PRISM_EXPORTED_FUNCTION pm_string_init_result_t pm_string_file_init(pm_string_t *string, const char *filepath); + +/** + * Ensure the string is owned. If it is not, then reinitialize it as owned and + * copy over the previous source. + * + * @param string The string to ensure is owned. + */ +void pm_string_ensure_owned(pm_string_t *string); + +/** + * Compare the underlying lengths and bytes of two strings. Returns 0 if the + * strings are equal, a negative number if the left string is less than the + * right string, and a positive number if the left string is greater than the + * right string. + * + * @param left The left string to compare. + * @param right The right string to compare. + * @return The comparison result. + */ +int pm_string_compare(const pm_string_t *left, const pm_string_t *right); + +/** + * Returns the length associated with the string. + * + * @param string The string to get the length of. + * @return The length of the string. + * + * \public \memberof pm_string_t + */ +PRISM_EXPORTED_FUNCTION size_t pm_string_length(const pm_string_t *string); + +/** + * Returns the start pointer associated with the string. + * + * @param string The string to get the start pointer of. + * @return The start pointer of the string. + * + * \public \memberof pm_string_t + */ +PRISM_EXPORTED_FUNCTION const uint8_t * pm_string_source(const pm_string_t *string); + +/** + * Free the associated memory of the given string. + * + * @param string The string to free. + * + * \public \memberof pm_string_t + */ +PRISM_EXPORTED_FUNCTION void pm_string_free(pm_string_t *string); + +#endif diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/util/pm_strncasecmp.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/util/pm_strncasecmp.h new file mode 100644 index 0000000..5cb88cb --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/util/pm_strncasecmp.h @@ -0,0 +1,32 @@ +/** + * @file pm_strncasecmp.h + * + * A custom strncasecmp implementation. + */ +#ifndef PRISM_STRNCASECMP_H +#define PRISM_STRNCASECMP_H + +#include "prism/defines.h" + +#include +#include +#include + +/** + * Compare two strings, ignoring case, up to the given length. Returns 0 if the + * strings are equal, a negative number if string1 is less than string2, or a + * positive number if string1 is greater than string2. + * + * Note that this is effectively our own implementation of strncasecmp, but it's + * not available on all of the platforms we want to support so we're rolling it + * here. + * + * @param string1 The first string to compare. + * @param string2 The second string to compare + * @param length The maximum number of characters to compare. + * @return 0 if the strings are equal, a negative number if string1 is less than + * string2, or a positive number if string1 is greater than string2. + */ +int pm_strncasecmp(const uint8_t *string1, const uint8_t *string2, size_t length); + +#endif diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/util/pm_strpbrk.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/util/pm_strpbrk.h new file mode 100644 index 0000000..f387bd5 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/util/pm_strpbrk.h @@ -0,0 +1,46 @@ +/** + * @file pm_strpbrk.h + * + * A custom strpbrk implementation. + */ +#ifndef PRISM_STRPBRK_H +#define PRISM_STRPBRK_H + +#include "prism/defines.h" +#include "prism/diagnostic.h" +#include "prism/parser.h" + +#include +#include + +/** + * Here we have rolled our own version of strpbrk. The standard library strpbrk + * has undefined behavior when the source string is not null-terminated. We want + * to support strings that are not null-terminated because pm_parse does not + * have the contract that the string is null-terminated. (This is desirable + * because it means the extension can call pm_parse with the result of a call to + * mmap). + * + * The standard library strpbrk also does not support passing a maximum length + * to search. We want to support this for the reason mentioned above, but we + * also don't want it to stop on null bytes. Ruby actually allows null bytes + * within strings, comments, regular expressions, etc. So we need to be able to + * skip past them. + * + * Finally, we want to support encodings wherein the charset could contain + * characters that are trailing bytes of multi-byte characters. For example, in + * Shift-JIS, the backslash character can be a trailing byte. In that case we + * need to take a slower path and iterate one multi-byte character at a time. + * + * @param parser The parser. + * @param source The source to search. + * @param charset The charset to search for. + * @param length The maximum number of bytes to search. + * @param validate Whether to validate that the source string is valid in the + * current encoding of the parser. + * @return A pointer to the first character in the source string that is in the + * charset, or NULL if no such character exists. + */ +const uint8_t * pm_strpbrk(pm_parser_t *parser, const uint8_t *source, const uint8_t *charset, ptrdiff_t length, bool validate); + +#endif diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/version.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/version.h new file mode 100644 index 0000000..f202b0f --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism/version.h @@ -0,0 +1,29 @@ +/** + * @file version.h + * + * The version of the Prism library. + */ +#ifndef PRISM_VERSION_H +#define PRISM_VERSION_H + +/** + * The major version of the Prism library as an int. + */ +#define PRISM_VERSION_MAJOR 1 + +/** + * The minor version of the Prism library as an int. + */ +#define PRISM_VERSION_MINOR 6 + +/** + * The patch version of the Prism library as an int. + */ +#define PRISM_VERSION_PATCH 0 + +/** + * The version of the Prism library as a constant string. + */ +#define PRISM_VERSION "1.6.0" + +#endif diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism_compile.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism_compile.h new file mode 100644 index 0000000..e588122 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/prism_compile.h @@ -0,0 +1,106 @@ +#include "prism/prism.h" +#include "ruby/encoding.h" + +/** + * the getlocal and setlocal instructions require two parameters. level is how + * many hops up the iseq stack one needs to go before finding the correct local + * table. The index is the index in that table where our variable is. + * + * Because these are always calculated and used together, we'll bind them + * together as a tuple. + */ +typedef struct pm_local_index_struct { + int index, level; +} pm_local_index_t; + +// A declaration for the struct that lives in compile.c. +struct iseq_link_anchor; + +// ScopeNodes are helper nodes, and will never be part of the AST. We manually +// declare them here to avoid generating them. +typedef struct pm_scope_node { + pm_node_t base; + struct pm_scope_node *previous; + pm_node_t *ast_node; + pm_node_t *parameters; + pm_node_t *body; + pm_constant_id_list_t locals; + + const pm_parser_t *parser; + rb_encoding *encoding; + + /** + * This is a pointer to the list of script lines for the ISEQs that will be + * associated with this scope node. It is only set if + * RubyVM.keep_script_lines is true. If it is set, it will be set to a + * pointer to an array that is always stack allocated (so no GC marking is + * needed by this struct). If it is not set, it will be NULL. It is + * inherited by all child scopes. + */ + VALUE *script_lines; + + /** + * This is the encoding of the actual filepath object that will be used when + * a __FILE__ node is compiled or when the path has to be set on a syntax + * error. + */ + rb_encoding *filepath_encoding; + + // The size of the local table on the iseq which includes locals and hidden + // variables. + int local_table_for_iseq_size; + + ID *constants; + st_table *index_lookup_table; + + // The current coverage setting, passed down through the various scopes. + int coverage_enabled; + + /** + * This will only be set on the top-level scope node. It will contain all of + * the instructions pertaining to BEGIN{} nodes. + */ + struct iseq_link_anchor *pre_execution_anchor; +} pm_scope_node_t; + +void pm_scope_node_init(const pm_node_t *node, pm_scope_node_t *scope, pm_scope_node_t *previous); +void pm_scope_node_destroy(pm_scope_node_t *scope_node); + +typedef struct { + /** The parser that will do the actual parsing. */ + pm_parser_t parser; + + /** The options that will be passed to the parser. */ + pm_options_t options; + + /** The input that represents the source to be parsed. */ + pm_string_t input; + + /** The resulting scope node that will hold the generated AST. */ + pm_scope_node_t node; + + /** Whether or not this parse result has performed its parsing yet. */ + bool parsed; +} pm_parse_result_t; + +#define PM_SPECIAL_CONSTANT_FLAG ((pm_constant_id_t)(1 << 31)) +#define PM_CONSTANT_AND ((pm_constant_id_t)(idAnd | PM_SPECIAL_CONSTANT_FLAG)) +#define PM_CONSTANT_DOT3 ((pm_constant_id_t)(idDot3 | PM_SPECIAL_CONSTANT_FLAG)) +#define PM_CONSTANT_MULT ((pm_constant_id_t)(idMULT | PM_SPECIAL_CONSTANT_FLAG)) +#define PM_CONSTANT_POW ((pm_constant_id_t)(idPow | PM_SPECIAL_CONSTANT_FLAG)) + +VALUE pm_load_file(pm_parse_result_t *result, VALUE filepath, bool load_error); +VALUE pm_parse_file(pm_parse_result_t *result, VALUE filepath, VALUE *script_lines); +VALUE pm_load_parse_file(pm_parse_result_t *result, VALUE filepath, VALUE *script_lines); +VALUE pm_parse_string(pm_parse_result_t *result, VALUE source, VALUE filepath, VALUE *script_lines); +VALUE pm_parse_stdin(pm_parse_result_t *result); +void pm_options_version_for_current_ruby_set(pm_options_t *options); +void pm_parse_result_free(pm_parse_result_t *result); + +rb_iseq_t *pm_iseq_new(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpath, const rb_iseq_t *parent, enum rb_iseq_type, int *error_state); +rb_iseq_t *pm_iseq_new_top(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpath, const rb_iseq_t *parent, int *error_state); +rb_iseq_t *pm_iseq_new_main(pm_scope_node_t *node, VALUE path, VALUE realpath, const rb_iseq_t *parent, int opt, int *error_state); +rb_iseq_t *pm_iseq_new_eval(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpath, int first_lineno, const rb_iseq_t *parent, int isolated_depth, int *error_state); +rb_iseq_t *pm_iseq_new_with_opt(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpath, int first_lineno, const rb_iseq_t *parent, int isolated_depth, enum rb_iseq_type, const rb_compile_option_t *option, int *error_state); + +VALUE pm_iseq_compile_node(rb_iseq_t *iseq, pm_scope_node_t *node); diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/ractor_core.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/ractor_core.h new file mode 100644 index 0000000..130ccb1 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/ractor_core.h @@ -0,0 +1,306 @@ +#include "internal/gc.h" +#include "ruby/ruby.h" +#include "ruby/ractor.h" +#include "vm_core.h" +#include "id_table.h" +#include "vm_debug.h" + +#ifndef RACTOR_CHECK_MODE +#define RACTOR_CHECK_MODE (VM_CHECK_MODE || RUBY_DEBUG) && (SIZEOF_UINT64_T == SIZEOF_VALUE) +#endif + +struct rb_ractor_sync { + // ractor lock + rb_nativethread_lock_t lock; + +#if RACTOR_CHECK_MODE > 0 + VALUE locked_by; +#endif + +#ifndef RUBY_THREAD_PTHREAD_H + rb_nativethread_cond_t wakeup_cond; +#endif + + // incoming messages + struct ractor_queue *recv_queue; + + // waiting threads for receiving + struct ccan_list_head waiters; + + // ports + VALUE default_port_value; + struct st_table *ports; + size_t next_port_id; + + // monitors + struct ccan_list_head monitors; + + // value + rb_ractor_t *successor; + VALUE legacy; + bool legacy_exc; +}; + +// created +// | ready to run +// ====================== inserted to vm->ractor +// v +// blocking <---+ all threads are blocking +// | | +// v | +// running -----+ +// | all threads are terminated. +// ====================== removed from vm->ractor +// v +// terminated +// +// status is protected by VM lock (global state) +enum ractor_status { + ractor_created, + ractor_running, + ractor_blocking, + ractor_terminated, +}; + +struct rb_ractor_struct { + struct rb_ractor_pub pub; + struct rb_ractor_sync sync; + + // thread management + struct { + struct ccan_list_head set; + unsigned int cnt; + unsigned int blocking_cnt; + unsigned int sleeper; + struct rb_thread_sched sched; + rb_execution_context_t *running_ec; + rb_thread_t *main; + } threads; + + VALUE thgroup_default; + + VALUE name; + VALUE loc; + + enum ractor_status status_; + + struct ccan_list_node vmlr_node; + + // ractor local data + + st_table *local_storage; + struct rb_id_table *idkey_local_storage; + VALUE local_storage_store_lock; + + VALUE r_stdin; + VALUE r_stdout; + VALUE r_stderr; + VALUE verbose; + VALUE debug; + + bool malloc_gc_disabled; + void *newobj_cache; +}; // rb_ractor_t is defined in vm_core.h + + +static inline VALUE +rb_ractor_self(const rb_ractor_t *r) +{ + return r->pub.self; +} + +rb_ractor_t *rb_ractor_main_alloc(void); +void rb_ractor_main_setup(rb_vm_t *vm, rb_ractor_t *main_ractor, rb_thread_t *main_thread); +void rb_ractor_atexit(rb_execution_context_t *ec, VALUE result); +void rb_ractor_atexit_exception(rb_execution_context_t *ec); +void rb_ractor_teardown(rb_execution_context_t *ec); +void rb_ractor_receive_parameters(rb_execution_context_t *ec, rb_ractor_t *g, int len, VALUE *ptr); +void rb_ractor_send_parameters(rb_execution_context_t *ec, rb_ractor_t *g, VALUE args); + +VALUE rb_thread_create_ractor(rb_ractor_t *g, VALUE args, VALUE proc); // defined in thread.c + +int rb_ractor_living_thread_num(const rb_ractor_t *); +VALUE rb_ractor_thread_list(void); +bool rb_ractor_p(VALUE rv); + +void rb_ractor_living_threads_init(rb_ractor_t *r); +void rb_ractor_living_threads_insert(rb_ractor_t *r, rb_thread_t *th); +void rb_ractor_living_threads_remove(rb_ractor_t *r, rb_thread_t *th); +void rb_ractor_blocking_threads_inc(rb_ractor_t *r, const char *file, int line); // TODO: file, line only for RUBY_DEBUG_LOG +void rb_ractor_blocking_threads_dec(rb_ractor_t *r, const char *file, int line); // TODO: file, line only for RUBY_DEBUG_LOG + +void rb_ractor_vm_barrier_interrupt_running_thread(rb_ractor_t *r); +void rb_ractor_terminate_interrupt_main_thread(rb_ractor_t *r); +void rb_ractor_terminate_all(void); +bool rb_ractor_main_p_(void); +void rb_ractor_atfork(rb_vm_t *vm, rb_thread_t *th); +void rb_ractor_terminate_atfork(rb_vm_t *vm, rb_ractor_t *th); +VALUE rb_ractor_require(VALUE feature, bool silent); +VALUE rb_ractor_autoload_load(VALUE space, ID id); + +VALUE rb_ractor_ensure_shareable(VALUE obj, VALUE name); + +RUBY_SYMBOL_EXPORT_BEGIN +void rb_ractor_finish_marking(void); + +bool rb_ractor_shareable_p_continue(VALUE obj); + +// THIS FUNCTION SHOULD NOT CALL WHILE INCREMENTAL MARKING!! +// This function is for T_DATA::free_func +void rb_ractor_local_storage_delkey(rb_ractor_local_key_t key); + +RUBY_SYMBOL_EXPORT_END + +static inline bool +rb_ractor_main_p(void) +{ + if (ruby_single_main_ractor) { + return true; + } + else { + return rb_ractor_main_p_(); + } +} + +static inline bool +rb_ractor_status_p(rb_ractor_t *r, enum ractor_status status) +{ + return r->status_ == status; +} + +static inline void +rb_ractor_sleeper_threads_inc(rb_ractor_t *r) +{ + r->threads.sleeper++; +} + +static inline void +rb_ractor_sleeper_threads_dec(rb_ractor_t *r) +{ + r->threads.sleeper--; +} + +static inline void +rb_ractor_sleeper_threads_clear(rb_ractor_t *r) +{ + r->threads.sleeper = 0; +} + +static inline int +rb_ractor_sleeper_thread_num(rb_ractor_t *r) +{ + return r->threads.sleeper; +} + +static inline void +rb_ractor_thread_switch(rb_ractor_t *cr, rb_thread_t *th, bool always_reset) +{ + RUBY_DEBUG_LOG("th:%d->%u%s", + cr->threads.running_ec ? (int)rb_th_serial(cr->threads.running_ec->thread_ptr) : -1, + rb_th_serial(th), cr->threads.running_ec == th->ec ? " (same)" : ""); + + if (cr->threads.running_ec != th->ec || always_reset) { + th->running_time_us = 0; + } + + if (cr->threads.running_ec != th->ec) { + if (0) { + ruby_debug_printf("rb_ractor_thread_switch ec:%p->%p\n", + (void *)cr->threads.running_ec, (void *)th->ec); + } + } + else { + return; + } + + cr->threads.running_ec = th->ec; + + VM_ASSERT(cr == GET_RACTOR()); +} + +#define rb_ractor_set_current_ec(cr, ec) rb_ractor_set_current_ec_(cr, ec, __FILE__, __LINE__) +#ifdef RB_THREAD_LOCAL_SPECIFIER +void rb_current_ec_set(rb_execution_context_t *ec); +#endif + +static inline void +rb_ractor_set_current_ec_(rb_ractor_t *cr, rb_execution_context_t *ec, const char *file, int line) +{ +#ifdef RB_THREAD_LOCAL_SPECIFIER + rb_current_ec_set(ec); +#else + native_tls_set(ruby_current_ec_key, ec); +#endif + RUBY_DEBUG_LOG2(file, line, "ec:%p->%p", (void *)cr->threads.running_ec, (void *)ec); + VM_ASSERT(ec == NULL || cr->threads.running_ec != ec); + cr->threads.running_ec = ec; +} + +void rb_vm_ractor_blocking_cnt_inc(rb_vm_t *vm, rb_ractor_t *cr, const char *file, int line); +void rb_vm_ractor_blocking_cnt_dec(rb_vm_t *vm, rb_ractor_t *cr, const char *file, int line); + +static inline uint32_t +rb_ractor_id(const rb_ractor_t *r) +{ + return r->pub.id; +} + +#if RACTOR_CHECK_MODE > 0 +# define RACTOR_BELONGING_ID(obj) (*(uint32_t *)(((uintptr_t)(obj)) + rb_gc_obj_slot_size(obj))) + +uint32_t rb_ractor_current_id(void); + +static inline void +rb_ractor_setup_belonging_to(VALUE obj, uint32_t rid) +{ + RACTOR_BELONGING_ID(obj) = rid; +} + +static inline uint32_t +rb_ractor_belonging(VALUE obj) +{ + if (SPECIAL_CONST_P(obj) || RB_OBJ_SHAREABLE_P(obj)) { + return 0; + } + else { + return RACTOR_BELONGING_ID(obj); + } +} + +extern bool rb_ractor_ignore_belonging_flag; + +static inline VALUE +rb_ractor_confirm_belonging(VALUE obj) +{ + if (rb_ractor_ignore_belonging_flag) return obj; + + uint32_t id = rb_ractor_belonging(obj); + + if (id == 0) { + if (UNLIKELY(!rb_ractor_shareable_p(obj))) { + rp(obj); + rb_bug("id == 0 but not shareable"); + } + } + else if (UNLIKELY(id != rb_ractor_current_id())) { + if (rb_ractor_shareable_p(obj)) { + // ok + } + else { + rp(obj); + rb_bug("rb_ractor_confirm_belonging object-ractor id:%u, current-ractor id:%u", id, rb_ractor_current_id()); + } + } + return obj; +} + +static inline void +rb_ractor_ignore_belonging(bool flag) +{ + rb_ractor_ignore_belonging_flag = flag; +} + +#else +#define rb_ractor_confirm_belonging(obj) obj +#define rb_ractor_ignore_belonging(flag) (0) +#endif diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/ruby_assert.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/ruby_assert.h new file mode 100644 index 0000000..d8f7ddd --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/ruby_assert.h @@ -0,0 +1,14 @@ +#ifndef RUBY_TOPLEVEL_ASSERT_H /*-*-C-*-vi:se ft=c:*/ +#define RUBY_TOPLEVEL_ASSERT_H +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + */ +#include "ruby/assert.h" +#undef assert +#define assert RUBY_ASSERT_NDEBUG + +#endif /* RUBY_TOPLEVEL_ASSERT_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/ruby_atomic.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/ruby_atomic.h new file mode 100644 index 0000000..ad53356 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/ruby_atomic.h @@ -0,0 +1,66 @@ +#ifndef INTERNAL_ATOMIC_H +#define INTERNAL_ATOMIC_H + +#include "ruby/atomic.h" + +#define RUBY_ATOMIC_VALUE_LOAD(x) rbimpl_atomic_value_load(&(x), RBIMPL_ATOMIC_SEQ_CST) + +/* shim macros only */ +#define ATOMIC_ADD(var, val) RUBY_ATOMIC_ADD(var, val) +#define ATOMIC_CAS(var, oldval, newval) RUBY_ATOMIC_CAS(var, oldval, newval) +#define ATOMIC_DEC(var) RUBY_ATOMIC_DEC(var) +#define ATOMIC_EXCHANGE(var, val) RUBY_ATOMIC_EXCHANGE(var, val) +#define ATOMIC_FETCH_ADD(var, val) RUBY_ATOMIC_FETCH_ADD(var, val) +#define ATOMIC_FETCH_SUB(var, val) RUBY_ATOMIC_FETCH_SUB(var, val) +#define ATOMIC_INC(var) RUBY_ATOMIC_INC(var) +#define ATOMIC_OR(var, val) RUBY_ATOMIC_OR(var, val) +#define ATOMIC_PTR_CAS(var, oldval, newval) RUBY_ATOMIC_PTR_CAS(var, oldval, newval) +#define ATOMIC_PTR_EXCHANGE(var, val) RUBY_ATOMIC_PTR_EXCHANGE(var, val) +#define ATOMIC_SET(var, val) RUBY_ATOMIC_SET(var, val) +#define ATOMIC_SIZE_ADD(var, val) RUBY_ATOMIC_SIZE_ADD(var, val) +#define ATOMIC_SIZE_CAS(var, oldval, newval) RUBY_ATOMIC_SIZE_CAS(var, oldval, newval) +#define ATOMIC_SIZE_DEC(var) RUBY_ATOMIC_SIZE_DEC(var) +#define ATOMIC_SIZE_EXCHANGE(var, val) RUBY_ATOMIC_SIZE_EXCHANGE(var, val) +#define ATOMIC_SIZE_INC(var) RUBY_ATOMIC_SIZE_INC(var) +#define ATOMIC_SIZE_SUB(var, val) RUBY_ATOMIC_SIZE_SUB(var, val) +#define ATOMIC_SUB(var, val) RUBY_ATOMIC_SUB(var, val) +#define ATOMIC_VALUE_CAS(var, oldval, val) RUBY_ATOMIC_VALUE_CAS(var, oldval, val) +#define ATOMIC_VALUE_EXCHANGE(var, val) RUBY_ATOMIC_VALUE_EXCHANGE(var, val) + +#define ATOMIC_LOAD_RELAXED(var) rbimpl_atomic_load(&(var), RBIMPL_ATOMIC_RELAXED) + +typedef RBIMPL_ALIGNAS(8) uint64_t rbimpl_atomic_uint64_t; + +static inline uint64_t +rbimpl_atomic_u64_load_relaxed(const volatile rbimpl_atomic_uint64_t *value) +{ +#if defined(HAVE_GCC_ATOMIC_BUILTINS_64) + return __atomic_load_n(value, __ATOMIC_RELAXED); +#elif defined(_WIN32) + uint64_t val = *value; + return InterlockedCompareExchange64(RBIMPL_CAST((uint64_t *)value), val, val); +#elif defined(__sun) && defined(HAVE_ATOMIC_H) && (defined(_LP64) || defined(_I32LPx)) + uint64_t val = *value; + return atomic_cas_64(value, val, val); +#else + return *value; +#endif +} +#define ATOMIC_U64_LOAD_RELAXED(var) rbimpl_atomic_u64_load_relaxed(&(var)) + +static inline void +rbimpl_atomic_u64_set_relaxed(volatile rbimpl_atomic_uint64_t *address, uint64_t value) +{ +#if defined(HAVE_GCC_ATOMIC_BUILTINS_64) + __atomic_store_n(address, value, __ATOMIC_RELAXED); +#elif defined(_WIN32) + InterlockedExchange64(address, value); +#elif defined(__sun) && defined(HAVE_ATOMIC_H) && (defined(_LP64) || defined(_I32LPx)) + atomic_swap_64(address, value); +#else + *address = value; +#endif +} +#define ATOMIC_U64_SET_RELAXED(var, val) rbimpl_atomic_u64_set_relaxed(&(var), val) + +#endif diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/rubyparser.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/rubyparser.h new file mode 100644 index 0000000..ee4fe2e --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/rubyparser.h @@ -0,0 +1,1394 @@ +#ifndef RUBY_RUBYPARSER_H +#define RUBY_RUBYPARSER_H 1 +/* + * This is a header file for librubyparser interface + */ + +#include /* for va_list */ +#include + +#ifdef UNIVERSAL_PARSER + +#define rb_encoding const void +#define OnigCodePoint unsigned int +#include "parser_st.h" +#ifndef RUBY_RUBY_H +#include "parser_value.h" +#endif + +#else + +#include "ruby/encoding.h" + +#endif + +#ifndef FLEX_ARY_LEN +/* From internal/compilers.h */ +/* A macro for defining a flexible array, like: VALUE ary[FLEX_ARY_LEN]; */ +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +# define FLEX_ARY_LEN /* VALUE ary[]; */ +#elif defined(__GNUC__) && !defined(__STRICT_ANSI__) +# define FLEX_ARY_LEN 0 /* VALUE ary[0]; */ +#else +# define FLEX_ARY_LEN 1 /* VALUE ary[1]; */ +#endif +#endif + +#if defined(__GNUC__) +# if defined(__MINGW_PRINTF_FORMAT) +# define RUBYPARSER_ATTRIBUTE_FORMAT(string_index, argument_index) __attribute__((format(__MINGW_PRINTF_FORMAT, string_index, argument_index))) +# else +# define RUBYPARSER_ATTRIBUTE_FORMAT(string_index, argument_index) __attribute__((format(printf, string_index, argument_index))) +# endif +#elif defined(__clang__) +# define RUBYPARSER_ATTRIBUTE_FORMAT(string_index, argument_index) __attribute__((__format__(__printf__, string_index, argument_index))) +#else +# define RUBYPARSER_ATTRIBUTE_FORMAT(string_index, argument_index) +#endif + +/* + * Parser String + */ +enum rb_parser_string_coderange_type { + /** The object's coderange is unclear yet. */ + RB_PARSER_ENC_CODERANGE_UNKNOWN = 0, + RB_PARSER_ENC_CODERANGE_7BIT = 1, + RB_PARSER_ENC_CODERANGE_VALID = 2, + RB_PARSER_ENC_CODERANGE_BROKEN = 3 +}; + +typedef struct rb_parser_string { + enum rb_parser_string_coderange_type coderange; + rb_encoding *enc; + /* Length of the string, not including terminating NUL character. */ + long len; + /* Pointer to the contents of the string. */ + char *ptr; +} rb_parser_string_t; + +enum rb_parser_shareability { + rb_parser_shareable_none, + rb_parser_shareable_literal, + rb_parser_shareable_copy, + rb_parser_shareable_everything, +}; + +typedef void* rb_parser_input_data; + +/* + * AST Node + */ +enum node_type { + NODE_SCOPE, + NODE_BLOCK, + NODE_IF, + NODE_UNLESS, + NODE_CASE, + NODE_CASE2, + NODE_CASE3, + NODE_WHEN, + NODE_IN, + NODE_WHILE, + NODE_UNTIL, + NODE_ITER, + NODE_FOR, + NODE_FOR_MASGN, + NODE_BREAK, + NODE_NEXT, + NODE_REDO, + NODE_RETRY, + NODE_BEGIN, + NODE_RESCUE, + NODE_RESBODY, + NODE_ENSURE, + NODE_AND, + NODE_OR, + NODE_MASGN, + NODE_LASGN, + NODE_DASGN, + NODE_GASGN, + NODE_IASGN, + NODE_CDECL, + NODE_CVASGN, + NODE_OP_ASGN1, + NODE_OP_ASGN2, + NODE_OP_ASGN_AND, + NODE_OP_ASGN_OR, + NODE_OP_CDECL, + NODE_CALL, + NODE_OPCALL, + NODE_FCALL, + NODE_VCALL, + NODE_QCALL, + NODE_SUPER, + NODE_ZSUPER, + NODE_LIST, + NODE_ZLIST, + NODE_HASH, + NODE_RETURN, + NODE_YIELD, + NODE_LVAR, + NODE_DVAR, + NODE_GVAR, + NODE_IVAR, + NODE_CONST, + NODE_CVAR, + NODE_NTH_REF, + NODE_BACK_REF, + NODE_MATCH, + NODE_MATCH2, + NODE_MATCH3, + NODE_INTEGER, + NODE_FLOAT, + NODE_RATIONAL, + NODE_IMAGINARY, + NODE_STR, + NODE_DSTR, + NODE_XSTR, + NODE_DXSTR, + NODE_EVSTR, + NODE_REGX, + NODE_DREGX, + NODE_ONCE, + NODE_ARGS, + NODE_ARGS_AUX, + NODE_OPT_ARG, + NODE_KW_ARG, + NODE_POSTARG, + NODE_ARGSCAT, + NODE_ARGSPUSH, + NODE_SPLAT, + NODE_BLOCK_PASS, + NODE_DEFN, + NODE_DEFS, + NODE_ALIAS, + NODE_VALIAS, + NODE_UNDEF, + NODE_CLASS, + NODE_MODULE, + NODE_SCLASS, + NODE_COLON2, + NODE_COLON3, + NODE_DOT2, + NODE_DOT3, + NODE_FLIP2, + NODE_FLIP3, + NODE_SELF, + NODE_NIL, + NODE_TRUE, + NODE_FALSE, + NODE_ERRINFO, + NODE_DEFINED, + NODE_POSTEXE, + NODE_SYM, + NODE_DSYM, + NODE_ATTRASGN, + NODE_LAMBDA, + NODE_ARYPTN, + NODE_HSHPTN, + NODE_FNDPTN, + NODE_ERROR, + NODE_LINE, + NODE_FILE, + NODE_ENCODING, + NODE_LAST +}; + +typedef struct rb_ast_id_table { + int size; + ID ids[FLEX_ARY_LEN]; +} rb_ast_id_table_t; + +typedef struct rb_code_position_struct { + int lineno; + int column; +} rb_code_position_t; + +typedef struct rb_code_location_struct { + rb_code_position_t beg_pos; + rb_code_position_t end_pos; +} rb_code_location_t; +#define YYLTYPE rb_code_location_t +#define YYLTYPE_IS_DECLARED 1 + +typedef struct rb_parser_ast_token { + int id; + const char *type_name; + rb_parser_string_t *str; + rb_code_location_t loc; +} rb_parser_ast_token_t; + +/* + * Array-like object for parser + */ +typedef void* rb_parser_ary_data; + +enum rb_parser_ary_data_type { + PARSER_ARY_DATA_AST_TOKEN = 1, + PARSER_ARY_DATA_SCRIPT_LINE, + PARSER_ARY_DATA_NODE +}; + +typedef struct rb_parser_ary { + enum rb_parser_ary_data_type data_type; + rb_parser_ary_data *data; + long len; // current size + long capa; // capacity +} rb_parser_ary_t; + +/* Header part of AST Node */ +typedef struct RNode { + VALUE flags; + rb_code_location_t nd_loc; + int node_id; +} NODE; + +typedef struct RNode_SCOPE { + NODE node; + + rb_ast_id_table_t *nd_tbl; + struct RNode *nd_body; + struct RNode *nd_parent; + struct RNode_ARGS *nd_args; +} rb_node_scope_t; + +typedef struct RNode_BLOCK { + NODE node; + + struct RNode *nd_head; + struct RNode *nd_end; + struct RNode *nd_next; +} rb_node_block_t; + +typedef struct RNode_IF { + NODE node; + + struct RNode *nd_cond; + struct RNode *nd_body; + struct RNode *nd_else; + rb_code_location_t if_keyword_loc; + rb_code_location_t then_keyword_loc; + rb_code_location_t end_keyword_loc; +} rb_node_if_t; + +typedef struct RNode_UNLESS { + NODE node; + + struct RNode *nd_cond; + struct RNode *nd_body; + struct RNode *nd_else; + rb_code_location_t keyword_loc; + rb_code_location_t then_keyword_loc; + rb_code_location_t end_keyword_loc; +} rb_node_unless_t; + +typedef struct RNode_CASE { + NODE node; + + struct RNode *nd_head; + struct RNode *nd_body; + rb_code_location_t case_keyword_loc; + rb_code_location_t end_keyword_loc; +} rb_node_case_t; + +typedef struct RNode_CASE2 { + NODE node; + + struct RNode *nd_head; + struct RNode *nd_body; + rb_code_location_t case_keyword_loc; + rb_code_location_t end_keyword_loc; +} rb_node_case2_t; + +typedef struct RNode_CASE3 { + NODE node; + + struct RNode *nd_head; + struct RNode *nd_body; + rb_code_location_t case_keyword_loc; + rb_code_location_t end_keyword_loc; +} rb_node_case3_t; + +typedef struct RNode_WHEN { + NODE node; + + struct RNode *nd_head; + struct RNode *nd_body; + struct RNode *nd_next; + rb_code_location_t keyword_loc; + rb_code_location_t then_keyword_loc; +} rb_node_when_t; + +typedef struct RNode_IN { + NODE node; + + struct RNode *nd_head; + struct RNode *nd_body; + struct RNode *nd_next; + rb_code_location_t in_keyword_loc; + rb_code_location_t then_keyword_loc; + rb_code_location_t operator_loc; +} rb_node_in_t; + +typedef struct RNode_LOOP { + NODE node; + + struct RNode *nd_cond; + struct RNode *nd_body; + long nd_state; + rb_code_location_t keyword_loc; + rb_code_location_t closing_loc; +} rb_node_while_t, rb_node_until_t; + +typedef struct RNode_ITER { + NODE node; + + struct RNode *nd_body; + struct RNode *nd_iter; +} rb_node_iter_t; + +typedef struct RNode_FOR { + NODE node; + + struct RNode *nd_body; + struct RNode *nd_iter; + rb_code_location_t for_keyword_loc; + rb_code_location_t in_keyword_loc; + rb_code_location_t do_keyword_loc; + rb_code_location_t end_keyword_loc; +} rb_node_for_t; + +typedef struct RNode_FOR_MASGN { + NODE node; + + struct RNode *nd_var; +} rb_node_for_masgn_t; + +typedef struct RNode_EXITS { + NODE node; + + struct RNode *nd_chain; + struct RNode *nd_stts; + rb_code_location_t keyword_loc; +} rb_node_exits_t, rb_node_break_t, rb_node_next_t, rb_node_redo_t; + +typedef struct RNode_RETRY { + NODE node; +} rb_node_retry_t; + +typedef struct RNode_BEGIN { + NODE node; + + struct RNode *nd_body; +} rb_node_begin_t; + +typedef struct RNode_RESCUE { + NODE node; + + struct RNode *nd_head; + struct RNode *nd_resq; + struct RNode *nd_else; +} rb_node_rescue_t; + +typedef struct RNode_RESBODY { + NODE node; + + struct RNode *nd_args; + struct RNode *nd_exc_var; + struct RNode *nd_body; + struct RNode *nd_next; +} rb_node_resbody_t; + +typedef struct RNode_ENSURE { + NODE node; + + struct RNode *nd_head; + struct RNode *nd_ensr; +} rb_node_ensure_t; + +typedef struct { + NODE node; + + struct RNode *nd_1st; + struct RNode *nd_2nd; + rb_code_location_t operator_loc; +} rb_node_and_t, rb_node_or_t; + +typedef struct RNode_MASGN { + NODE node; + + struct RNode *nd_head; + struct RNode *nd_value; + struct RNode *nd_args; +} rb_node_masgn_t; + +typedef struct RNode_LASGN { + NODE node; + + ID nd_vid; + struct RNode *nd_value; +} rb_node_lasgn_t; + +typedef struct RNode_DASGN { + NODE node; + + ID nd_vid; + struct RNode *nd_value; +} rb_node_dasgn_t; + +typedef struct RNode_GASGN { + NODE node; + + ID nd_vid; + struct RNode *nd_value; +} rb_node_gasgn_t; + +typedef struct RNode_IASGN { + NODE node; + + ID nd_vid; + struct RNode *nd_value; +} rb_node_iasgn_t; + +typedef struct RNode_CDECL { + NODE node; + + ID nd_vid; + struct RNode *nd_value; + struct RNode *nd_else; + enum rb_parser_shareability shareability; +} rb_node_cdecl_t; + +typedef struct RNode_CVASGN { + NODE node; + + ID nd_vid; + struct RNode *nd_value; +} rb_node_cvasgn_t; + +typedef struct RNode_OP_ASGN1 { + NODE node; + + struct RNode *nd_recv; + ID nd_mid; + struct RNode *nd_index; + struct RNode *nd_rvalue; + rb_code_location_t call_operator_loc; + rb_code_location_t opening_loc; + rb_code_location_t closing_loc; + rb_code_location_t binary_operator_loc; +} rb_node_op_asgn1_t; + +typedef struct RNode_OP_ASGN2 { + NODE node; + + struct RNode *nd_recv; + struct RNode *nd_value; + ID nd_vid; + ID nd_mid; + bool nd_aid; + rb_code_location_t call_operator_loc; + rb_code_location_t message_loc; + rb_code_location_t binary_operator_loc; +} rb_node_op_asgn2_t; + +typedef struct RNode_OP_ASGN_AND { + NODE node; + + struct RNode *nd_head; + struct RNode *nd_value; +} rb_node_op_asgn_and_t; + +typedef struct RNode_OP_ASGN_OR { + NODE node; + + struct RNode *nd_head; + struct RNode *nd_value; +} rb_node_op_asgn_or_t; + +typedef struct RNode_OP_CDECL { + NODE node; + + struct RNode *nd_head; + struct RNode *nd_value; + ID nd_aid; + enum rb_parser_shareability shareability; +} rb_node_op_cdecl_t; + +typedef struct RNode_CALL { + NODE node; + + struct RNode *nd_recv; + ID nd_mid; + struct RNode *nd_args; +} rb_node_call_t; + +typedef struct RNode_OPCALL { + NODE node; + + struct RNode *nd_recv; + ID nd_mid; + struct RNode *nd_args; +} rb_node_opcall_t; + +typedef struct RNode_FCALL { + NODE node; + + ID nd_mid; + struct RNode *nd_args; +} rb_node_fcall_t; + +typedef struct RNode_VCALL { + NODE node; + + ID nd_mid; +} rb_node_vcall_t; + +typedef struct RNode_QCALL { + NODE node; + + struct RNode *nd_recv; + ID nd_mid; + struct RNode *nd_args; +} rb_node_qcall_t; + +typedef struct RNode_SUPER { + NODE node; + + struct RNode *nd_args; + rb_code_location_t keyword_loc; + rb_code_location_t lparen_loc; + rb_code_location_t rparen_loc; +} rb_node_super_t; + +typedef struct RNode_ZSUPER { + NODE node; +} rb_node_zsuper_t; + +/* + + Structure of LIST: + + LIST +--> LIST + * head --> element | * head + * alen (length of list) | * nd_end (point to the last LIST) + * next -----------------+ * next + +*/ +typedef struct RNode_LIST { + NODE node; + + struct RNode *nd_head; /* element */ + union { + long nd_alen; + struct RNode *nd_end; /* Second list node has this structure */ + } as; + struct RNode *nd_next; /* next list node */ +} rb_node_list_t; + +typedef struct RNode_ZLIST { + NODE node; +} rb_node_zlist_t; + +typedef struct RNode_HASH { + NODE node; + + struct RNode *nd_head; + long nd_brace; +} rb_node_hash_t; + +typedef struct RNode_RETURN { + NODE node; + + struct RNode *nd_stts; + rb_code_location_t keyword_loc; +} rb_node_return_t; + +typedef struct RNode_YIELD { + NODE node; + + struct RNode *nd_head; + rb_code_location_t keyword_loc; + rb_code_location_t lparen_loc; + rb_code_location_t rparen_loc; +} rb_node_yield_t; + +typedef struct RNode_LVAR { + NODE node; + + ID nd_vid; +} rb_node_lvar_t; + +typedef struct RNode_DVAR { + NODE node; + + ID nd_vid; +} rb_node_dvar_t; + +typedef struct RNode_GVAR { + NODE node; + + ID nd_vid; +} rb_node_gvar_t; + +typedef struct RNode_IVAR { + NODE node; + + ID nd_vid; +} rb_node_ivar_t; + +typedef struct RNode_CONST { + NODE node; + + ID nd_vid; +} rb_node_const_t; + +typedef struct RNode_CVAR { + NODE node; + + ID nd_vid; +} rb_node_cvar_t; + +typedef struct RNode_NTH_REF { + NODE node; + + long nd_nth; +} rb_node_nth_ref_t; + +typedef struct RNode_BACK_REF { + NODE node; + + long nd_nth; +} rb_node_back_ref_t; + +typedef struct RNode_MATCH2 { + NODE node; + + struct RNode *nd_recv; + struct RNode *nd_value; + struct RNode *nd_args; +} rb_node_match2_t; + +typedef struct RNode_MATCH3 { + NODE node; + + struct RNode *nd_recv; + struct RNode *nd_value; +} rb_node_match3_t; + +typedef struct RNode_INTEGER { + NODE node; + + char *val; + int minus; + int base; +} rb_node_integer_t; + +typedef struct RNode_FLOAT { + NODE node; + + char *val; + int minus; +} rb_node_float_t; + +typedef struct RNode_RATIONAL { + NODE node; + + char *val; + int minus; + int base; + int seen_point; +} rb_node_rational_t; + +enum rb_numeric_type { + integer_literal, + float_literal, + rational_literal +}; + +typedef struct RNode_IMAGINARY { + NODE node; + + char *val; + int minus; + int base; + int seen_point; + enum rb_numeric_type type; +} rb_node_imaginary_t; + +typedef struct RNode_STR { + NODE node; + + struct rb_parser_string *string; +} rb_node_str_t; + +/* NODE_DSTR, NODE_DXSTR, NODE_DREGX, NODE_DSYM */ +typedef struct RNode_DSTR { + NODE node; + + struct rb_parser_string *string; + union { + long nd_alen; + long nd_cflag; + struct RNode *nd_end; /* Second dstr node has this structure. See also RNode_LIST */ + } as; + struct RNode_LIST *nd_next; +} rb_node_dstr_t; + +typedef rb_node_str_t rb_node_xstr_t; + +typedef rb_node_dstr_t rb_node_dxstr_t; + +typedef struct RNode_EVSTR { + NODE node; + + struct RNode *nd_body; + rb_code_location_t opening_loc; + rb_code_location_t closing_loc; +} rb_node_evstr_t; + +typedef struct RNode_REGX { /* also RNode_MATCH */ + NODE node; + + struct rb_parser_string *string; + int options; + rb_code_location_t opening_loc; + rb_code_location_t content_loc; + rb_code_location_t closing_loc; +} rb_node_regx_t, rb_node_match_t; + +typedef rb_node_dstr_t rb_node_dregx_t; + +typedef struct RNode_ONCE { + NODE node; + + struct RNode *nd_body; +} rb_node_once_t; + +struct rb_args_info { + NODE *pre_init; + NODE *post_init; + + int pre_args_num; /* count of mandatory pre-arguments */ + int post_args_num; /* count of mandatory post-arguments */ + + ID first_post_arg; + + ID rest_arg; + ID block_arg; + + struct RNode_KW_ARG *kw_args; + NODE *kw_rest_arg; + + struct RNode_OPT_ARG *opt_args; + unsigned int no_kwarg: 1; + unsigned int ruby2_keywords: 1; + unsigned int forwarding: 1; +}; + +typedef struct RNode_ARGS { + NODE node; + + struct rb_args_info nd_ainfo; +} rb_node_args_t; + +typedef struct RNode_ARGS_AUX { + NODE node; + + ID nd_pid; + int nd_plen; + struct RNode *nd_next; +} rb_node_args_aux_t; + +typedef struct RNode_OPT_ARG { + NODE node; + + struct RNode *nd_body; + struct RNode_OPT_ARG *nd_next; +} rb_node_opt_arg_t; + +typedef struct RNode_KW_ARG { + NODE node; + + struct RNode *nd_body; + struct RNode_KW_ARG *nd_next; +} rb_node_kw_arg_t; + +typedef struct RNode_POSTARG { + NODE node; + + struct RNode *nd_1st; + struct RNode *nd_2nd; +} rb_node_postarg_t; + +typedef struct RNode_ARGSCAT { + NODE node; + + struct RNode *nd_head; + struct RNode *nd_body; +} rb_node_argscat_t; + +typedef struct RNode_ARGSPUSH { + NODE node; + + struct RNode *nd_head; + struct RNode *nd_body; +} rb_node_argspush_t; + +typedef struct RNode_SPLAT { + NODE node; + + struct RNode *nd_head; + rb_code_location_t operator_loc; +} rb_node_splat_t; + +typedef struct RNode_BLOCK_PASS { + NODE node; + + struct RNode *nd_head; + struct RNode *nd_body; + unsigned int forwarding: 1; + rb_code_location_t operator_loc; +} rb_node_block_pass_t; + +typedef struct RNode_DEFN { + NODE node; + + ID nd_mid; + struct RNode *nd_defn; +} rb_node_defn_t; + +typedef struct RNode_DEFS { + NODE node; + + struct RNode *nd_recv; + ID nd_mid; + struct RNode *nd_defn; +} rb_node_defs_t; + +typedef struct RNode_ALIAS { + NODE node; + + struct RNode *nd_1st; + struct RNode *nd_2nd; + rb_code_location_t keyword_loc; +} rb_node_alias_t; + +typedef struct RNode_VALIAS { + NODE node; + + ID nd_alias; + ID nd_orig; + rb_code_location_t keyword_loc; +} rb_node_valias_t; + +typedef struct RNode_UNDEF { + NODE node; + + rb_parser_ary_t *nd_undefs; + rb_code_location_t keyword_loc; +} rb_node_undef_t; + +typedef struct RNode_CLASS { + NODE node; + + struct RNode *nd_cpath; + struct RNode *nd_body; + struct RNode *nd_super; + rb_code_location_t class_keyword_loc; + rb_code_location_t inheritance_operator_loc; + rb_code_location_t end_keyword_loc; +} rb_node_class_t; + +typedef struct RNode_MODULE { + NODE node; + + struct RNode *nd_cpath; + struct RNode *nd_body; + rb_code_location_t module_keyword_loc; + rb_code_location_t end_keyword_loc; +} rb_node_module_t; + +typedef struct RNode_SCLASS { + NODE node; + + struct RNode *nd_recv; + struct RNode *nd_body; + rb_code_location_t class_keyword_loc; + rb_code_location_t operator_loc; + rb_code_location_t end_keyword_loc; +} rb_node_sclass_t; + +typedef struct RNode_COLON2 { + NODE node; + + struct RNode *nd_head; + ID nd_mid; + rb_code_location_t delimiter_loc; + rb_code_location_t name_loc; +} rb_node_colon2_t; + +typedef struct RNode_COLON3 { + NODE node; + + ID nd_mid; + rb_code_location_t delimiter_loc; + rb_code_location_t name_loc; +} rb_node_colon3_t; + +/* NODE_DOT2, NODE_DOT3, NODE_FLIP2, NODE_FLIP3 */ +typedef struct RNode_DOTS { + NODE node; + + struct RNode *nd_beg; + struct RNode *nd_end; + rb_code_location_t operator_loc; +} rb_node_dot2_t, rb_node_dot3_t, rb_node_flip2_t, rb_node_flip3_t; + +typedef struct RNode_SELF { + NODE node; + + long nd_state; /* Default 1. See NEW_SELF. */ +} rb_node_self_t; + +typedef struct RNode_NIL { + NODE node; +} rb_node_nil_t; + +typedef struct RNode_TRUE { + NODE node; +} rb_node_true_t; + +typedef struct RNode_FALSE { + NODE node; +} rb_node_false_t; + +typedef struct RNode_ERRINFO { + NODE node; +} rb_node_errinfo_t; + +typedef struct RNode_DEFINED { + NODE node; + + struct RNode *nd_head; + rb_code_location_t keyword_loc; +} rb_node_defined_t; + +typedef struct RNode_POSTEXE { + NODE node; + + struct RNode *nd_body; + rb_code_location_t keyword_loc; + rb_code_location_t opening_loc; + rb_code_location_t closing_loc; +} rb_node_postexe_t; + +typedef struct RNode_SYM { + NODE node; + + struct rb_parser_string *string; +} rb_node_sym_t; + +typedef rb_node_dstr_t rb_node_dsym_t; + +typedef struct RNode_ATTRASGN { + NODE node; + + struct RNode *nd_recv; + ID nd_mid; + struct RNode *nd_args; +} rb_node_attrasgn_t; + +typedef struct RNode_LAMBDA { + NODE node; + + struct RNode *nd_body; + rb_code_location_t operator_loc; + rb_code_location_t opening_loc; + rb_code_location_t closing_loc; +} rb_node_lambda_t; + +typedef struct RNode_ARYPTN { + NODE node; + + struct RNode *nd_pconst; + NODE *pre_args; + NODE *rest_arg; + NODE *post_args; +} rb_node_aryptn_t; + +typedef struct RNode_HSHPTN { + NODE node; + + struct RNode *nd_pconst; + struct RNode *nd_pkwargs; + struct RNode *nd_pkwrestarg; +} rb_node_hshptn_t; + +typedef struct RNode_FNDPTN { + NODE node; + + struct RNode *nd_pconst; + NODE *pre_rest_arg; + NODE *args; + NODE *post_rest_arg; +} rb_node_fndptn_t; + +typedef struct RNode_LINE { + NODE node; +} rb_node_line_t; + +typedef struct RNode_FILE { + NODE node; + + struct rb_parser_string *path; +} rb_node_file_t; + +typedef struct RNode_ENCODING { + NODE node; + rb_encoding *enc; +} rb_node_encoding_t; + +typedef struct RNode_ERROR { + NODE node; +} rb_node_error_t; + +#define RNODE(obj) ((NODE *)(obj)) + +#define RNODE_SCOPE(node) ((rb_node_scope_t *)(node)) +#define RNODE_BLOCK(node) ((rb_node_block_t *)(node)) +#define RNODE_IF(node) ((rb_node_if_t *)(node)) +#define RNODE_UNLESS(node) ((rb_node_unless_t *)(node)) +#define RNODE_CASE(node) ((rb_node_case_t *)(node)) +#define RNODE_CASE2(node) ((rb_node_case2_t *)(node)) +#define RNODE_CASE3(node) ((rb_node_case3_t *)(node)) +#define RNODE_WHEN(node) ((rb_node_when_t *)(node)) +#define RNODE_IN(node) ((rb_node_in_t *)(node)) +#define RNODE_WHILE(node) ((rb_node_while_t *)(node)) +#define RNODE_UNTIL(node) ((rb_node_until_t *)(node)) +#define RNODE_ITER(node) ((rb_node_iter_t *)(node)) +#define RNODE_FOR(node) ((rb_node_for_t *)(node)) +#define RNODE_FOR_MASGN(node) ((rb_node_for_masgn_t *)(node)) +#define RNODE_BREAK(node) ((rb_node_break_t *)(node)) +#define RNODE_NEXT(node) ((rb_node_next_t *)(node)) +#define RNODE_REDO(node) ((rb_node_redo_t *)(node)) +#define RNODE_RETRY(node) ((rb_node_retry_t *)(node)) +#define RNODE_BEGIN(node) ((rb_node_begin_t *)(node)) +#define RNODE_RESCUE(node) ((rb_node_rescue_t *)(node)) +#define RNODE_RESBODY(node) ((rb_node_resbody_t *)(node)) +#define RNODE_ENSURE(node) ((rb_node_ensure_t *)(node)) +#define RNODE_AND(node) ((rb_node_and_t *)(node)) +#define RNODE_OR(node) ((rb_node_or_t *)(node)) +#define RNODE_MASGN(node) ((rb_node_masgn_t *)(node)) +#define RNODE_LASGN(node) ((rb_node_lasgn_t *)(node)) +#define RNODE_DASGN(node) ((rb_node_dasgn_t *)(node)) +#define RNODE_GASGN(node) ((rb_node_gasgn_t *)(node)) +#define RNODE_IASGN(node) ((rb_node_iasgn_t *)(node)) +#define RNODE_CDECL(node) ((rb_node_cdecl_t *)(node)) +#define RNODE_CVASGN(node) ((rb_node_cvasgn_t *)(node)) +#define RNODE_OP_ASGN1(node) ((rb_node_op_asgn1_t *)(node)) +#define RNODE_OP_ASGN2(node) ((rb_node_op_asgn2_t *)(node)) +#define RNODE_OP_ASGN_AND(node) ((rb_node_op_asgn_and_t *)(node)) +#define RNODE_OP_ASGN_OR(node) ((rb_node_op_asgn_or_t *)(node)) +#define RNODE_OP_CDECL(node) ((rb_node_op_cdecl_t *)(node)) +#define RNODE_CALL(node) ((rb_node_call_t *)(node)) +#define RNODE_OPCALL(node) ((rb_node_opcall_t *)(node)) +#define RNODE_FCALL(node) ((rb_node_fcall_t *)(node)) +#define RNODE_VCALL(node) ((rb_node_vcall_t *)(node)) +#define RNODE_QCALL(node) ((rb_node_qcall_t *)(node)) +#define RNODE_SUPER(node) ((rb_node_super_t *)(node)) +#define RNODE_ZSUPER(node) ((rb_node_zsuper_t *)(node)) +#define RNODE_LIST(node) ((rb_node_list_t *)(node)) +#define RNODE_ZLIST(node) ((rb_node_zlist_t *)(node)) +#define RNODE_HASH(node) ((rb_node_hash_t *)(node)) +#define RNODE_RETURN(node) ((rb_node_return_t *)(node)) +#define RNODE_YIELD(node) ((rb_node_yield_t *)(node)) +#define RNODE_LVAR(node) ((rb_node_lvar_t *)(node)) +#define RNODE_DVAR(node) ((rb_node_dvar_t *)(node)) +#define RNODE_GVAR(node) ((rb_node_gvar_t *)(node)) +#define RNODE_IVAR(node) ((rb_node_ivar_t *)(node)) +#define RNODE_CONST(node) ((rb_node_const_t *)(node)) +#define RNODE_CVAR(node) ((rb_node_cvar_t *)(node)) +#define RNODE_NTH_REF(node) ((rb_node_nth_ref_t *)(node)) +#define RNODE_BACK_REF(node) ((rb_node_back_ref_t *)(node)) +#define RNODE_MATCH(node) ((rb_node_match_t *)(node)) +#define RNODE_MATCH2(node) ((rb_node_match2_t *)(node)) +#define RNODE_MATCH3(node) ((rb_node_match3_t *)(node)) +#define RNODE_INTEGER(node) ((rb_node_integer_t *)(node)) +#define RNODE_FLOAT(node) ((rb_node_float_t *)(node)) +#define RNODE_RATIONAL(node) ((rb_node_rational_t *)(node)) +#define RNODE_IMAGINARY(node) ((rb_node_imaginary_t *)(node)) +#define RNODE_STR(node) ((rb_node_str_t *)(node)) +#define RNODE_DSTR(node) ((rb_node_dstr_t *)(node)) +#define RNODE_XSTR(node) ((rb_node_xstr_t *)(node)) +#define RNODE_DXSTR(node) ((rb_node_dxstr_t *)(node)) +#define RNODE_EVSTR(node) ((rb_node_evstr_t *)(node)) +#define RNODE_REGX(node) ((rb_node_regx_t *)(node)) +#define RNODE_DREGX(node) ((rb_node_dregx_t *)(node)) +#define RNODE_ONCE(node) ((rb_node_once_t *)(node)) +#define RNODE_ARGS(node) ((rb_node_args_t *)(node)) +#define RNODE_ARGS_AUX(node) ((rb_node_args_aux_t *)(node)) +#define RNODE_OPT_ARG(node) ((rb_node_opt_arg_t *)(node)) +#define RNODE_KW_ARG(node) ((rb_node_kw_arg_t *)(node)) +#define RNODE_POSTARG(node) ((rb_node_postarg_t *)(node)) +#define RNODE_ARGSCAT(node) ((rb_node_argscat_t *)(node)) +#define RNODE_ARGSPUSH(node) ((rb_node_argspush_t *)(node)) +#define RNODE_SPLAT(node) ((rb_node_splat_t *)(node)) +#define RNODE_BLOCK_PASS(node) ((rb_node_block_pass_t *)(node)) +#define RNODE_DEFN(node) ((rb_node_defn_t *)(node)) +#define RNODE_DEFS(node) ((rb_node_defs_t *)(node)) +#define RNODE_ALIAS(node) ((rb_node_alias_t *)(node)) +#define RNODE_VALIAS(node) ((rb_node_valias_t *)(node)) +#define RNODE_UNDEF(node) ((rb_node_undef_t *)(node)) +#define RNODE_CLASS(node) ((rb_node_class_t *)(node)) +#define RNODE_MODULE(node) ((rb_node_module_t *)(node)) +#define RNODE_SCLASS(node) ((rb_node_sclass_t *)(node)) +#define RNODE_COLON2(node) ((rb_node_colon2_t *)(node)) +#define RNODE_COLON3(node) ((rb_node_colon3_t *)(node)) +#define RNODE_DOT2(node) ((rb_node_dot2_t *)(node)) +#define RNODE_DOT3(node) ((rb_node_dot3_t *)(node)) +#define RNODE_FLIP2(node) ((rb_node_flip2_t *)(node)) +#define RNODE_FLIP3(node) ((rb_node_flip3_t *)(node)) +#define RNODE_SELF(node) ((rb_node_self_t *)(node)) +#define RNODE_NIL(node) ((rb_node_nil_t *)(node)) +#define RNODE_TRUE(node) ((rb_node_true_t *)(node)) +#define RNODE_FALSE(node) ((rb_node_false_t *)(node)) +#define RNODE_ERRINFO(node) ((rb_node_errinfo_t *)(node)) +#define RNODE_DEFINED(node) ((rb_node_defined_t *)(node)) +#define RNODE_POSTEXE(node) ((rb_node_postexe_t *)(node)) +#define RNODE_SYM(node) ((rb_node_sym_t *)(node)) +#define RNODE_DSYM(node) ((rb_node_dsym_t *)(node)) +#define RNODE_ATTRASGN(node) ((rb_node_attrasgn_t *)(node)) +#define RNODE_LAMBDA(node) ((rb_node_lambda_t *)(node)) +#define RNODE_ARYPTN(node) ((rb_node_aryptn_t *)(node)) +#define RNODE_HSHPTN(node) ((rb_node_hshptn_t *)(node)) +#define RNODE_FNDPTN(node) ((rb_node_fndptn_t *)(node)) +#define RNODE_LINE(node) ((rb_node_line_t *)(node)) +#define RNODE_FILE(node) ((rb_node_file_t *)(node)) +#define RNODE_ENCODING(node) ((rb_node_encoding_t *)(node)) + +/* FL : 0..4: T_TYPES, 5: KEEP_WB, 6: PROMOTED, 7: FINALIZE, 8..10: UNUSED, 11: FREEZE */ +/* NODE_FL: 0..4: UNUSED, 5: UNUSED, 6: UNUSED, 7: NODE_FL_NEWLINE, + * 8..14: nd_type, + * 15..: nd_line + */ +#define NODE_FL_NEWLINE (((VALUE)1)<<7) + +#define NODE_TYPESHIFT 8 +#define NODE_TYPEMASK (((VALUE)0x7f)<flags & NODE_FL_NEWLINE) +#define nd_set_fl_newline(n) ((n)->flags |= NODE_FL_NEWLINE) +#define nd_unset_fl_newline(n) ((n)->flags &= ~NODE_FL_NEWLINE) + +#define nd_type(n) ((int) ((RNODE(n)->flags & NODE_TYPEMASK)>>NODE_TYPESHIFT)) +#define nd_set_type(n,t) \ + rb_node_set_type(n, t) +#define nd_init_type(n,t) \ + (n)->flags=(((n)->flags&~NODE_TYPEMASK)|((((unsigned long)(t))<> SHAPE_ID_NUM_BITS) + +#define SHAPE_MAX_VARIATIONS 8 + +#define INVALID_SHAPE_ID ((shape_id_t)-1) +#define ATTR_INDEX_NOT_SET ((attr_index_t)-1) + +#define ROOT_SHAPE_ID 0x0 +#define ROOT_SHAPE_WITH_OBJ_ID 0x1 +#define ROOT_TOO_COMPLEX_SHAPE_ID (ROOT_SHAPE_ID | SHAPE_ID_FL_TOO_COMPLEX) +#define ROOT_TOO_COMPLEX_WITH_OBJ_ID (ROOT_SHAPE_WITH_OBJ_ID | SHAPE_ID_FL_TOO_COMPLEX | SHAPE_ID_FL_HAS_OBJECT_ID) + +typedef struct redblack_node redblack_node_t; + +struct rb_shape { + VALUE edges; // id_table from ID (ivar) to next shape + ID edge_name; // ID (ivar) for transition from parent to rb_shape + redblack_node_t *ancestor_index; + shape_id_t parent_id; + attr_index_t next_field_index; // Fields are either ivars or internal properties like `object_id` + attr_index_t capacity; // Total capacity of the object with this shape + uint8_t type; +}; + +typedef struct rb_shape rb_shape_t; + +struct redblack_node { + ID key; + rb_shape_t *value; + redblack_id_t l; + redblack_id_t r; +}; + +enum shape_type { + SHAPE_ROOT, + SHAPE_IVAR, + SHAPE_OBJ_ID, +}; + +enum shape_flags { + SHAPE_FL_FROZEN = 1 << 0, + SHAPE_FL_HAS_OBJECT_ID = 1 << 1, + SHAPE_FL_TOO_COMPLEX = 1 << 2, + + SHAPE_FL_NON_CANONICAL_MASK = SHAPE_FL_FROZEN | SHAPE_FL_HAS_OBJECT_ID, +}; + +typedef struct { + /* object shapes */ + rb_shape_t *shape_list; + rb_shape_t *root_shape; + const attr_index_t *capacities; + rb_atomic_t next_shape_id; + + redblack_node_t *shape_cache; + unsigned int cache_size; +} rb_shape_tree_t; + +RUBY_SYMBOL_EXPORT_BEGIN +RUBY_EXTERN rb_shape_tree_t rb_shape_tree; +RUBY_SYMBOL_EXPORT_END + +static inline shape_id_t +rb_shapes_count(void) +{ + return (shape_id_t)RUBY_ATOMIC_LOAD(rb_shape_tree.next_shape_id); +} + +union rb_attr_index_cache { + uint64_t pack; + struct { + shape_id_t shape_id; + attr_index_t index; + } unpack; +}; + +static inline shape_id_t +RBASIC_SHAPE_ID(VALUE obj) +{ + RUBY_ASSERT(!RB_SPECIAL_CONST_P(obj)); + RUBY_ASSERT(!RB_TYPE_P(obj, T_IMEMO) || IMEMO_TYPE_P(obj, imemo_fields)); +#if RBASIC_SHAPE_ID_FIELD + return (shape_id_t)((RBASIC(obj)->shape_id)); +#else + return (shape_id_t)((RBASIC(obj)->flags) >> SHAPE_FLAG_SHIFT); +#endif +} + +// Same as RBASIC_SHAPE_ID but with flags that have no impact +// on reads removed. e.g. Remove FL_FROZEN. +static inline shape_id_t +RBASIC_SHAPE_ID_FOR_READ(VALUE obj) +{ + return RBASIC_SHAPE_ID(obj) & SHAPE_ID_READ_ONLY_MASK; +} + +#if RUBY_DEBUG +bool rb_shape_verify_consistency(VALUE obj, shape_id_t shape_id); +#endif + +static inline void +RBASIC_SET_SHAPE_ID(VALUE obj, shape_id_t shape_id) +{ + RUBY_ASSERT(!RB_SPECIAL_CONST_P(obj)); + RUBY_ASSERT(!RB_TYPE_P(obj, T_IMEMO) || IMEMO_TYPE_P(obj, imemo_fields)); +#if RBASIC_SHAPE_ID_FIELD + RBASIC(obj)->shape_id = (VALUE)shape_id; +#else + // Object shapes are occupying top bits + RBASIC(obj)->flags &= SHAPE_FLAG_MASK; + RBASIC(obj)->flags |= ((VALUE)(shape_id) << SHAPE_FLAG_SHIFT); +#endif + RUBY_ASSERT(rb_shape_verify_consistency(obj, shape_id)); +} + +void rb_set_boxed_class_shape_id(VALUE obj, shape_id_t shape_id); + +static inline void +RB_SET_SHAPE_ID(VALUE obj, shape_id_t shape_id) +{ + switch (BUILTIN_TYPE(obj)) { + case T_CLASS: + case T_MODULE: + rb_set_boxed_class_shape_id(obj, shape_id); + break; + default: + RBASIC_SET_SHAPE_ID(obj, shape_id); + break; + } +} + +static inline rb_shape_t * +RSHAPE(shape_id_t shape_id) +{ + uint32_t offset = (shape_id & SHAPE_ID_OFFSET_MASK); + RUBY_ASSERT(offset != INVALID_SHAPE_ID); + + return &rb_shape_tree.shape_list[offset]; +} + +int32_t rb_shape_id_offset(void); + +RUBY_FUNC_EXPORTED shape_id_t rb_obj_shape_id(VALUE obj); +shape_id_t rb_shape_get_next_iv_shape(shape_id_t shape_id, ID id); +bool rb_shape_get_iv_index(shape_id_t shape_id, ID id, attr_index_t *value); +bool rb_shape_get_iv_index_with_hint(shape_id_t shape_id, ID id, attr_index_t *value, shape_id_t *shape_id_hint); +bool rb_shape_find_ivar(shape_id_t shape_id, ID id, shape_id_t *ivar_shape); + +typedef int rb_shape_foreach_transition_callback(shape_id_t shape_id, void *data); +bool rb_shape_foreach_field(shape_id_t shape_id, rb_shape_foreach_transition_callback func, void *data); + +shape_id_t rb_shape_transition_frozen(VALUE obj); +shape_id_t rb_shape_transition_complex(VALUE obj); +shape_id_t rb_shape_transition_remove_ivar(VALUE obj, ID id, shape_id_t *removed_shape_id); +shape_id_t rb_shape_transition_add_ivar(VALUE obj, ID id); +shape_id_t rb_shape_transition_add_ivar_no_warnings(VALUE obj, ID id); +shape_id_t rb_shape_transition_object_id(VALUE obj); +shape_id_t rb_shape_transition_heap(VALUE obj, size_t heap_index); +shape_id_t rb_shape_object_id(shape_id_t original_shape_id); + +void rb_shape_free_all(void); + +shape_id_t rb_shape_rebuild(shape_id_t initial_shape_id, shape_id_t dest_shape_id); +void rb_shape_copy_fields(VALUE dest, VALUE *dest_buf, shape_id_t dest_shape_id, VALUE *src_buf, shape_id_t src_shape_id); +void rb_shape_copy_complex_ivars(VALUE dest, VALUE obj, shape_id_t src_shape_id, st_table *fields_table); + +static inline bool +rb_shape_too_complex_p(shape_id_t shape_id) +{ + return shape_id & SHAPE_ID_FL_TOO_COMPLEX; +} + +static inline bool +rb_shape_obj_too_complex_p(VALUE obj) +{ + return !RB_SPECIAL_CONST_P(obj) && rb_shape_too_complex_p(RBASIC_SHAPE_ID(obj)); +} + +static inline bool +rb_shape_has_object_id(shape_id_t shape_id) +{ + return shape_id & SHAPE_ID_FL_HAS_OBJECT_ID; +} + +static inline bool +rb_shape_canonical_p(shape_id_t shape_id) +{ + return !(shape_id & SHAPE_ID_FL_NON_CANONICAL_MASK); +} + +static inline uint8_t +rb_shape_heap_index(shape_id_t shape_id) +{ + return (uint8_t)((shape_id & SHAPE_ID_HEAP_INDEX_MASK) >> SHAPE_ID_HEAP_INDEX_OFFSET); +} + +static inline shape_id_t +rb_shape_root(size_t heap_id) +{ + shape_id_t heap_index = (shape_id_t)(heap_id + 1); + shape_id_t heap_flags = heap_index << SHAPE_ID_HEAP_INDEX_OFFSET; + + RUBY_ASSERT((heap_flags & SHAPE_ID_HEAP_INDEX_MASK) == heap_flags); + RUBY_ASSERT(rb_shape_heap_index(heap_flags) == heap_index); + + return ROOT_SHAPE_ID | heap_flags; +} + +static inline shape_id_t +RSHAPE_PARENT_RAW_ID(shape_id_t shape_id) +{ + return RSHAPE(shape_id)->parent_id; +} + +static inline bool +RSHAPE_DIRECT_CHILD_P(shape_id_t parent_id, shape_id_t child_id) +{ + return (parent_id & SHAPE_ID_FLAGS_MASK) == (child_id & SHAPE_ID_FLAGS_MASK) && + RSHAPE(child_id)->parent_id == (parent_id & SHAPE_ID_OFFSET_MASK); +} + +static inline enum shape_type +RSHAPE_TYPE(shape_id_t shape_id) +{ + return RSHAPE(shape_id)->type; +} + +static inline bool +RSHAPE_TYPE_P(shape_id_t shape_id, enum shape_type type) +{ + return RSHAPE_TYPE(shape_id) == type; +} + +static inline attr_index_t +RSHAPE_EMBEDDED_CAPACITY(shape_id_t shape_id) +{ + uint8_t heap_index = rb_shape_heap_index(shape_id); + if (heap_index) { + return rb_shape_tree.capacities[heap_index - 1]; + } + return 0; +} + +static inline attr_index_t +RSHAPE_CAPACITY(shape_id_t shape_id) +{ + attr_index_t embedded_capacity = RSHAPE_EMBEDDED_CAPACITY(shape_id); + + if (embedded_capacity > RSHAPE(shape_id)->capacity) { + return embedded_capacity; + } + else { + return RSHAPE(shape_id)->capacity; + } +} + +static inline attr_index_t +RSHAPE_LEN(shape_id_t shape_id) +{ + return RSHAPE(shape_id)->next_field_index; +} + +static inline attr_index_t +RSHAPE_INDEX(shape_id_t shape_id) +{ + RUBY_ASSERT(RSHAPE_LEN(shape_id) > 0); + return RSHAPE_LEN(shape_id) - 1; +} + +static inline ID +RSHAPE_EDGE_NAME(shape_id_t shape_id) +{ + return RSHAPE(shape_id)->edge_name; +} + +static inline uint32_t +ROBJECT_FIELDS_CAPACITY(VALUE obj) +{ + RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT); + // Asking for capacity doesn't make sense when the object is using + // a hash table for storing instance variables + RUBY_ASSERT(!rb_shape_obj_too_complex_p(obj)); + return RSHAPE_CAPACITY(RBASIC_SHAPE_ID(obj)); +} + +static inline st_table * +ROBJECT_FIELDS_HASH(VALUE obj) +{ + RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT); + RUBY_ASSERT(rb_shape_obj_too_complex_p(obj)); + RUBY_ASSERT(FL_TEST_RAW(obj, ROBJECT_HEAP)); + + return (st_table *)ROBJECT(obj)->as.heap.fields; +} + +static inline void +ROBJECT_SET_FIELDS_HASH(VALUE obj, const st_table *tbl) +{ + RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT); + RUBY_ASSERT(rb_shape_obj_too_complex_p(obj)); + RUBY_ASSERT(FL_TEST_RAW(obj, ROBJECT_HEAP)); + + ROBJECT(obj)->as.heap.fields = (VALUE *)tbl; +} + +static inline uint32_t +ROBJECT_FIELDS_COUNT(VALUE obj) +{ + if (rb_shape_obj_too_complex_p(obj)) { + return (uint32_t)rb_st_table_size(ROBJECT_FIELDS_HASH(obj)); + } + else { + RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT); + RUBY_ASSERT(!rb_shape_obj_too_complex_p(obj)); + return RSHAPE(RBASIC_SHAPE_ID(obj))->next_field_index; + } +} + +static inline uint32_t +RBASIC_FIELDS_COUNT(VALUE obj) +{ + return RSHAPE(rb_obj_shape_id(obj))->next_field_index; +} + +static inline bool +rb_shape_obj_has_id(VALUE obj) +{ + return rb_shape_has_object_id(RBASIC_SHAPE_ID(obj)); +} + +static inline bool +rb_shape_has_ivars(shape_id_t shape_id) +{ + return shape_id & SHAPE_ID_HAS_IVAR_MASK; +} + +static inline bool +rb_shape_obj_has_ivars(VALUE obj) +{ + return rb_shape_has_ivars(RBASIC_SHAPE_ID(obj)); +} + +static inline bool +rb_shape_has_fields(shape_id_t shape_id) +{ + return shape_id & (SHAPE_ID_OFFSET_MASK | SHAPE_ID_FL_TOO_COMPLEX); +} + +static inline bool +rb_shape_obj_has_fields(VALUE obj) +{ + return rb_shape_has_fields(RBASIC_SHAPE_ID(obj)); +} + +static inline bool +rb_obj_exivar_p(VALUE obj) +{ + switch (TYPE(obj)) { + case T_NONE: + case T_OBJECT: + case T_CLASS: + case T_MODULE: + case T_IMEMO: + return false; + default: + break; + } + return rb_shape_obj_has_fields(obj); +} + +// For ext/objspace +RUBY_SYMBOL_EXPORT_BEGIN +typedef void each_shape_callback(shape_id_t shape_id, void *data); +void rb_shape_each_shape_id(each_shape_callback callback, void *data); +size_t rb_shape_memsize(shape_id_t shape); +size_t rb_shape_edges_count(shape_id_t shape_id); +size_t rb_shape_depth(shape_id_t shape_id); +RUBY_SYMBOL_EXPORT_END + +#endif diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/thread_none.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/thread_none.h new file mode 100644 index 0000000..ac47e52 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/thread_none.h @@ -0,0 +1,21 @@ +#ifndef RUBY_THREAD_NONE_H +#define RUBY_THREAD_NONE_H + +#define RB_NATIVETHREAD_LOCK_INIT (void)(0) +#define RB_NATIVETHREAD_COND_INIT (void)(0) + +// no-thread impl doesn't use TLS but define this to avoid using tls key +// based implementation in vm.c +#define RB_THREAD_LOCAL_SPECIFIER + +struct rb_native_thread { + void *thread_id; // NULL +}; + +struct rb_thread_sched_item {}; +struct rb_thread_sched {}; + +RUBY_EXTERN struct rb_execution_context_struct *ruby_current_ec; +NOINLINE(struct rb_execution_context_struct *rb_current_ec_noinline(void)); // for assertions + +#endif /* RUBY_THREAD_NONE_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/thread_pthread.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/thread_pthread.h new file mode 100644 index 0000000..d635948 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/thread_pthread.h @@ -0,0 +1,175 @@ +#ifndef RUBY_THREAD_PTHREAD_H +#define RUBY_THREAD_PTHREAD_H +/********************************************************************** + + thread_pthread.h - + + $Author$ + + Copyright (C) 2004-2007 Koichi Sasada + +**********************************************************************/ + +#ifdef HAVE_PTHREAD_NP_H +#include +#endif + +#define RB_NATIVETHREAD_LOCK_INIT PTHREAD_MUTEX_INITIALIZER +#define RB_NATIVETHREAD_COND_INIT PTHREAD_COND_INITIALIZER + +// TLS can not be accessed across .so on arm64 and perhaps ppc64le too. +#if defined(__arm64__) || defined(__aarch64__) || defined(__powerpc64__) +# define RB_THREAD_CURRENT_EC_NOINLINE +#endif + +// this data should be protected by timer_th.waiting_lock +struct rb_thread_sched_waiting { + enum thread_sched_waiting_flag { + thread_sched_waiting_none = 0x00, + thread_sched_waiting_timeout = 0x01, + thread_sched_waiting_io_read = 0x02, + thread_sched_waiting_io_write = 0x08, + thread_sched_waiting_io_force = 0x40, // ignore readable + } flags; + + struct { + // should be compat with hrtime.h +#ifdef MY_RUBY_BUILD_MAY_TIME_TRAVEL + int128_t timeout; +#else + uint64_t timeout; +#endif + int fd; // -1 for timeout only + int result; + } data; + + // connected to timer_th.waiting + struct ccan_list_node node; +}; + +// per-Thead scheduler helper data +struct rb_thread_sched_item { + struct { + struct ccan_list_node ubf; + + // connected to ractor->threads.sched.reqdyq + // locked by ractor->threads.sched.lock + struct ccan_list_node readyq; + + // connected to vm->ractor.sched.timeslice_threads + // locked by vm->ractor.sched.lock + struct ccan_list_node timeslice_threads; + + // connected to vm->ractor.sched.running_threads + // locked by vm->ractor.sched.lock + struct ccan_list_node running_threads; + + // connected to vm->ractor.sched.zombie_threads + struct ccan_list_node zombie_threads; + } node; + + struct rb_thread_sched_waiting waiting_reason; + + bool finished; + bool malloc_stack; + void *context_stack; + struct coroutine_context *context; +}; + +struct rb_native_thread { + rb_atomic_t serial; + struct rb_vm_struct *vm; + + rb_nativethread_id_t thread_id; + +#ifdef RB_THREAD_T_HAS_NATIVE_ID + int tid; +#endif + + struct rb_thread_struct *running_thread; + + // to control native thread +#if defined(__GLIBC__) || defined(__FreeBSD__) + union +#else + /* + * assume the platform condvars are badly implemented and have a + * "memory" of which mutex they're associated with + */ + struct +#endif + { + rb_nativethread_cond_t intr; /* th->interrupt_lock */ + rb_nativethread_cond_t readyq; /* use sched->lock */ + } cond; + +#ifdef USE_SIGALTSTACK + void *altstack; +#endif + + struct coroutine_context *nt_context; + int dedicated; + + size_t machine_stack_maxsize; +}; + +#undef except +#undef try +#undef leave +#undef finally + +// per-Ractor +struct rb_thread_sched { + rb_nativethread_lock_t lock_; +#if VM_CHECK_MODE + struct rb_thread_struct *lock_owner; +#endif + struct rb_thread_struct *running; // running thread or NULL + bool is_running; + bool is_running_timeslice; + bool enable_mn_threads; + + struct ccan_list_head readyq; + int readyq_cnt; + // ractor scheduling + struct ccan_list_node grq_node; +}; + +#ifdef RB_THREAD_LOCAL_SPECIFIER + NOINLINE(void rb_current_ec_set(struct rb_execution_context_struct *)); + + # ifdef RB_THREAD_CURRENT_EC_NOINLINE + NOINLINE(struct rb_execution_context_struct *rb_current_ec(void)); + # else + RUBY_EXTERN RB_THREAD_LOCAL_SPECIFIER struct rb_execution_context_struct *ruby_current_ec; + + // for RUBY_DEBUG_LOG() + RUBY_EXTERN RB_THREAD_LOCAL_SPECIFIER rb_atomic_t ruby_nt_serial; + #define RUBY_NT_SERIAL 1 + # endif +#else +typedef pthread_key_t native_tls_key_t; + +static inline void * +native_tls_get(native_tls_key_t key) +{ + // return value should be checked by caller + return pthread_getspecific(key); +} + +static inline void +native_tls_set(native_tls_key_t key, void *ptr) +{ + if (UNLIKELY(pthread_setspecific(key, ptr) != 0)) { + rb_bug("pthread_setspecific error"); + } +} + +RUBY_EXTERN native_tls_key_t ruby_current_ec_key; +#endif + +struct rb_ractor_struct; +void rb_ractor_sched_wait(struct rb_execution_context_struct *ec, struct rb_ractor_struct *cr, rb_unblock_function_t *ubf, void *ptr); +void rb_ractor_sched_wakeup(struct rb_ractor_struct *r, struct rb_thread_struct *th); + +#endif /* RUBY_THREAD_PTHREAD_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/vm_core.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/vm_core.h new file mode 100644 index 0000000..9f794d8 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/vm_core.h @@ -0,0 +1,2350 @@ +#ifndef RUBY_VM_CORE_H +#define RUBY_VM_CORE_H +/********************************************************************** + + vm_core.h - + + $Author$ + created at: 04/01/01 19:41:38 JST + + Copyright (C) 2004-2007 Koichi Sasada + +**********************************************************************/ + +/* + * Enable check mode. + * 1: enable local assertions. + */ +#ifndef VM_CHECK_MODE + +// respect RUBY_DUBUG: if given n is 0, then use RUBY_DEBUG +#define N_OR_RUBY_DEBUG(n) (((n) > 0) ? (n) : RUBY_DEBUG) + +#define VM_CHECK_MODE N_OR_RUBY_DEBUG(0) +#endif + +/** + * VM Debug Level + * + * debug level: + * 0: no debug output + * 1: show instruction name + * 2: show stack frame when control stack frame is changed + * 3: show stack status + * 4: show register + * 5: + * 10: gc check + */ + +#ifndef VMDEBUG +#define VMDEBUG 0 +#endif + +#if 0 +#undef VMDEBUG +#define VMDEBUG 3 +#endif + +#include "ruby/internal/config.h" + +#include +#include +#include + +#include "ruby_assert.h" + +#define RVALUE_SIZE (sizeof(struct RBasic) + sizeof(VALUE[RBIMPL_RVALUE_EMBED_LEN_MAX])) + +#if VM_CHECK_MODE > 0 +#define VM_ASSERT(expr, ...) \ + RUBY_ASSERT_MESG_WHEN(VM_CHECK_MODE > 0, expr, #expr RBIMPL_VA_OPT_ARGS(__VA_ARGS__)) +#define VM_UNREACHABLE(func) rb_bug(#func ": unreachable") +#define RUBY_ASSERT_CRITICAL_SECTION +#define RUBY_DEBUG_THREAD_SCHEDULE() rb_thread_schedule() +#else +#define VM_ASSERT(/*expr, */...) ((void)0) +#define VM_UNREACHABLE(func) UNREACHABLE +#define RUBY_DEBUG_THREAD_SCHEDULE() +#endif + +#define RUBY_ASSERT_MUTEX_OWNED(mutex) VM_ASSERT(rb_mutex_owned_p(mutex)) + +#if defined(RUBY_ASSERT_CRITICAL_SECTION) +/* +# Critical Section Assertions + +These assertions are used to ensure that context switching does not occur between two points in the code. In theory, +such code should already be protected by a mutex, but these assertions are used to ensure that the mutex is held. + +The specific case where it can be useful is where a mutex is held further up the call stack, and the code in question +may not directly hold the mutex. In this case, the critical section assertions can be used to ensure that the mutex is +held by someone else. + +These assertions are only enabled when RUBY_ASSERT_CRITICAL_SECTION is defined, which is only defined if VM_CHECK_MODE +is set. + +## Example Usage + +```c +RUBY_ASSERT_CRITICAL_SECTION_ENTER(); +// ... some code which does not invoke rb_vm_check_ints() ... +RUBY_ASSERT_CRITICAL_SECTION_LEAVE(); +``` + +If `rb_vm_check_ints()` is called between the `RUBY_ASSERT_CRITICAL_SECTION_ENTER()` and +`RUBY_ASSERT_CRITICAL_SECTION_LEAVE()`, a failed assertion will result. +*/ +extern int ruby_assert_critical_section_entered; +#define RUBY_ASSERT_CRITICAL_SECTION_ENTER() do{ruby_assert_critical_section_entered += 1;}while(false) +#define RUBY_ASSERT_CRITICAL_SECTION_LEAVE() do{VM_ASSERT(ruby_assert_critical_section_entered > 0);ruby_assert_critical_section_entered -= 1;}while(false) +#else +#define RUBY_ASSERT_CRITICAL_SECTION_ENTER() +#define RUBY_ASSERT_CRITICAL_SECTION_LEAVE() +#endif + +#if defined(__wasm__) && !defined(__EMSCRIPTEN__) +# include "wasm/setjmp.h" +#else +# include +#endif + +#if defined(__linux__) || defined(__FreeBSD__) +# define RB_THREAD_T_HAS_NATIVE_ID +#endif + +#include "ruby/internal/stdbool.h" +#include "ccan/list/list.h" +#include "id.h" +#include "internal.h" +#include "internal/array.h" +#include "internal/basic_operators.h" +#include "internal/box.h" +#include "internal/sanitizers.h" +#include "internal/serial.h" +#include "internal/set_table.h" +#include "internal/vm.h" +#include "method.h" +#include "node.h" +#include "ruby/ruby.h" +#include "ruby/st.h" +#include "ruby_atomic.h" +#include "vm_opts.h" + +#include "ruby/thread_native.h" +/* + * implementation selector of get_insn_info algorithm + * 0: linear search + * 1: binary search + * 2: succinct bitvector + */ +#ifndef VM_INSN_INFO_TABLE_IMPL +# define VM_INSN_INFO_TABLE_IMPL 2 +#endif + +#if defined(NSIG_MAX) /* POSIX issue 8 */ +# undef NSIG +# define NSIG NSIG_MAX +#elif defined(_SIG_MAXSIG) /* FreeBSD */ +# undef NSIG +# define NSIG _SIG_MAXSIG +#elif defined(_SIGMAX) /* QNX */ +# define NSIG (_SIGMAX + 1) +#elif defined(NSIG) /* 99% of everything else */ +# /* take it */ +#else /* Last resort */ +# define NSIG (sizeof(sigset_t) * CHAR_BIT + 1) +#endif + +#define RUBY_NSIG NSIG + +#if defined(SIGCLD) +# define RUBY_SIGCHLD (SIGCLD) +#elif defined(SIGCHLD) +# define RUBY_SIGCHLD (SIGCHLD) +#endif + +#if defined(SIGSEGV) && defined(HAVE_SIGALTSTACK) && defined(SA_SIGINFO) && !defined(__NetBSD__) +# define USE_SIGALTSTACK +void *rb_allocate_sigaltstack(void); +void *rb_register_sigaltstack(void *); +# define RB_ALTSTACK_INIT(var, altstack) var = rb_register_sigaltstack(altstack) +# define RB_ALTSTACK_FREE(var) free(var) +# define RB_ALTSTACK(var) var +#else /* noop */ +# define RB_ALTSTACK_INIT(var, altstack) +# define RB_ALTSTACK_FREE(var) +# define RB_ALTSTACK(var) (0) +#endif + +#include THREAD_IMPL_H +#define RUBY_VM_THREAD_MODEL 2 + +/*****************/ +/* configuration */ +/*****************/ + +/* gcc ver. check */ +#if defined(__GNUC__) && __GNUC__ >= 2 + +#if OPT_TOKEN_THREADED_CODE +#if OPT_DIRECT_THREADED_CODE +#undef OPT_DIRECT_THREADED_CODE +#endif +#endif + +#else /* defined(__GNUC__) && __GNUC__ >= 2 */ + +/* disable threaded code options */ +#if OPT_DIRECT_THREADED_CODE +#undef OPT_DIRECT_THREADED_CODE +#endif +#if OPT_TOKEN_THREADED_CODE +#undef OPT_TOKEN_THREADED_CODE +#endif +#endif + +/* call threaded code */ +#if OPT_CALL_THREADED_CODE +#if OPT_DIRECT_THREADED_CODE +#undef OPT_DIRECT_THREADED_CODE +#endif /* OPT_DIRECT_THREADED_CODE */ +#endif /* OPT_CALL_THREADED_CODE */ + +void rb_vm_encoded_insn_data_table_init(void); +typedef unsigned long rb_num_t; +typedef signed long rb_snum_t; + +enum ruby_tag_type { + RUBY_TAG_NONE = 0x0, + RUBY_TAG_RETURN = 0x1, + RUBY_TAG_BREAK = 0x2, + RUBY_TAG_NEXT = 0x3, + RUBY_TAG_RETRY = 0x4, + RUBY_TAG_REDO = 0x5, + RUBY_TAG_RAISE = 0x6, + RUBY_TAG_THROW = 0x7, + RUBY_TAG_FATAL = 0x8, + RUBY_TAG_MASK = 0xf +}; + +#define TAG_NONE RUBY_TAG_NONE +#define TAG_RETURN RUBY_TAG_RETURN +#define TAG_BREAK RUBY_TAG_BREAK +#define TAG_NEXT RUBY_TAG_NEXT +#define TAG_RETRY RUBY_TAG_RETRY +#define TAG_REDO RUBY_TAG_REDO +#define TAG_RAISE RUBY_TAG_RAISE +#define TAG_THROW RUBY_TAG_THROW +#define TAG_FATAL RUBY_TAG_FATAL +#define TAG_MASK RUBY_TAG_MASK + +enum ruby_vm_throw_flags { + VM_THROW_NO_ESCAPE_FLAG = 0x8000, + VM_THROW_STATE_MASK = 0xff +}; + +/* forward declarations */ +struct rb_thread_struct; +struct rb_control_frame_struct; + +/* iseq data type */ +typedef struct rb_compile_option_struct rb_compile_option_t; + +union ic_serial_entry { + rb_serial_t raw; + VALUE data[2]; +}; + +#define IMEMO_CONST_CACHE_SHAREABLE IMEMO_FL_USER0 + +// imemo_constcache +struct iseq_inline_constant_cache_entry { + VALUE flags; + + VALUE value; + const rb_cref_t *ic_cref; +}; +STATIC_ASSERT(sizeof_iseq_inline_constant_cache_entry, + (offsetof(struct iseq_inline_constant_cache_entry, ic_cref) + + sizeof(const rb_cref_t *)) <= RVALUE_SIZE); + +struct iseq_inline_constant_cache { + struct iseq_inline_constant_cache_entry *entry; + + /** + * A null-terminated list of ids, used to represent a constant's path + * idNULL is used to represent the :: prefix, and 0 is used to donate the end + * of the list. + * + * For example + * FOO {rb_intern("FOO"), 0} + * FOO::BAR {rb_intern("FOO"), rb_intern("BAR"), 0} + * ::FOO {idNULL, rb_intern("FOO"), 0} + * ::FOO::BAR {idNULL, rb_intern("FOO"), rb_intern("BAR"), 0} + */ + const ID *segments; +}; + +struct iseq_inline_iv_cache_entry { + uint64_t value; // dest_shape_id in former half, attr_index in latter half + ID iv_set_name; +}; + +struct iseq_inline_cvar_cache_entry { + struct rb_cvar_class_tbl_entry *entry; +}; + +union iseq_inline_storage_entry { + struct { + struct rb_thread_struct *running_thread; + VALUE value; + } once; + struct iseq_inline_constant_cache ic_cache; + struct iseq_inline_iv_cache_entry iv_cache; +}; + +struct rb_calling_info { + const struct rb_call_data *cd; + const struct rb_callcache *cc; + VALUE block_handler; + VALUE recv; + int argc; + bool kw_splat; + VALUE heap_argv; +}; + +#ifndef VM_ARGC_STACK_MAX +#define VM_ARGC_STACK_MAX 128 +#endif + +# define CALLING_ARGC(calling) ((calling)->heap_argv ? RARRAY_LENINT((calling)->heap_argv) : (calling)->argc) + +struct rb_execution_context_struct; + +#if 1 +#define CoreDataFromValue(obj, type) (type*)DATA_PTR(obj) +#else +#define CoreDataFromValue(obj, type) (type*)rb_data_object_get(obj) +#endif +#define GetCoreDataFromValue(obj, type, ptr) ((ptr) = CoreDataFromValue((obj), type)) + +typedef struct rb_iseq_location_struct { + VALUE pathobj; /* String (path) or Array [path, realpath]. Frozen. */ + VALUE base_label; /* String */ + VALUE label; /* String */ + int first_lineno; + int node_id; + rb_code_location_t code_location; +} rb_iseq_location_t; + +#define PATHOBJ_PATH 0 +#define PATHOBJ_REALPATH 1 + +static inline VALUE +pathobj_path(VALUE pathobj) +{ + if (RB_TYPE_P(pathobj, T_STRING)) { + return pathobj; + } + else { + VM_ASSERT(RB_TYPE_P(pathobj, T_ARRAY)); + return RARRAY_AREF(pathobj, PATHOBJ_PATH); + } +} + +static inline VALUE +pathobj_realpath(VALUE pathobj) +{ + if (RB_TYPE_P(pathobj, T_STRING)) { + return pathobj; + } + else { + VM_ASSERT(RB_TYPE_P(pathobj, T_ARRAY)); + return RARRAY_AREF(pathobj, PATHOBJ_REALPATH); + } +} + +/* Forward declarations */ +typedef uintptr_t iseq_bits_t; + +#define ISEQ_IS_SIZE(body) (body->ic_size + body->ivc_size + body->ise_size + body->icvarc_size) + +/* [ TS_IVC | TS_ICVARC | TS_ISE | TS_IC ] */ +#define ISEQ_IS_IC_ENTRY(body, idx) (body->is_entries[(idx) + body->ise_size + body->icvarc_size + body->ivc_size].ic_cache); + +/* instruction sequence type */ +enum rb_iseq_type { + ISEQ_TYPE_TOP, + ISEQ_TYPE_METHOD, + ISEQ_TYPE_BLOCK, + ISEQ_TYPE_CLASS, + ISEQ_TYPE_RESCUE, + ISEQ_TYPE_ENSURE, + ISEQ_TYPE_EVAL, + ISEQ_TYPE_MAIN, + ISEQ_TYPE_PLAIN +}; + +// Attributes specified by Primitive.attr! +enum rb_builtin_attr { + // The iseq does not call methods. + BUILTIN_ATTR_LEAF = 0x01, + // This iseq only contains single `opt_invokebuiltin_delegate_leave` instruction with 0 arguments. + BUILTIN_ATTR_SINGLE_NOARG_LEAF = 0x02, + // This attribute signals JIT to duplicate the iseq for each block iseq so that its `yield` will be monomorphic. + BUILTIN_ATTR_INLINE_BLOCK = 0x04, + // The iseq acts like a C method in backtraces. + BUILTIN_ATTR_C_TRACE = 0x08, +}; + +typedef VALUE (*rb_jit_func_t)(struct rb_execution_context_struct *, struct rb_control_frame_struct *); +typedef VALUE (*rb_zjit_func_t)(struct rb_execution_context_struct *, struct rb_control_frame_struct *, rb_jit_func_t); + +struct rb_iseq_constant_body { + enum rb_iseq_type type; + + unsigned int iseq_size; + VALUE *iseq_encoded; /* encoded iseq (insn addr and operands) */ + + /** + * parameter information + * + * def m(a1, a2, ..., aM, # mandatory + * b1=(...), b2=(...), ..., bN=(...), # optional + * *c, # rest + * d1, d2, ..., dO, # post + * e1:(...), e2:(...), ..., eK:(...), # keyword + * **f, # keyword_rest + * &g) # block + * => + * + * lead_num = M + * opt_num = N + * rest_start = M+N + * post_start = M+N+(*1) + * post_num = O + * keyword_num = K + * block_start = M+N+(*1)+O+K + * keyword_bits = M+N+(*1)+O+K+(&1) + * size = M+N+O+(*1)+K+(&1)+(**1) // parameter size. + */ + + struct { + struct { + unsigned int has_lead : 1; + unsigned int has_opt : 1; + unsigned int has_rest : 1; + unsigned int has_post : 1; + unsigned int has_kw : 1; + unsigned int has_kwrest : 1; + unsigned int has_block : 1; + + unsigned int ambiguous_param0 : 1; /* {|a|} */ + unsigned int accepts_no_kwarg : 1; + unsigned int ruby2_keywords: 1; + unsigned int anon_rest: 1; + unsigned int anon_kwrest: 1; + unsigned int use_block: 1; + unsigned int forwardable: 1; + } flags; + + unsigned int size; + + int lead_num; + int opt_num; + int rest_start; + int post_start; + int post_num; + int block_start; + + const VALUE *opt_table; /* (opt_num + 1) entries. */ + /* opt_num and opt_table: + * + * def foo o1=e1, o2=e2, ..., oN=eN + * #=> + * # prologue code + * A1: e1 + * A2: e2 + * ... + * AN: eN + * AL: body + * opt_num = N + * opt_table = [A1, A2, ..., AN, AL] + */ + + const struct rb_iseq_param_keyword { + int num; + int required_num; + int bits_start; + int rest_start; + const ID *table; + VALUE *default_values; + } *keyword; + } param; + + rb_iseq_location_t location; + + /* insn info, must be freed */ + struct iseq_insn_info { + const struct iseq_insn_info_entry *body; + unsigned int *positions; + unsigned int size; +#if VM_INSN_INFO_TABLE_IMPL == 2 + struct succ_index_table *succ_index_table; +#endif + } insns_info; + + const ID *local_table; /* must free */ + + enum lvar_state { + lvar_uninitialized, + lvar_initialized, + lvar_reassigned, + } *lvar_states; + + /* catch table */ + struct iseq_catch_table *catch_table; + + /* for child iseq */ + const struct rb_iseq_struct *parent_iseq; + struct rb_iseq_struct *local_iseq; /* local_iseq->flip_cnt can be modified */ + + union iseq_inline_storage_entry *is_entries; /* [ TS_IVC | TS_ICVARC | TS_ISE | TS_IC ] */ + struct rb_call_data *call_data; //struct rb_call_data calls[ci_size]; + + struct { + rb_snum_t flip_count; + VALUE script_lines; + VALUE coverage; + VALUE pc2branchindex; + VALUE *original_iseq; + } variable; + + unsigned int local_table_size; + unsigned int ic_size; // Number of IC caches + unsigned int ise_size; // Number of ISE caches + unsigned int ivc_size; // Number of IVC caches + unsigned int icvarc_size; // Number of ICVARC caches + unsigned int ci_size; + unsigned int stack_max; /* for stack overflow check */ + + unsigned int builtin_attrs; // Union of rb_builtin_attr + + bool prism; // ISEQ was generated from prism compiler + + union { + iseq_bits_t * list; /* Find references for GC */ + iseq_bits_t single; + } mark_bits; + + struct rb_id_table *outer_variables; + + const rb_iseq_t *mandatory_only_iseq; + +#if USE_YJIT || USE_ZJIT + // Function pointer for JIT code on jit_exec() + rb_jit_func_t jit_entry; + // Number of calls on jit_exec() + long unsigned jit_entry_calls; + // Function pointer for JIT code on jit_exec_exception() + rb_jit_func_t jit_exception; + // Number of calls on jit_exec_exception() + long unsigned jit_exception_calls; +#endif + +#if USE_YJIT + // YJIT stores some data on each iseq. + void *yjit_payload; + // Used to estimate how frequently this ISEQ gets called + uint64_t yjit_calls_at_interv; +#endif + +#if USE_ZJIT + // ZJIT stores some data on each iseq. + void *zjit_payload; +#endif +}; + +/* T_IMEMO/iseq */ +/* typedef rb_iseq_t is in method.h */ +struct rb_iseq_struct { + VALUE flags; /* 1 */ + VALUE wrapper; /* 2 */ + + struct rb_iseq_constant_body *body; /* 3 */ + + union { /* 4, 5 words */ + struct iseq_compile_data *compile_data; /* used at compile time */ + + struct { + VALUE obj; + int index; + } loader; + + struct { + struct rb_hook_list_struct *local_hooks; + rb_event_flag_t global_trace_events; + } exec; + } aux; +}; + +#define ISEQ_BODY(iseq) ((iseq)->body) + +#if !defined(USE_LAZY_LOAD) || !(USE_LAZY_LOAD+0) +#define USE_LAZY_LOAD 0 +#endif + +#if !USE_LAZY_LOAD +static inline const rb_iseq_t *rb_iseq_complete(const rb_iseq_t *iseq) {return 0;} +#endif +const rb_iseq_t *rb_iseq_complete(const rb_iseq_t *iseq); + +static inline const rb_iseq_t * +rb_iseq_check(const rb_iseq_t *iseq) +{ + if (USE_LAZY_LOAD && ISEQ_BODY(iseq) == NULL) { + rb_iseq_complete((rb_iseq_t *)iseq); + } + return iseq; +} + +static inline bool +rb_iseq_attr_p(const rb_iseq_t *iseq, enum rb_builtin_attr attr) +{ + return (ISEQ_BODY(iseq)->builtin_attrs & attr) == attr; +} + +static inline const rb_iseq_t * +def_iseq_ptr(rb_method_definition_t *def) +{ +//TODO: re-visit. to check the bug, enable this assertion. +#if VM_CHECK_MODE > 0 + if (def->type != VM_METHOD_TYPE_ISEQ) rb_bug("def_iseq_ptr: not iseq (%d)", def->type); +#endif + return rb_iseq_check(def->body.iseq.iseqptr); +} + +enum ruby_special_exceptions { + ruby_error_reenter, + ruby_error_nomemory, + ruby_error_sysstack, + ruby_error_stackfatal, + ruby_error_stream_closed, + ruby_special_error_count +}; + +#define GetVMPtr(obj, ptr) \ + GetCoreDataFromValue((obj), rb_vm_t, (ptr)) + +struct rb_vm_struct; +typedef void rb_vm_at_exit_func(struct rb_vm_struct*); + +typedef struct rb_at_exit_list { + rb_vm_at_exit_func *func; + struct rb_at_exit_list *next; +} rb_at_exit_list; + +void *rb_objspace_alloc(void); +void rb_objspace_free(void *objspace); +void rb_objspace_call_finalizer(void); + +typedef struct rb_hook_list_struct { + struct rb_event_hook_struct *hooks; + rb_event_flag_t events; + unsigned int running; + bool need_clean; + bool is_local; +} rb_hook_list_t; + + +// see builtin.h for definition +typedef const struct rb_builtin_function *RB_BUILTIN; + +struct global_object_list { + VALUE *varptr; + struct global_object_list *next; +}; + +typedef struct rb_vm_struct { + VALUE self; + + struct { + struct ccan_list_head set; + unsigned int cnt; + unsigned int blocking_cnt; + + struct rb_ractor_struct *main_ractor; + struct rb_thread_struct *main_thread; // == vm->ractor.main_ractor->threads.main + + struct { + // monitor + rb_nativethread_lock_t lock; + struct rb_ractor_struct *lock_owner; + unsigned int lock_rec; + + // join at exit + rb_nativethread_cond_t terminate_cond; + bool terminate_waiting; + +#ifndef RUBY_THREAD_PTHREAD_H + // win32 + bool barrier_waiting; + unsigned int barrier_cnt; + rb_nativethread_cond_t barrier_complete_cond; + rb_nativethread_cond_t barrier_release_cond; +#endif + } sync; + +#ifdef RUBY_THREAD_PTHREAD_H + // ractor scheduling + struct { + rb_nativethread_lock_t lock; + struct rb_ractor_struct *lock_owner; + bool locked; + + rb_nativethread_cond_t cond; // GRQ + unsigned int snt_cnt; // count of shared NTs + unsigned int dnt_cnt; // count of dedicated NTs + + unsigned int running_cnt; + + unsigned int max_cpu; + struct ccan_list_head grq; // // Global Ready Queue + unsigned int grq_cnt; + + // running threads + struct ccan_list_head running_threads; + + // threads which switch context by timeslice + struct ccan_list_head timeslice_threads; + + struct ccan_list_head zombie_threads; + + // true if timeslice timer is not enable + bool timeslice_wait_inf; + + // barrier + rb_nativethread_cond_t barrier_complete_cond; + rb_nativethread_cond_t barrier_release_cond; + bool barrier_waiting; + unsigned int barrier_waiting_cnt; + unsigned int barrier_serial; + struct rb_ractor_struct *barrier_ractor; + unsigned int barrier_lock_rec; + } sched; +#endif + } ractor; + +#ifdef USE_SIGALTSTACK + void *main_altstack; +#endif + + rb_serial_t fork_gen; + + /* set in single-threaded processes only: */ + volatile int ubf_async_safe; + + unsigned int running: 1; + unsigned int thread_abort_on_exception: 1; + unsigned int thread_report_on_exception: 1; + unsigned int thread_ignore_deadlock: 1; + + /* object management */ + VALUE mark_object_ary; + struct global_object_list *global_object_list; + const VALUE special_exceptions[ruby_special_error_count]; + + /* Ruby Box */ + rb_box_t *root_box; + rb_box_t *main_box; + + /* load */ + // For running the init function of statically linked + // extensions when they are loaded + struct st_table *static_ext_inits; + + /* signal */ + struct { + VALUE cmd[RUBY_NSIG]; + } trap_list; + + /* postponed_job (async-signal-safe, and thread-safe) */ + struct rb_postponed_job_queue *postponed_job_queue; + + int src_encoding_index; + + /* workqueue (thread-safe, NOT async-signal-safe) */ + struct ccan_list_head workqueue; /* <=> rb_workqueue_job.jnode */ + rb_nativethread_lock_t workqueue_lock; + + VALUE orig_progname, progname; + VALUE coverages, me2counter; + int coverage_mode; + + struct { + struct rb_objspace *objspace; + struct gc_mark_func_data_struct { + void *data; + void (*mark_func)(VALUE v, void *data); + } *mark_func_data; + } gc; + + rb_at_exit_list *at_exit; + + const struct rb_builtin_function *builtin_function_table; + + st_table *ci_table; + struct rb_id_table *negative_cme_table; + st_table *overloaded_cme_table; // cme -> overloaded_cme + set_table *unused_block_warning_table; + set_table *cc_refinement_table; + + // This id table contains a mapping from ID to ICs. It does this with ID + // keys and nested st_tables as values. The nested tables have ICs as keys + // and Qtrue as values. It is used when inline constant caches need to be + // invalidated or ISEQs are being freed. + struct rb_id_table *constant_cache; + ID inserting_constant_cache_id; + +#ifndef VM_GLOBAL_CC_CACHE_TABLE_SIZE +#define VM_GLOBAL_CC_CACHE_TABLE_SIZE 1023 +#endif + const struct rb_callcache *global_cc_cache_table[VM_GLOBAL_CC_CACHE_TABLE_SIZE]; // vm_eval.c + +#if defined(USE_VM_CLOCK) && USE_VM_CLOCK + uint32_t clock; +#endif + + /* params */ + struct { /* size in byte */ + size_t thread_vm_stack_size; + size_t thread_machine_stack_size; + size_t fiber_vm_stack_size; + size_t fiber_machine_stack_size; + } default_params; +} rb_vm_t; + +extern bool ruby_vm_during_cleanup; + +/* default values */ + +#define RUBY_VM_SIZE_ALIGN 4096 + +#define RUBY_VM_THREAD_VM_STACK_SIZE ( 128 * 1024 * sizeof(VALUE)) /* 512 KB or 1024 KB */ +#define RUBY_VM_THREAD_VM_STACK_SIZE_MIN ( 2 * 1024 * sizeof(VALUE)) /* 8 KB or 16 KB */ +#define RUBY_VM_THREAD_MACHINE_STACK_SIZE ( 128 * 1024 * sizeof(VALUE)) /* 512 KB or 1024 KB */ +#define RUBY_VM_THREAD_MACHINE_STACK_SIZE_MIN ( 16 * 1024 * sizeof(VALUE)) /* 64 KB or 128 KB */ + +#define RUBY_VM_FIBER_VM_STACK_SIZE ( 16 * 1024 * sizeof(VALUE)) /* 64 KB or 128 KB */ +#define RUBY_VM_FIBER_VM_STACK_SIZE_MIN ( 2 * 1024 * sizeof(VALUE)) /* 8 KB or 16 KB */ +#define RUBY_VM_FIBER_MACHINE_STACK_SIZE ( 64 * 1024 * sizeof(VALUE)) /* 256 KB or 512 KB */ +#if defined(__powerpc64__) || defined(__ppc64__) // macOS has __ppc64__ +#define RUBY_VM_FIBER_MACHINE_STACK_SIZE_MIN ( 32 * 1024 * sizeof(VALUE)) /* 128 KB or 256 KB */ +#else +#define RUBY_VM_FIBER_MACHINE_STACK_SIZE_MIN ( 16 * 1024 * sizeof(VALUE)) /* 64 KB or 128 KB */ +#endif + +#if __has_feature(memory_sanitizer) || __has_feature(address_sanitizer) || __has_feature(leak_sanitizer) +/* It seems sanitizers consume A LOT of machine stacks */ +#undef RUBY_VM_THREAD_MACHINE_STACK_SIZE +#define RUBY_VM_THREAD_MACHINE_STACK_SIZE (1024 * 1024 * sizeof(VALUE)) +#undef RUBY_VM_THREAD_MACHINE_STACK_SIZE_MIN +#define RUBY_VM_THREAD_MACHINE_STACK_SIZE_MIN ( 512 * 1024 * sizeof(VALUE)) +#undef RUBY_VM_FIBER_MACHINE_STACK_SIZE +#define RUBY_VM_FIBER_MACHINE_STACK_SIZE ( 256 * 1024 * sizeof(VALUE)) +#undef RUBY_VM_FIBER_MACHINE_STACK_SIZE_MIN +#define RUBY_VM_FIBER_MACHINE_STACK_SIZE_MIN ( 128 * 1024 * sizeof(VALUE)) +#endif + +#ifndef VM_DEBUG_BP_CHECK +#define VM_DEBUG_BP_CHECK 0 +#endif + +#ifndef VM_DEBUG_VERIFY_METHOD_CACHE +#define VM_DEBUG_VERIFY_METHOD_CACHE (VMDEBUG != 0) +#endif + +struct rb_captured_block { + VALUE self; + const VALUE *ep; + union { + const rb_iseq_t *iseq; + const struct vm_ifunc *ifunc; + VALUE val; + } code; +}; + +enum rb_block_handler_type { + block_handler_type_iseq, + block_handler_type_ifunc, + block_handler_type_symbol, + block_handler_type_proc +}; + +enum rb_block_type { + block_type_iseq, + block_type_ifunc, + block_type_symbol, + block_type_proc +}; + +struct rb_block { + union { + struct rb_captured_block captured; + VALUE symbol; + VALUE proc; + } as; + enum rb_block_type type; +}; + +typedef struct rb_control_frame_struct { + const VALUE *pc; // cfp[0] + VALUE *sp; // cfp[1] + const rb_iseq_t *iseq; // cfp[2] + VALUE self; // cfp[3] / block[0] + const VALUE *ep; // cfp[4] / block[1] + const void *block_code; // cfp[5] / block[2] -- iseq, ifunc, or forwarded block handler + void *jit_return; // cfp[6] -- return address for JIT code +#if VM_DEBUG_BP_CHECK + VALUE *bp_check; // cfp[7] +#endif +} rb_control_frame_t; + +extern const rb_data_type_t ruby_threadptr_data_type; + +static inline struct rb_thread_struct * +rb_thread_ptr(VALUE thval) +{ + return (struct rb_thread_struct *)rb_check_typeddata(thval, &ruby_threadptr_data_type); +} + +enum rb_thread_status { + THREAD_RUNNABLE, + THREAD_STOPPED, + THREAD_STOPPED_FOREVER, + THREAD_KILLED +}; + +#ifdef RUBY_JMP_BUF +typedef RUBY_JMP_BUF rb_jmpbuf_t; +#else +typedef void *rb_jmpbuf_t[5]; +#endif + +/* + `rb_vm_tag_jmpbuf_t` type represents a buffer used to + long jump to a C frame associated with `rb_vm_tag`. + + Use-site of `rb_vm_tag_jmpbuf_t` is responsible for calling the + following functions: + - `rb_vm_tag_jmpbuf_init` once `rb_vm_tag_jmpbuf_t` is allocated. + - `rb_vm_tag_jmpbuf_deinit` once `rb_vm_tag_jmpbuf_t` is no longer necessary. + + `RB_VM_TAG_JMPBUF_GET` transforms a `rb_vm_tag_jmpbuf_t` into a + `rb_jmpbuf_t` to be passed to `rb_setjmp/rb_longjmp`. +*/ +#if defined(__wasm__) && !defined(__EMSCRIPTEN__) +/* + WebAssembly target with Asyncify-based SJLJ needs + to capture the execution context by unwind/rewind-ing + call frames into a jump buffer. The buffer space tends + to be considerably large unlike other architectures' + register-based buffers. + Therefore, we allocates the buffer on the heap on such + environments. +*/ +typedef rb_jmpbuf_t *rb_vm_tag_jmpbuf_t; + +#define RB_VM_TAG_JMPBUF_GET(buf) (*buf) + +static inline void +rb_vm_tag_jmpbuf_init(rb_vm_tag_jmpbuf_t *jmpbuf) +{ + *jmpbuf = ruby_xmalloc(sizeof(rb_jmpbuf_t)); +} + +static inline void +rb_vm_tag_jmpbuf_deinit(const rb_vm_tag_jmpbuf_t *jmpbuf) +{ + ruby_xfree(*jmpbuf); +} +#else +typedef rb_jmpbuf_t rb_vm_tag_jmpbuf_t; + +#define RB_VM_TAG_JMPBUF_GET(buf) (buf) + +static inline void +rb_vm_tag_jmpbuf_init(rb_vm_tag_jmpbuf_t *jmpbuf) +{ + // no-op +} + +static inline void +rb_vm_tag_jmpbuf_deinit(const rb_vm_tag_jmpbuf_t *jmpbuf) +{ + // no-op +} +#endif + +/* + the members which are written in EC_PUSH_TAG() should be placed at + the beginning and the end, so that entire region is accessible. +*/ +struct rb_vm_tag { + VALUE tag; + VALUE retval; + rb_vm_tag_jmpbuf_t buf; + struct rb_vm_tag *prev; + enum ruby_tag_type state; + unsigned int lock_rec; +}; + +STATIC_ASSERT(rb_vm_tag_buf_offset, offsetof(struct rb_vm_tag, buf) > 0); +STATIC_ASSERT(rb_vm_tag_buf_end, + offsetof(struct rb_vm_tag, buf) + sizeof(rb_vm_tag_jmpbuf_t) < + sizeof(struct rb_vm_tag)); + +struct rb_unblock_callback { + rb_unblock_function_t *func; + void *arg; +}; + +struct rb_mutex_struct; + +typedef struct rb_fiber_struct rb_fiber_t; + +struct rb_waiting_list { + struct rb_waiting_list *next; + struct rb_thread_struct *thread; + struct rb_fiber_struct *fiber; +}; + +struct rb_execution_context_struct { + /* execution information */ + VALUE *vm_stack; /* must free, must mark */ + size_t vm_stack_size; /* size in word (byte size / sizeof(VALUE)) */ + rb_control_frame_t *cfp; + + struct rb_vm_tag *tag; + + /* interrupt flags */ + rb_atomic_t interrupt_flag; + rb_atomic_t interrupt_mask; /* size should match flag */ +#if defined(USE_VM_CLOCK) && USE_VM_CLOCK + uint32_t checked_clock; +#endif + + rb_fiber_t *fiber_ptr; + struct rb_thread_struct *thread_ptr; + + /* storage (ec (fiber) local) */ + struct rb_id_table *local_storage; + VALUE local_storage_recursive_hash; + VALUE local_storage_recursive_hash_for_trace; + + /* Inheritable fiber storage. */ + VALUE storage; + + /* eval env */ + const VALUE *root_lep; + VALUE root_svar; + + /* trace information */ + struct rb_trace_arg_struct *trace_arg; + + /* temporary places */ + VALUE errinfo; + VALUE passed_block_handler; /* for rb_iterate */ + + uint8_t raised_flag; /* only 3 bits needed */ + + /* n.b. only 7 bits needed, really: */ + BITFIELD(enum method_missing_reason, method_missing_reason, 8); + + VALUE private_const_reference; + + struct { + VALUE obj; + VALUE fields_obj; + } gen_fields_cache; + + /* for GC */ + struct { + VALUE *stack_start; + VALUE *stack_end; + size_t stack_maxsize; + RUBY_ALIGNAS(SIZEOF_VALUE) jmp_buf regs; + +#ifdef RUBY_ASAN_ENABLED + void *asan_fake_stack_handle; +#endif + } machine; +}; + +#ifndef rb_execution_context_t +typedef struct rb_execution_context_struct rb_execution_context_t; +#define rb_execution_context_t rb_execution_context_t +#endif + +// for builtin.h +#define VM_CORE_H_EC_DEFINED 1 + +// Set the vm_stack pointer in the execution context. +void rb_ec_set_vm_stack(rb_execution_context_t *ec, VALUE *stack, size_t size); + +// Initialize the vm_stack pointer in the execution context and push the initial stack frame. +// @param ec the execution context to update. +// @param stack a pointer to the stack to use. +// @param size the size of the stack, as in `VALUE stack[size]`. +void rb_ec_initialize_vm_stack(rb_execution_context_t *ec, VALUE *stack, size_t size); + +// Clear (set to `NULL`) the vm_stack pointer. +// @param ec the execution context to update. +void rb_ec_clear_vm_stack(rb_execution_context_t *ec); + +struct rb_ext_config { + bool ractor_safe; +}; + +typedef struct rb_ractor_struct rb_ractor_t; + +struct rb_native_thread; + +typedef struct rb_thread_struct { + struct ccan_list_node lt_node; // managed by a ractor (r->threads.set) + VALUE self; + rb_ractor_t *ractor; + rb_vm_t *vm; + struct rb_native_thread *nt; + rb_execution_context_t *ec; + + struct rb_thread_sched_item sched; + bool mn_schedulable; + rb_atomic_t serial; // only for RUBY_DEBUG_LOG() + + VALUE last_status; /* $? */ + + /* for cfunc */ + struct rb_calling_info *calling; + + /* for load(true) */ + VALUE top_self; + VALUE top_wrapper; + + /* thread control */ + + BITFIELD(enum rb_thread_status, status, 2); + /* bit flags */ + unsigned int has_dedicated_nt : 1; + unsigned int to_kill : 1; + unsigned int abort_on_exception: 1; + unsigned int report_on_exception: 1; + unsigned int pending_interrupt_queue_checked: 1; + int8_t priority; /* -3 .. 3 (RUBY_THREAD_PRIORITY_{MIN,MAX}) */ + uint32_t running_time_us; /* 12500..800000 */ + + void *blocking_region_buffer; + + VALUE thgroup; + VALUE value; + + /* temporary place of retval on OPT_CALL_THREADED_CODE */ +#if OPT_CALL_THREADED_CODE + VALUE retval; +#endif + + /* async errinfo queue */ + VALUE pending_interrupt_queue; + VALUE pending_interrupt_mask_stack; + + /* interrupt management */ + rb_nativethread_lock_t interrupt_lock; + struct rb_unblock_callback unblock; + VALUE locking_mutex; + struct rb_mutex_struct *keeping_mutexes; + struct ccan_list_head interrupt_exec_tasks; + + struct rb_waiting_list *join_list; + + union { + struct { + VALUE proc; + VALUE args; + int kw_splat; + } proc; + struct { + VALUE (*func)(void *); + void *arg; + } func; + } invoke_arg; + + enum thread_invoke_type { + thread_invoke_type_none = 0, + thread_invoke_type_proc, + thread_invoke_type_ractor_proc, + thread_invoke_type_func + } invoke_type; + + /* fiber */ + rb_fiber_t *root_fiber; + + VALUE scheduler; + unsigned int blocking; + + /* misc */ + VALUE name; + void **specific_storage; + + struct rb_ext_config ext_config; +} rb_thread_t; + +static inline unsigned int +rb_th_serial(const rb_thread_t *th) +{ + return th ? (unsigned int)th->serial : 0; +} + +typedef enum { + VM_DEFINECLASS_TYPE_CLASS = 0x00, + VM_DEFINECLASS_TYPE_SINGLETON_CLASS = 0x01, + VM_DEFINECLASS_TYPE_MODULE = 0x02, + /* 0x03..0x06 is reserved */ + VM_DEFINECLASS_TYPE_MASK = 0x07 +} rb_vm_defineclass_type_t; + +#define VM_DEFINECLASS_TYPE(x) ((rb_vm_defineclass_type_t)(x) & VM_DEFINECLASS_TYPE_MASK) +#define VM_DEFINECLASS_FLAG_SCOPED 0x08 +#define VM_DEFINECLASS_FLAG_HAS_SUPERCLASS 0x10 +#define VM_DEFINECLASS_SCOPED_P(x) ((x) & VM_DEFINECLASS_FLAG_SCOPED) +#define VM_DEFINECLASS_HAS_SUPERCLASS_P(x) \ + ((x) & VM_DEFINECLASS_FLAG_HAS_SUPERCLASS) + +/* iseq.c */ +RUBY_SYMBOL_EXPORT_BEGIN + +/* node -> iseq */ +rb_iseq_t *rb_iseq_new (const VALUE ast_value, VALUE name, VALUE path, VALUE realpath, const rb_iseq_t *parent, enum rb_iseq_type); +rb_iseq_t *rb_iseq_new_top (const VALUE ast_value, VALUE name, VALUE path, VALUE realpath, const rb_iseq_t *parent); +rb_iseq_t *rb_iseq_new_main (const VALUE ast_value, VALUE path, VALUE realpath, const rb_iseq_t *parent, int opt); +rb_iseq_t *rb_iseq_new_eval (const VALUE ast_value, VALUE name, VALUE path, VALUE realpath, int first_lineno, const rb_iseq_t *parent, int isolated_depth); +rb_iseq_t *rb_iseq_new_with_opt( VALUE ast_value, VALUE name, VALUE path, VALUE realpath, int first_lineno, const rb_iseq_t *parent, int isolated_depth, + enum rb_iseq_type, const rb_compile_option_t*, + VALUE script_lines); + +struct iseq_link_anchor; +struct rb_iseq_new_with_callback_callback_func { + VALUE flags; + VALUE reserved; + void (*func)(rb_iseq_t *, struct iseq_link_anchor *, const void *); + const void *data; +}; +static inline struct rb_iseq_new_with_callback_callback_func * +rb_iseq_new_with_callback_new_callback( + void (*func)(rb_iseq_t *, struct iseq_link_anchor *, const void *), const void *ptr) +{ + struct rb_iseq_new_with_callback_callback_func *memo = + IMEMO_NEW(struct rb_iseq_new_with_callback_callback_func, imemo_ifunc, Qfalse); + memo->func = func; + memo->data = ptr; + + return memo; +} +rb_iseq_t *rb_iseq_new_with_callback(const struct rb_iseq_new_with_callback_callback_func * ifunc, + VALUE name, VALUE path, VALUE realpath, int first_lineno, + const rb_iseq_t *parent, enum rb_iseq_type, const rb_compile_option_t*); + +VALUE rb_iseq_disasm(const rb_iseq_t *iseq); +int rb_iseq_disasm_insn(VALUE str, const VALUE *iseqval, size_t pos, const rb_iseq_t *iseq, VALUE child); + +VALUE rb_iseq_coverage(const rb_iseq_t *iseq); + +RUBY_EXTERN VALUE rb_cISeq; +RUBY_EXTERN VALUE rb_cRubyVM; +RUBY_EXTERN VALUE rb_mRubyVMFrozenCore; +RUBY_EXTERN VALUE rb_block_param_proxy; +RUBY_SYMBOL_EXPORT_END + +#define GetProcPtr(obj, ptr) \ + GetCoreDataFromValue((obj), rb_proc_t, (ptr)) + +typedef struct { + const struct rb_block block; + unsigned int is_from_method: 1; /* bool */ + unsigned int is_lambda: 1; /* bool */ + unsigned int is_isolated: 1; /* bool */ +} rb_proc_t; + +RUBY_SYMBOL_EXPORT_BEGIN +VALUE rb_proc_isolate(VALUE self); +VALUE rb_proc_isolate_bang(VALUE self, VALUE replace_self); +VALUE rb_proc_ractor_make_shareable(VALUE proc, VALUE replace_self); +RUBY_SYMBOL_EXPORT_END + +typedef struct { + VALUE flags; /* imemo header */ + rb_iseq_t *iseq; + const VALUE *ep; + const VALUE *env; + unsigned int env_size; +} rb_env_t; + +extern const rb_data_type_t ruby_binding_data_type; + +#define GetBindingPtr(obj, ptr) \ + GetCoreDataFromValue((obj), rb_binding_t, (ptr)) + +typedef struct { + const struct rb_block block; + const VALUE pathobj; + int first_lineno; +} rb_binding_t; + +/* used by compile time and send insn */ + +enum vm_check_match_type { + VM_CHECKMATCH_TYPE_WHEN = 1, + VM_CHECKMATCH_TYPE_CASE = 2, + VM_CHECKMATCH_TYPE_RESCUE = 3 +}; + +#define VM_CHECKMATCH_TYPE_MASK 0x03 +#define VM_CHECKMATCH_ARRAY 0x04 + +enum vm_opt_newarray_send_type { + VM_OPT_NEWARRAY_SEND_MAX = 1, + VM_OPT_NEWARRAY_SEND_MIN = 2, + VM_OPT_NEWARRAY_SEND_HASH = 3, + VM_OPT_NEWARRAY_SEND_PACK = 4, + VM_OPT_NEWARRAY_SEND_PACK_BUFFER = 5, + VM_OPT_NEWARRAY_SEND_INCLUDE_P = 6, +}; + +enum vm_special_object_type { + VM_SPECIAL_OBJECT_VMCORE = 1, + VM_SPECIAL_OBJECT_CBASE, + VM_SPECIAL_OBJECT_CONST_BASE +}; + +enum vm_svar_index { + VM_SVAR_LASTLINE = 0, /* $_ */ + VM_SVAR_BACKREF = 1, /* $~ */ + + VM_SVAR_EXTRA_START = 2, + VM_SVAR_FLIPFLOP_START = 2 /* flipflop */ +}; + +/* inline cache */ +typedef struct iseq_inline_constant_cache *IC; +typedef struct iseq_inline_iv_cache_entry *IVC; +typedef struct iseq_inline_cvar_cache_entry *ICVARC; +typedef union iseq_inline_storage_entry *ISE; +typedef const struct rb_callinfo *CALL_INFO; +typedef const struct rb_callcache *CALL_CACHE; +typedef struct rb_call_data *CALL_DATA; + +typedef VALUE CDHASH; + +#ifndef FUNC_FASTCALL +#define FUNC_FASTCALL(x) x +#endif + +typedef rb_control_frame_t * + (FUNC_FASTCALL(*rb_insn_func_t))(rb_execution_context_t *, rb_control_frame_t *); + +#define VM_TAGGED_PTR_SET(p, tag) ((VALUE)(p) | (tag)) +#define VM_TAGGED_PTR_REF(v, mask) ((void *)((v) & ~mask)) + +#define GC_GUARDED_PTR(p) VM_TAGGED_PTR_SET((p), 0x01) +#define GC_GUARDED_PTR_REF(p) VM_TAGGED_PTR_REF((p), 0x03) +#define GC_GUARDED_PTR_P(p) (((VALUE)(p)) & 0x01) + +enum vm_frame_env_flags { + /* Frame/Environment flag bits: + * MMMM MMMM MMMM MMMM ___F FFFF FFFE EEEX (LSB) + * + * X : tag for GC marking (It seems as Fixnum) + * EEE : 4 bits Env flags + * FF..: 8 bits Frame flags + * MM..: 15 bits frame magic (to check frame corruption) + */ + + /* frame types */ + VM_FRAME_MAGIC_METHOD = 0x11110001, + VM_FRAME_MAGIC_BLOCK = 0x22220001, + VM_FRAME_MAGIC_CLASS = 0x33330001, + VM_FRAME_MAGIC_TOP = 0x44440001, + VM_FRAME_MAGIC_CFUNC = 0x55550001, + VM_FRAME_MAGIC_IFUNC = 0x66660001, + VM_FRAME_MAGIC_EVAL = 0x77770001, + VM_FRAME_MAGIC_RESCUE = 0x78880001, + VM_FRAME_MAGIC_DUMMY = 0x79990001, + + VM_FRAME_MAGIC_MASK = 0x7fff0001, + + /* frame flag */ + VM_FRAME_FLAG_FINISH = 0x0020, + VM_FRAME_FLAG_BMETHOD = 0x0040, + VM_FRAME_FLAG_CFRAME = 0x0080, + VM_FRAME_FLAG_LAMBDA = 0x0100, + VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM = 0x0200, + VM_FRAME_FLAG_CFRAME_KW = 0x0400, + VM_FRAME_FLAG_PASSED = 0x0800, + VM_FRAME_FLAG_BOX_REQUIRE = 0x1000, + + /* env flag */ + VM_ENV_FLAG_LOCAL = 0x0002, + VM_ENV_FLAG_ESCAPED = 0x0004, + VM_ENV_FLAG_WB_REQUIRED = 0x0008, + VM_ENV_FLAG_ISOLATED = 0x0010, +}; + +#define VM_ENV_DATA_SIZE ( 3) + +#define VM_ENV_DATA_INDEX_ME_CREF (-2) /* ep[-2] */ +#define VM_ENV_DATA_INDEX_SPECVAL (-1) /* ep[-1] */ +#define VM_ENV_DATA_INDEX_FLAGS ( 0) /* ep[ 0] */ +#define VM_ENV_DATA_INDEX_ENV ( 1) /* ep[ 1] */ + +#define VM_ENV_INDEX_LAST_LVAR (-VM_ENV_DATA_SIZE) + +static inline void VM_FORCE_WRITE_SPECIAL_CONST(const VALUE *ptr, VALUE special_const_value); + +static inline void +VM_ENV_FLAGS_SET(const VALUE *ep, VALUE flag) +{ + VALUE flags = ep[VM_ENV_DATA_INDEX_FLAGS]; + VM_ASSERT(FIXNUM_P(flags)); + VM_FORCE_WRITE_SPECIAL_CONST(&ep[VM_ENV_DATA_INDEX_FLAGS], flags | flag); +} + +static inline void +VM_ENV_FLAGS_UNSET(const VALUE *ep, VALUE flag) +{ + VALUE flags = ep[VM_ENV_DATA_INDEX_FLAGS]; + VM_ASSERT(FIXNUM_P(flags)); + VM_FORCE_WRITE_SPECIAL_CONST(&ep[VM_ENV_DATA_INDEX_FLAGS], flags & ~flag); +} + +static inline unsigned long +VM_ENV_FLAGS(const VALUE *ep, long flag) +{ + VALUE flags = ep[VM_ENV_DATA_INDEX_FLAGS]; + VM_ASSERT(FIXNUM_P(flags)); + return flags & flag; +} + +static inline unsigned long +VM_ENV_FLAGS_UNCHECKED(const VALUE *ep, long flag) +{ + VALUE flags = ep[VM_ENV_DATA_INDEX_FLAGS]; + return flags & flag; +} + +static inline unsigned long +VM_ENV_FRAME_TYPE_P(const VALUE *ep, unsigned long frame_type) +{ + return VM_ENV_FLAGS(ep, VM_FRAME_MAGIC_MASK) == frame_type; +} + +static inline unsigned long +VM_FRAME_TYPE(const rb_control_frame_t *cfp) +{ + return VM_ENV_FLAGS(cfp->ep, VM_FRAME_MAGIC_MASK); +} + +static inline unsigned long +VM_FRAME_TYPE_UNCHECKED(const rb_control_frame_t *cfp) +{ + return VM_ENV_FLAGS_UNCHECKED(cfp->ep, VM_FRAME_MAGIC_MASK); +} + +static inline int +VM_FRAME_LAMBDA_P(const rb_control_frame_t *cfp) +{ + return VM_ENV_FLAGS(cfp->ep, VM_FRAME_FLAG_LAMBDA) != 0; +} + +static inline int +VM_FRAME_CFRAME_KW_P(const rb_control_frame_t *cfp) +{ + return VM_ENV_FLAGS(cfp->ep, VM_FRAME_FLAG_CFRAME_KW) != 0; +} + +static inline int +VM_FRAME_FINISHED_P(const rb_control_frame_t *cfp) +{ + return VM_ENV_FLAGS(cfp->ep, VM_FRAME_FLAG_FINISH) != 0; +} + +static inline int +VM_FRAME_FINISHED_P_UNCHECKED(const rb_control_frame_t *cfp) +{ + return VM_ENV_FLAGS_UNCHECKED(cfp->ep, VM_FRAME_FLAG_FINISH) != 0; +} + +static inline int +VM_FRAME_BMETHOD_P(const rb_control_frame_t *cfp) +{ + return VM_ENV_FLAGS(cfp->ep, VM_FRAME_FLAG_BMETHOD) != 0; +} + +static inline int +rb_obj_is_iseq(VALUE iseq) +{ + return imemo_type_p(iseq, imemo_iseq); +} + +#if VM_CHECK_MODE > 0 +#define RUBY_VM_NORMAL_ISEQ_P(iseq) rb_obj_is_iseq((VALUE)iseq) +#endif + +static inline int +VM_FRAME_CFRAME_P(const rb_control_frame_t *cfp) +{ + int cframe_p = VM_ENV_FLAGS(cfp->ep, VM_FRAME_FLAG_CFRAME) != 0; + VM_ASSERT(RUBY_VM_NORMAL_ISEQ_P(cfp->iseq) != cframe_p || + (VM_FRAME_TYPE(cfp) & VM_FRAME_MAGIC_MASK) == VM_FRAME_MAGIC_DUMMY); + return cframe_p; +} + +static inline int +VM_FRAME_CFRAME_P_UNCHECKED(const rb_control_frame_t *cfp) +{ + return VM_ENV_FLAGS_UNCHECKED(cfp->ep, VM_FRAME_FLAG_CFRAME) != 0; +} + +static inline int +VM_FRAME_RUBYFRAME_P(const rb_control_frame_t *cfp) +{ + return !VM_FRAME_CFRAME_P(cfp); +} + +static inline int +VM_FRAME_RUBYFRAME_P_UNCHECKED(const rb_control_frame_t *cfp) +{ + return !VM_FRAME_CFRAME_P_UNCHECKED(cfp); +} + +static inline int +VM_FRAME_NS_REQUIRE_P(const rb_control_frame_t *cfp) +{ + return VM_ENV_FLAGS(cfp->ep, VM_FRAME_FLAG_BOX_REQUIRE) != 0; +} + +#define RUBYVM_CFUNC_FRAME_P(cfp) \ + (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_CFUNC) + +#define VM_GUARDED_PREV_EP(ep) GC_GUARDED_PTR(ep) +#define VM_BLOCK_HANDLER_NONE 0 + +static inline int +VM_ENV_LOCAL_P(const VALUE *ep) +{ + return VM_ENV_FLAGS(ep, VM_ENV_FLAG_LOCAL) ? 1 : 0; +} + +static inline int +VM_ENV_LOCAL_P_UNCHECKED(const VALUE *ep) +{ + return VM_ENV_FLAGS_UNCHECKED(ep, VM_ENV_FLAG_LOCAL) ? 1 : 0; +} + +static inline const VALUE * +VM_ENV_PREV_EP_UNCHECKED(const VALUE *ep) +{ + return GC_GUARDED_PTR_REF(ep[VM_ENV_DATA_INDEX_SPECVAL]); +} + +static inline const VALUE * +VM_ENV_PREV_EP(const VALUE *ep) +{ + VM_ASSERT(VM_ENV_LOCAL_P(ep) == 0); + return VM_ENV_PREV_EP_UNCHECKED(ep); +} + +static inline bool +VM_ENV_BOXED_P(const VALUE *ep) +{ + return VM_ENV_FRAME_TYPE_P(ep, VM_FRAME_MAGIC_CLASS) || VM_ENV_FRAME_TYPE_P(ep, VM_FRAME_MAGIC_TOP); +} + +static inline VALUE +VM_ENV_BLOCK_HANDLER(const VALUE *ep) +{ + if (VM_ENV_BOXED_P(ep)) { + VM_ASSERT(VM_ENV_LOCAL_P(ep)); + return VM_BLOCK_HANDLER_NONE; + } + + VM_ASSERT(VM_ENV_LOCAL_P(ep)); + return ep[VM_ENV_DATA_INDEX_SPECVAL]; +} + +static inline const rb_box_t * +VM_ENV_BOX(const VALUE *ep) +{ + VM_ASSERT(VM_ENV_BOXED_P(ep)); + VM_ASSERT(VM_ENV_LOCAL_P(ep)); + return (const rb_box_t *)GC_GUARDED_PTR_REF(ep[VM_ENV_DATA_INDEX_SPECVAL]); +} + +static inline const rb_box_t * +VM_ENV_BOX_UNCHECKED(const VALUE *ep) +{ + return (const rb_box_t *)GC_GUARDED_PTR_REF(ep[VM_ENV_DATA_INDEX_SPECVAL]); +} + +#if VM_CHECK_MODE > 0 +int rb_vm_ep_in_heap_p(const VALUE *ep); +#endif + +static inline int +VM_ENV_ESCAPED_P(const VALUE *ep) +{ + VM_ASSERT(rb_vm_ep_in_heap_p(ep) == !!VM_ENV_FLAGS(ep, VM_ENV_FLAG_ESCAPED)); + return VM_ENV_FLAGS(ep, VM_ENV_FLAG_ESCAPED) ? 1 : 0; +} + +RBIMPL_ATTR_NONNULL((1)) +static inline VALUE +VM_ENV_ENVVAL(const VALUE *ep) +{ + VALUE envval = ep[VM_ENV_DATA_INDEX_ENV]; + VM_ASSERT(VM_ENV_ESCAPED_P(ep)); + VM_ASSERT(envval == Qundef || imemo_type_p(envval, imemo_env)); + return envval; +} + +RBIMPL_ATTR_NONNULL((1)) +static inline const rb_env_t * +VM_ENV_ENVVAL_PTR(const VALUE *ep) +{ + return (const rb_env_t *)VM_ENV_ENVVAL(ep); +} + +static inline const rb_env_t * +vm_env_new(VALUE *env_ep, VALUE *env_body, unsigned int env_size, const rb_iseq_t *iseq) +{ + rb_env_t *env = IMEMO_NEW(rb_env_t, imemo_env, (VALUE)iseq); + env->ep = env_ep; + env->env = env_body; + env->env_size = env_size; + env_ep[VM_ENV_DATA_INDEX_ENV] = (VALUE)env; + return env; +} + +static inline void +VM_FORCE_WRITE(const VALUE *ptr, VALUE v) +{ + *((VALUE *)ptr) = v; +} + +static inline void +VM_FORCE_WRITE_SPECIAL_CONST(const VALUE *ptr, VALUE special_const_value) +{ + VM_ASSERT(RB_SPECIAL_CONST_P(special_const_value)); + VM_FORCE_WRITE(ptr, special_const_value); +} + +static inline void +VM_STACK_ENV_WRITE(const VALUE *ep, int index, VALUE v) +{ + VM_ASSERT(VM_ENV_FLAGS(ep, VM_ENV_FLAG_WB_REQUIRED) == 0); + VM_FORCE_WRITE(&ep[index], v); +} + +const VALUE *rb_vm_ep_local_ep(const VALUE *ep); +const VALUE *rb_vm_proc_local_ep(VALUE proc); +void rb_vm_block_ep_update(VALUE obj, const struct rb_block *dst, const VALUE *ep); +void rb_vm_block_copy(VALUE obj, const struct rb_block *dst, const struct rb_block *src); + +VALUE rb_vm_frame_block_handler(const rb_control_frame_t *cfp); + +#define RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp) ((cfp)+1) +#define RUBY_VM_NEXT_CONTROL_FRAME(cfp) ((cfp)-1) + +#define RUBY_VM_VALID_CONTROL_FRAME_P(cfp, ecfp) \ + ((void *)(ecfp) > (void *)(cfp)) + +static inline const rb_control_frame_t * +RUBY_VM_END_CONTROL_FRAME(const rb_execution_context_t *ec) +{ + return (rb_control_frame_t *)(ec->vm_stack + ec->vm_stack_size); +} + +static inline int +RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(const rb_execution_context_t *ec, const rb_control_frame_t *cfp) +{ + return !RUBY_VM_VALID_CONTROL_FRAME_P(cfp, RUBY_VM_END_CONTROL_FRAME(ec)); +} + +static inline int +VM_BH_ISEQ_BLOCK_P(VALUE block_handler) +{ + if ((block_handler & 0x03) == 0x01) { +#if VM_CHECK_MODE > 0 + struct rb_captured_block *captured = VM_TAGGED_PTR_REF(block_handler, 0x03); + VM_ASSERT(imemo_type_p(captured->code.val, imemo_iseq)); +#endif + return 1; + } + else { + return 0; + } +} + +static inline VALUE +VM_BH_FROM_ISEQ_BLOCK(const struct rb_captured_block *captured) +{ + VALUE block_handler = VM_TAGGED_PTR_SET(captured, 0x01); + VM_ASSERT(VM_BH_ISEQ_BLOCK_P(block_handler)); + return block_handler; +} + +static inline const struct rb_captured_block * +VM_BH_TO_ISEQ_BLOCK(VALUE block_handler) +{ + struct rb_captured_block *captured = VM_TAGGED_PTR_REF(block_handler, 0x03); + VM_ASSERT(VM_BH_ISEQ_BLOCK_P(block_handler)); + return captured; +} + +static inline int +VM_BH_IFUNC_P(VALUE block_handler) +{ + if ((block_handler & 0x03) == 0x03) { +#if VM_CHECK_MODE > 0 + struct rb_captured_block *captured = (void *)(block_handler & ~0x03); + VM_ASSERT(imemo_type_p(captured->code.val, imemo_ifunc)); +#endif + return 1; + } + else { + return 0; + } +} + +static inline VALUE +VM_BH_FROM_IFUNC_BLOCK(const struct rb_captured_block *captured) +{ + VALUE block_handler = VM_TAGGED_PTR_SET(captured, 0x03); + VM_ASSERT(VM_BH_IFUNC_P(block_handler)); + return block_handler; +} + +static inline const struct rb_captured_block * +VM_BH_TO_IFUNC_BLOCK(VALUE block_handler) +{ + struct rb_captured_block *captured = VM_TAGGED_PTR_REF(block_handler, 0x03); + VM_ASSERT(VM_BH_IFUNC_P(block_handler)); + return captured; +} + +static inline const struct rb_captured_block * +VM_BH_TO_CAPT_BLOCK(VALUE block_handler) +{ + struct rb_captured_block *captured = VM_TAGGED_PTR_REF(block_handler, 0x03); + VM_ASSERT(VM_BH_IFUNC_P(block_handler) || VM_BH_ISEQ_BLOCK_P(block_handler)); + return captured; +} + +static inline enum rb_block_handler_type +vm_block_handler_type(VALUE block_handler) +{ + if (VM_BH_ISEQ_BLOCK_P(block_handler)) { + return block_handler_type_iseq; + } + else if (VM_BH_IFUNC_P(block_handler)) { + return block_handler_type_ifunc; + } + else if (SYMBOL_P(block_handler)) { + return block_handler_type_symbol; + } + else { + VM_ASSERT(rb_obj_is_proc(block_handler)); + return block_handler_type_proc; + } +} + +static inline void +vm_block_handler_verify(MAYBE_UNUSED(VALUE block_handler)) +{ + VM_ASSERT(block_handler == VM_BLOCK_HANDLER_NONE || + (vm_block_handler_type(block_handler), 1)); +} + +static inline enum rb_block_type +vm_block_type(const struct rb_block *block) +{ +#if VM_CHECK_MODE > 0 + switch (block->type) { + case block_type_iseq: + VM_ASSERT(imemo_type_p(block->as.captured.code.val, imemo_iseq)); + break; + case block_type_ifunc: + VM_ASSERT(imemo_type_p(block->as.captured.code.val, imemo_ifunc)); + break; + case block_type_symbol: + VM_ASSERT(SYMBOL_P(block->as.symbol)); + break; + case block_type_proc: + VM_ASSERT(rb_obj_is_proc(block->as.proc)); + break; + } +#endif + return block->type; +} + +static inline void +vm_block_type_set(const struct rb_block *block, enum rb_block_type type) +{ + struct rb_block *mb = (struct rb_block *)block; + mb->type = type; +} + +static inline const struct rb_block * +vm_proc_block(VALUE procval) +{ + VM_ASSERT(rb_obj_is_proc(procval)); + return &((rb_proc_t *)RTYPEDDATA_DATA(procval))->block; +} + +static inline const rb_iseq_t *vm_block_iseq(const struct rb_block *block); +static inline const VALUE *vm_block_ep(const struct rb_block *block); + +static inline const rb_iseq_t * +vm_proc_iseq(VALUE procval) +{ + return vm_block_iseq(vm_proc_block(procval)); +} + +static inline const VALUE * +vm_proc_ep(VALUE procval) +{ + return vm_block_ep(vm_proc_block(procval)); +} + +static inline const rb_iseq_t * +vm_block_iseq(const struct rb_block *block) +{ + switch (vm_block_type(block)) { + case block_type_iseq: return rb_iseq_check(block->as.captured.code.iseq); + case block_type_proc: return vm_proc_iseq(block->as.proc); + case block_type_ifunc: + case block_type_symbol: return NULL; + } + VM_UNREACHABLE(vm_block_iseq); + return NULL; +} + +static inline const VALUE * +vm_block_ep(const struct rb_block *block) +{ + switch (vm_block_type(block)) { + case block_type_iseq: + case block_type_ifunc: return block->as.captured.ep; + case block_type_proc: return vm_proc_ep(block->as.proc); + case block_type_symbol: return NULL; + } + VM_UNREACHABLE(vm_block_ep); + return NULL; +} + +static inline VALUE +vm_block_self(const struct rb_block *block) +{ + switch (vm_block_type(block)) { + case block_type_iseq: + case block_type_ifunc: + return block->as.captured.self; + case block_type_proc: + return vm_block_self(vm_proc_block(block->as.proc)); + case block_type_symbol: + return Qundef; + } + VM_UNREACHABLE(vm_block_self); + return Qundef; +} + +static inline VALUE +VM_BH_TO_SYMBOL(VALUE block_handler) +{ + VM_ASSERT(SYMBOL_P(block_handler)); + return block_handler; +} + +static inline VALUE +VM_BH_FROM_SYMBOL(VALUE symbol) +{ + VM_ASSERT(SYMBOL_P(symbol)); + return symbol; +} + +static inline VALUE +VM_BH_TO_PROC(VALUE block_handler) +{ + VM_ASSERT(rb_obj_is_proc(block_handler)); + return block_handler; +} + +static inline VALUE +VM_BH_FROM_PROC(VALUE procval) +{ + VM_ASSERT(rb_obj_is_proc(procval)); + return procval; +} + +/* VM related object allocate functions */ +VALUE rb_thread_alloc(VALUE klass); +VALUE rb_binding_alloc(VALUE klass); +VALUE rb_proc_alloc(VALUE klass); +VALUE rb_proc_dup(VALUE self); + +/* for debug */ +extern bool rb_vmdebug_stack_dump_raw(const rb_execution_context_t *ec, const rb_control_frame_t *cfp, FILE *); +extern bool rb_vmdebug_debug_print_pre(const rb_execution_context_t *ec, const rb_control_frame_t *cfp, const VALUE *_pc, FILE *); +extern bool rb_vmdebug_debug_print_post(const rb_execution_context_t *ec, const rb_control_frame_t *cfp, FILE *); + +#define SDR() rb_vmdebug_stack_dump_raw(GET_EC(), GET_EC()->cfp, stderr) +#define SDR2(cfp) rb_vmdebug_stack_dump_raw(GET_EC(), (cfp), stderr) +bool rb_vm_bugreport(const void *, FILE *); +typedef void (*ruby_sighandler_t)(int); +RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 4, 5) +NORETURN(void rb_bug_for_fatal_signal(ruby_sighandler_t default_sighandler, int sig, const void *, const char *fmt, ...)); + +/* functions about thread/vm execution */ +RUBY_SYMBOL_EXPORT_BEGIN +VALUE rb_iseq_eval(const rb_iseq_t *iseq, const rb_box_t *box); +VALUE rb_iseq_eval_main(const rb_iseq_t *iseq); +VALUE rb_iseq_path(const rb_iseq_t *iseq); +VALUE rb_iseq_realpath(const rb_iseq_t *iseq); +RUBY_SYMBOL_EXPORT_END + +VALUE rb_iseq_pathobj_new(VALUE path, VALUE realpath); +void rb_iseq_pathobj_set(const rb_iseq_t *iseq, VALUE path, VALUE realpath); + +int rb_ec_frame_method_id_and_class(const rb_execution_context_t *ec, ID *idp, ID *called_idp, VALUE *klassp); +void rb_ec_setup_exception(const rb_execution_context_t *ec, VALUE mesg, VALUE cause); + +VALUE rb_vm_invoke_proc(rb_execution_context_t *ec, rb_proc_t *proc, int argc, const VALUE *argv, int kw_splat, VALUE block_handler); + +VALUE rb_vm_make_proc_lambda(const rb_execution_context_t *ec, const struct rb_captured_block *captured, VALUE klass, int8_t is_lambda); +static inline VALUE +rb_vm_make_proc(const rb_execution_context_t *ec, const struct rb_captured_block *captured, VALUE klass) +{ + return rb_vm_make_proc_lambda(ec, captured, klass, 0); +} + +static inline VALUE +rb_vm_make_lambda(const rb_execution_context_t *ec, const struct rb_captured_block *captured, VALUE klass) +{ + return rb_vm_make_proc_lambda(ec, captured, klass, 1); +} + +VALUE rb_vm_make_binding(const rb_execution_context_t *ec, const rb_control_frame_t *src_cfp); +VALUE rb_vm_env_local_variables(const rb_env_t *env); +VALUE rb_vm_env_numbered_parameters(const rb_env_t *env); +const rb_env_t *rb_vm_env_prev_env(const rb_env_t *env); +const VALUE *rb_binding_add_dynavars(VALUE bindval, rb_binding_t *bind, int dyncount, const ID *dynvars); +void rb_vm_inc_const_missing_count(void); +VALUE rb_vm_call_kw(rb_execution_context_t *ec, VALUE recv, VALUE id, int argc, + const VALUE *argv, const rb_callable_method_entry_t *me, int kw_splat); +void rb_vm_pop_frame_no_int(rb_execution_context_t *ec); +void rb_vm_pop_frame(rb_execution_context_t *ec); + +void rb_thread_start_timer_thread(void); +void rb_thread_stop_timer_thread(void); +void rb_thread_reset_timer_thread(void); +void rb_thread_wakeup_timer_thread(int); + +static inline void +rb_vm_living_threads_init(rb_vm_t *vm) +{ + ccan_list_head_init(&vm->workqueue); + ccan_list_head_init(&vm->ractor.set); +#ifdef RUBY_THREAD_PTHREAD_H + ccan_list_head_init(&vm->ractor.sched.zombie_threads); +#endif +} + +typedef int rb_backtrace_iter_func(void *, VALUE, int, VALUE); +rb_control_frame_t *rb_vm_get_ruby_level_next_cfp(const rb_execution_context_t *ec, const rb_control_frame_t *cfp); +rb_control_frame_t *rb_vm_get_binding_creatable_next_cfp(const rb_execution_context_t *ec, const rb_control_frame_t *cfp); +VALUE *rb_vm_svar_lep(const rb_execution_context_t *ec, const rb_control_frame_t *cfp); +int rb_vm_get_sourceline(const rb_control_frame_t *); +void rb_vm_stack_to_heap(rb_execution_context_t *ec); +void ruby_thread_init_stack(rb_thread_t *th, void *local_in_parent_frame); +void rb_thread_malloc_stack_set(rb_thread_t *th, void *stack); +rb_thread_t * ruby_thread_from_native(void); +int ruby_thread_set_native(rb_thread_t *th); +int rb_vm_control_frame_id_and_class(const rb_control_frame_t *cfp, ID *idp, ID *called_idp, VALUE *klassp); +void rb_vm_rewind_cfp(rb_execution_context_t *ec, rb_control_frame_t *cfp); +void rb_vm_env_write(const VALUE *ep, int index, VALUE v); +VALUE rb_vm_bh_to_procval(const rb_execution_context_t *ec, VALUE block_handler); + +void rb_vm_register_special_exception_str(enum ruby_special_exceptions sp, VALUE exception_class, VALUE mesg); + +#define rb_vm_register_special_exception(sp, e, m) \ + rb_vm_register_special_exception_str(sp, e, rb_usascii_str_new_static((m), (long)rb_strlen_lit(m))) + +void rb_gc_mark_machine_context(const rb_execution_context_t *ec); + +rb_cref_t *rb_vm_rewrite_cref(rb_cref_t *node, VALUE old_klass, VALUE new_klass); + +const rb_callable_method_entry_t *rb_vm_frame_method_entry(const rb_control_frame_t *cfp); +const rb_callable_method_entry_t *rb_vm_frame_method_entry_unchecked(const rb_control_frame_t *cfp); + +#define sysstack_error GET_VM()->special_exceptions[ruby_error_sysstack] + +#define CHECK_VM_STACK_OVERFLOW0(cfp, sp, margin) do { \ + STATIC_ASSERT(sizeof_sp, sizeof(*(sp)) == sizeof(VALUE)); \ + STATIC_ASSERT(sizeof_cfp, sizeof(*(cfp)) == sizeof(rb_control_frame_t)); \ + const struct rb_control_frame_struct *bound = (void *)&(sp)[(margin)]; \ + if (UNLIKELY((cfp) <= &bound[1])) { \ + vm_stackoverflow(); \ + } \ +} while (0) + +#define CHECK_VM_STACK_OVERFLOW(cfp, margin) \ + CHECK_VM_STACK_OVERFLOW0((cfp), (cfp)->sp, (margin)) + +VALUE rb_catch_protect(VALUE t, rb_block_call_func *func, VALUE data, enum ruby_tag_type *stateptr); + +rb_execution_context_t *rb_vm_main_ractor_ec(rb_vm_t *vm); // ractor.c + +/* for thread */ + +#if RUBY_VM_THREAD_MODEL == 2 + +RUBY_EXTERN struct rb_ractor_struct *ruby_single_main_ractor; // ractor.c +RUBY_EXTERN rb_vm_t *ruby_current_vm_ptr; +RUBY_EXTERN rb_event_flag_t ruby_vm_event_flags; +RUBY_EXTERN rb_event_flag_t ruby_vm_event_enabled_global_flags; +RUBY_EXTERN unsigned int ruby_vm_event_local_num; + +#define GET_VM() rb_current_vm() +#define GET_RACTOR() rb_current_ractor() +#define GET_THREAD() rb_current_thread() +#define GET_EC() rb_current_execution_context(true) + +static inline rb_thread_t * +rb_ec_thread_ptr(const rb_execution_context_t *ec) +{ + return ec->thread_ptr; +} + +static inline rb_ractor_t * +rb_ec_ractor_ptr(const rb_execution_context_t *ec) +{ + const rb_thread_t *th = rb_ec_thread_ptr(ec); + if (th) { + VM_ASSERT(th->ractor != NULL); + return th->ractor; + } + else { + return NULL; + } +} + +static inline rb_vm_t * +rb_ec_vm_ptr(const rb_execution_context_t *ec) +{ + const rb_thread_t *th = rb_ec_thread_ptr(ec); + if (th) { + return th->vm; + } + else { + return NULL; + } +} + +NOINLINE(struct rb_execution_context_struct *rb_current_ec_noinline(void)); + +static inline rb_execution_context_t * +rb_current_execution_context(bool expect_ec) +{ +#ifdef RB_THREAD_LOCAL_SPECIFIER + #ifdef RB_THREAD_CURRENT_EC_NOINLINE + rb_execution_context_t * volatile ec = rb_current_ec(); + #else + rb_execution_context_t * volatile ec = ruby_current_ec; + #endif + + /* On the shared objects, `__tls_get_addr()` is used to access the TLS + * and the address of the `ruby_current_ec` can be stored on a function + * frame. However, this address can be mis-used after native thread + * migration of a coroutine. + * 1) Get `ptr =&ruby_current_ec` op NT1 and store it on the frame. + * 2) Context switch and resume it on the NT2. + * 3) `ptr` is used on NT2 but it accesses to the TLS on NT1. + * This assertion checks such misusage. + * + * To avoid accidents, `GET_EC()` should be called once on the frame. + * Note that inlining can produce the problem. + */ + VM_ASSERT(ec == rb_current_ec_noinline()); +#else + rb_execution_context_t * volatile ec = native_tls_get(ruby_current_ec_key); +#endif + VM_ASSERT(!expect_ec || ec != NULL); + return ec; +} + +static inline rb_thread_t * +rb_current_thread(void) +{ + const rb_execution_context_t *ec = GET_EC(); + return rb_ec_thread_ptr(ec); +} + +static inline rb_ractor_t * +rb_current_ractor_raw(bool expect) +{ + if (ruby_single_main_ractor) { + return ruby_single_main_ractor; + } + else { + const rb_execution_context_t *ec = rb_current_execution_context(expect); + return (expect || ec) ? rb_ec_ractor_ptr(ec) : NULL; + } +} + +static inline rb_ractor_t * +rb_current_ractor(void) +{ + return rb_current_ractor_raw(true); +} + +static inline rb_vm_t * +rb_current_vm(void) +{ +#if 0 // TODO: reconsider the assertions + VM_ASSERT(ruby_current_vm_ptr == NULL || + ruby_current_execution_context_ptr == NULL || + rb_ec_thread_ptr(GET_EC()) == NULL || + rb_ec_thread_ptr(GET_EC())->status == THREAD_KILLED || + rb_ec_vm_ptr(GET_EC()) == ruby_current_vm_ptr); +#endif + + return ruby_current_vm_ptr; +} + +void rb_ec_vm_lock_rec_release(const rb_execution_context_t *ec, + unsigned int recorded_lock_rec, + unsigned int current_lock_rec); + +/* This technically is a data race, as it's checked without the lock, however we + * check against a value only our own thread will write. */ +NO_SANITIZE("thread", static inline bool +vm_locked_by_ractor_p(rb_vm_t *vm, rb_ractor_t *cr)) +{ + VM_ASSERT(cr == GET_RACTOR()); + return vm->ractor.sync.lock_owner == cr; +} + +static inline unsigned int +rb_ec_vm_lock_rec(const rb_execution_context_t *ec) +{ + rb_vm_t *vm = rb_ec_vm_ptr(ec); + + if (!vm_locked_by_ractor_p(vm, rb_ec_ractor_ptr(ec))) { + return 0; + } + else { + return vm->ractor.sync.lock_rec; + } +} + +#else +#error "unsupported thread model" +#endif + +enum { + TIMER_INTERRUPT_MASK = 0x01, + PENDING_INTERRUPT_MASK = 0x02, + POSTPONED_JOB_INTERRUPT_MASK = 0x04, + TRAP_INTERRUPT_MASK = 0x08, + TERMINATE_INTERRUPT_MASK = 0x10, + VM_BARRIER_INTERRUPT_MASK = 0x20, +}; + +#define RUBY_VM_SET_TIMER_INTERRUPT(ec) ATOMIC_OR((ec)->interrupt_flag, TIMER_INTERRUPT_MASK) +#define RUBY_VM_SET_INTERRUPT(ec) ATOMIC_OR((ec)->interrupt_flag, PENDING_INTERRUPT_MASK) +#define RUBY_VM_SET_POSTPONED_JOB_INTERRUPT(ec) ATOMIC_OR((ec)->interrupt_flag, POSTPONED_JOB_INTERRUPT_MASK) +#define RUBY_VM_SET_TRAP_INTERRUPT(ec) ATOMIC_OR((ec)->interrupt_flag, TRAP_INTERRUPT_MASK) +#define RUBY_VM_SET_TERMINATE_INTERRUPT(ec) ATOMIC_OR((ec)->interrupt_flag, TERMINATE_INTERRUPT_MASK) +#define RUBY_VM_SET_VM_BARRIER_INTERRUPT(ec) ATOMIC_OR((ec)->interrupt_flag, VM_BARRIER_INTERRUPT_MASK) + +static inline bool +RUBY_VM_INTERRUPTED(rb_execution_context_t *ec) +{ + return (ATOMIC_LOAD_RELAXED(ec->interrupt_flag) & ~(ec->interrupt_mask) & (PENDING_INTERRUPT_MASK|TRAP_INTERRUPT_MASK)); +} + +static inline bool +RUBY_VM_INTERRUPTED_ANY(rb_execution_context_t *ec) +{ +#if defined(USE_VM_CLOCK) && USE_VM_CLOCK + uint32_t current_clock = rb_ec_vm_ptr(ec)->clock; + + if (current_clock != ec->checked_clock) { + ec->checked_clock = current_clock; + RUBY_VM_SET_TIMER_INTERRUPT(ec); + } +#endif + return ATOMIC_LOAD_RELAXED(ec->interrupt_flag) & ~(ec)->interrupt_mask; +} + +VALUE rb_exc_set_backtrace(VALUE exc, VALUE bt); +int rb_signal_buff_size(void); +int rb_signal_exec(rb_thread_t *th, int sig); +void rb_threadptr_check_signal(rb_thread_t *mth); +void rb_threadptr_signal_raise(rb_thread_t *th, int sig); +void rb_threadptr_signal_exit(rb_thread_t *th); +int rb_threadptr_execute_interrupts(rb_thread_t *, int); +void rb_threadptr_interrupt(rb_thread_t *th); +void rb_threadptr_unlock_all_locking_mutexes(rb_thread_t *th); +void rb_threadptr_pending_interrupt_clear(rb_thread_t *th); +void rb_threadptr_pending_interrupt_enque(rb_thread_t *th, VALUE v); +VALUE rb_ec_get_errinfo(const rb_execution_context_t *ec); +void rb_ec_error_print(rb_execution_context_t * volatile ec, volatile VALUE errinfo); +void rb_execution_context_update(rb_execution_context_t *ec); +void rb_execution_context_mark(const rb_execution_context_t *ec); +void rb_fiber_close(rb_fiber_t *fib); +void Init_native_thread(rb_thread_t *th); +int rb_vm_check_ints_blocking(rb_execution_context_t *ec); + +// vm_sync.h +void rb_vm_cond_wait(rb_vm_t *vm, rb_nativethread_cond_t *cond); +void rb_vm_cond_timedwait(rb_vm_t *vm, rb_nativethread_cond_t *cond, unsigned long msec); + +#define RUBY_VM_CHECK_INTS(ec) rb_vm_check_ints(ec) +static inline void +rb_vm_check_ints(rb_execution_context_t *ec) +{ +#ifdef RUBY_ASSERT_CRITICAL_SECTION + VM_ASSERT(ruby_assert_critical_section_entered == 0); +#endif + + VM_ASSERT(ec == rb_current_ec_noinline()); + + if (UNLIKELY(RUBY_VM_INTERRUPTED_ANY(ec))) { + rb_threadptr_execute_interrupts(rb_ec_thread_ptr(ec), 0); + } +} + +/* tracer */ + +struct rb_trace_arg_struct { + rb_event_flag_t event; + rb_execution_context_t *ec; + const rb_control_frame_t *cfp; + VALUE self; + ID id; + ID called_id; + VALUE klass; + VALUE data; + + int klass_solved; + + /* calc from cfp */ + int lineno; + VALUE path; +}; + +void rb_hook_list_mark(rb_hook_list_t *hooks); +void rb_hook_list_mark_and_move(rb_hook_list_t *hooks); +void rb_hook_list_free(rb_hook_list_t *hooks); +void rb_hook_list_connect_tracepoint(VALUE target, rb_hook_list_t *list, VALUE tpval, unsigned int target_line); +void rb_hook_list_remove_tracepoint(rb_hook_list_t *list, VALUE tpval); + +void rb_exec_event_hooks(struct rb_trace_arg_struct *trace_arg, rb_hook_list_t *hooks, int pop_p); + +#define EXEC_EVENT_HOOK_ORIG(ec_, hooks_, flag_, self_, id_, called_id_, klass_, data_, pop_p_) do { \ + const rb_event_flag_t flag_arg_ = (flag_); \ + rb_hook_list_t *hooks_arg_ = (hooks_); \ + if (UNLIKELY((hooks_arg_)->events & (flag_arg_))) { \ + /* defer evaluating the other arguments */ \ + rb_exec_event_hook_orig(ec_, hooks_arg_, flag_arg_, self_, id_, called_id_, klass_, data_, pop_p_); \ + } \ +} while (0) + +static inline void +rb_exec_event_hook_orig(rb_execution_context_t *ec, rb_hook_list_t *hooks, rb_event_flag_t flag, + VALUE self, ID id, ID called_id, VALUE klass, VALUE data, int pop_p) +{ + struct rb_trace_arg_struct trace_arg; + + VM_ASSERT((hooks->events & flag) != 0); + + trace_arg.event = flag; + trace_arg.ec = ec; + trace_arg.cfp = ec->cfp; + trace_arg.self = self; + trace_arg.id = id; + trace_arg.called_id = called_id; + trace_arg.klass = klass; + trace_arg.data = data; + trace_arg.path = Qundef; + trace_arg.klass_solved = 0; + + rb_exec_event_hooks(&trace_arg, hooks, pop_p); +} + +struct rb_ractor_pub { + VALUE self; + uint32_t id; + rb_hook_list_t hooks; +}; + +static inline rb_hook_list_t * +rb_ec_ractor_hooks(const rb_execution_context_t *ec) +{ + struct rb_ractor_pub *cr_pub = (struct rb_ractor_pub *)rb_ec_ractor_ptr(ec); + return &cr_pub->hooks; +} + +#define EXEC_EVENT_HOOK(ec_, flag_, self_, id_, called_id_, klass_, data_) \ + EXEC_EVENT_HOOK_ORIG(ec_, rb_ec_ractor_hooks(ec_), flag_, self_, id_, called_id_, klass_, data_, 0) + +#define EXEC_EVENT_HOOK_AND_POP_FRAME(ec_, flag_, self_, id_, called_id_, klass_, data_) \ + EXEC_EVENT_HOOK_ORIG(ec_, rb_ec_ractor_hooks(ec_), flag_, self_, id_, called_id_, klass_, data_, 1) + +static inline void +rb_exec_event_hook_script_compiled(rb_execution_context_t *ec, const rb_iseq_t *iseq, VALUE eval_script) +{ + EXEC_EVENT_HOOK(ec, RUBY_EVENT_SCRIPT_COMPILED, ec->cfp->self, 0, 0, 0, + NIL_P(eval_script) ? (VALUE)iseq : + rb_ary_new_from_args(2, eval_script, (VALUE)iseq)); +} + +void rb_vm_trap_exit(rb_vm_t *vm); +void rb_vm_postponed_job_atfork(void); /* vm_trace.c */ +void rb_vm_postponed_job_free(void); /* vm_trace.c */ +size_t rb_vm_memsize_postponed_job_queue(void); /* vm_trace.c */ +void rb_vm_postponed_job_queue_init(rb_vm_t *vm); /* vm_trace.c */ + +RUBY_SYMBOL_EXPORT_BEGIN + +int rb_thread_check_trap_pending(void); + +/* #define RUBY_EVENT_RESERVED_FOR_INTERNAL_USE 0x030000 */ /* from vm_core.h */ +#define RUBY_EVENT_COVERAGE_LINE 0x010000 +#define RUBY_EVENT_COVERAGE_BRANCH 0x020000 + +extern VALUE rb_get_coverages(void); +extern void rb_set_coverages(VALUE, int, VALUE); +extern void rb_clear_coverages(void); +extern void rb_reset_coverages(void); +extern void rb_resume_coverages(void); +extern void rb_suspend_coverages(void); + +void rb_postponed_job_flush(rb_vm_t *vm); + +// ractor.c +RUBY_EXTERN VALUE rb_eRactorUnsafeError; +RUBY_EXTERN VALUE rb_eRactorIsolationError; + +RUBY_SYMBOL_EXPORT_END + +#endif /* RUBY_VM_CORE_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/vm_debug.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/vm_debug.h new file mode 100644 index 0000000..d0bc815 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/vm_debug.h @@ -0,0 +1,124 @@ +#ifndef RUBY_DEBUG_H +#define RUBY_DEBUG_H +/********************************************************************** + + vm_debug.h - YARV Debug function interface + + $Author$ + created at: 04/08/25 02:33:49 JST + + Copyright (C) 2004-2007 Koichi Sasada + +**********************************************************************/ + +#include "ruby/ruby.h" + +RUBY_SYMBOL_EXPORT_BEGIN + +#define dpv(h,v) ruby_debug_print_value(-1, 0, (h), (v)) +#define dp(v) ruby_debug_print_value(-1, 0, "", (v)) +#define dpi(i) ruby_debug_print_id(-1, 0, "", (i)) +#define dpn(n) ruby_debug_print_node(-1, 0, "", (n)) + +struct RNode; + +VALUE ruby_debug_print_value(int level, int debug_level, const char *header, VALUE v); +void ruby_debug_print_v(VALUE v); +ID ruby_debug_print_id(int level, int debug_level, const char *header, ID id); +struct RNode *ruby_debug_print_node(int level, int debug_level, const char *header, const struct RNode *node); +void ruby_debug_print_n(const struct RNode *node); +int ruby_debug_print_indent(int level, int debug_level, int indent_level); +void ruby_debug_gc_check_func(void); +void ruby_set_debug_option(const char *str); + +RUBY_SYMBOL_EXPORT_END + +#ifndef USE_RUBY_DEBUG_LOG +#define USE_RUBY_DEBUG_LOG 0 +#endif + +/* RUBY_DEBUG_LOG: Logging debug information mechanism + * + * This feature provides a mechanism to store logging information + * to a file, stderr or memory space with simple macros. + * + * The following information will be stored. + * * (1) __FILE__, __LINE__ in C + * * (2) __FILE__, __LINE__ in Ruby + * * (3) __func__ in C (message title) + * * (4) given string with sprintf format + * * (5) Thread number (if multiple threads are running) + * + * This feature is enabled only USE_RUBY_DEBUG_LOG is enabled. + * Release version should not enable it. + * + * Running with the `RUBY_DEBUG_LOG` environment variable enables + * this feature. + * + * # logging into a file + * RUBY_DEBUG_LOG=/path/to/file STDERR + * + * # logging into STDERR + * RUBY_DEBUG_LOG=stderr + * + * # logging into memory space (check with a debugger) + * # It will help if the timing is important. + * RUBY_DEBUG_LOG=mem + * + * RUBY_DEBUG_LOG_FILTER environment variable can specify the filter string. + * If "(3) __func__ in C (message title)" contains the specified string, the + * information will be stored (example: RUBY_DEBUG_LOG_FILTER=str will enable + * only on str related information). + * + * In a MRI source code, you can use the following macros: + * * RUBY_DEBUG_LOG(fmt, ...): Above (1) to (4) will be logged. + * * RUBY_DEBUG_LOG2(file, line, fmt, ...): + * Same as RUBY_DEBUG_LOG(), but (1) will be replaced with given file, line. + */ + +extern enum ruby_debug_log_mode { + ruby_debug_log_disabled = 0x00, + ruby_debug_log_memory = 0x01, + ruby_debug_log_stderr = 0x02, + ruby_debug_log_file = 0x04, +} ruby_debug_log_mode; + +RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 4, 5) +void ruby_debug_log(const char *file, int line, const char *func_name, const char *fmt, ...); +void ruby_debug_log_print(unsigned int n); +bool ruby_debug_log_filter(const char *func_name, const char *file_name); + +#if RBIMPL_COMPILER_IS(GCC) && defined(__OPTIMIZE__) +# define ruby_debug_log(...) \ + RB_GNUC_EXTENSION_BLOCK( \ + RBIMPL_WARNING_PUSH(); \ + RBIMPL_WARNING_IGNORED(-Wformat-zero-length); \ + ruby_debug_log(__VA_ARGS__); \ + RBIMPL_WARNING_POP()) +#endif + +// convenient macro to log even if the USE_RUBY_DEBUG_LOG macro is not specified. +// You can use this macro for temporary usage (you should not commit it). +#define _RUBY_DEBUG_LOG(...) ruby_debug_log(__FILE__, __LINE__, RUBY_FUNCTION_NAME_STRING, "" __VA_ARGS__) + +#if USE_RUBY_DEBUG_LOG +# define RUBY_DEBUG_LOG_ENABLED(func_name, file_name) \ + (ruby_debug_log_mode && ruby_debug_log_filter(func_name, file_name)) + +#define RUBY_DEBUG_LOG(...) do { \ + if (RUBY_DEBUG_LOG_ENABLED(RUBY_FUNCTION_NAME_STRING, __FILE__)) \ + ruby_debug_log(__FILE__, __LINE__, RUBY_FUNCTION_NAME_STRING, "" __VA_ARGS__); \ +} while (0) + +#define RUBY_DEBUG_LOG2(file, line, ...) do { \ + if (RUBY_DEBUG_LOG_ENABLED(RUBY_FUNCTION_NAME_STRING, file)) \ + ruby_debug_log(file, line, RUBY_FUNCTION_NAME_STRING, "" __VA_ARGS__); \ +} while (0) + +#else // USE_RUBY_DEBUG_LOG +// do nothing +#define RUBY_DEBUG_LOG(...) +#define RUBY_DEBUG_LOG2(file, line, ...) +#endif // USE_RUBY_DEBUG_LOG + +#endif /* RUBY_DEBUG_H */ diff --git a/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/vm_opts.h b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/vm_opts.h new file mode 100644 index 0000000..ce47745 --- /dev/null +++ b/lib/datadog/ruby_core_source/ruby-4.0.0-preview2/vm_opts.h @@ -0,0 +1,67 @@ +#ifndef RUBY_VM_OPTS_H/*-*-c-*-*/ +#define RUBY_VM_OPTS_H +/********************************************************************** + + vm_opts.h - VM optimize option + + $Author$ + + Copyright (C) 2004-2007 Koichi Sasada + +**********************************************************************/ + +/* Compile options. + * You can change these options at runtime by VM::CompileOption. + * Following definitions are default values. + */ + +#define OPT_TAILCALL_OPTIMIZATION 0 +#define OPT_PEEPHOLE_OPTIMIZATION 1 +#define OPT_SPECIALISED_INSTRUCTION 1 +#define OPT_INLINE_CONST_CACHE 1 +#define OPT_FROZEN_STRING_LITERAL -1 +#define OPT_DEBUG_FROZEN_STRING_LITERAL 0 + +/* Build Options. + * You can't change these options at runtime. + */ + +/* C compiler dependent */ + +/* + * 0: direct (using labeled goto using GCC special) + * 1: token (switch/case) + * 2: call (function call for each insn dispatch) + */ +#ifndef OPT_THREADED_CODE +#define OPT_THREADED_CODE 0 +#endif + +#define OPT_DIRECT_THREADED_CODE (OPT_THREADED_CODE == 0) +#define OPT_TOKEN_THREADED_CODE (OPT_THREADED_CODE == 1) +#define OPT_CALL_THREADED_CODE (OPT_THREADED_CODE == 2) + +/* VM running option */ +#define OPT_CHECKED_RUN 1 +#define OPT_INLINE_METHOD_CACHE 1 +#define OPT_GLOBAL_METHOD_CACHE 1 + +#ifndef OPT_IC_FOR_IVAR +#define OPT_IC_FOR_IVAR 1 +#endif + +/* architecture independent, affects generated code */ +#define OPT_OPERANDS_UNIFICATION 1 +#define OPT_INSTRUCTIONS_UNIFICATION 0 +#define OPT_UNIFY_ALL_COMBINATION 0 + +/* misc */ +#ifndef OPT_SUPPORT_JOKE +#define OPT_SUPPORT_JOKE 0 +#endif + +#ifndef VM_COLLECT_USAGE_DETAILS +#define VM_COLLECT_USAGE_DETAILS 0 +#endif + +#endif /* RUBY_VM_OPTS_H */