diff --git a/.gitignore b/.gitignore
index c8319fc9e2bbd2..11e635412d5d94 100644
--- a/.gitignore
+++ b/.gitignore
@@ -268,6 +268,7 @@ lcov*.info
/prism/api_node.c
/prism/ast.h
/prism/diagnostic.c
+/prism/json.c
/prism/node.c
/prism/prettyprint.c
/prism/serialize.c
diff --git a/configure.ac b/configure.ac
index b9d465e0494d09..2a732c1d30eb21 100644
--- a/configure.ac
+++ b/configure.ac
@@ -115,6 +115,9 @@ AC_ARG_WITH(dump-ast,
AS_HELP_STRING([--with-dump-ast=DUMP_AST], [use DUMP_AST as dump_ast; for cross-compiling with a host-built dump_ast]),
[DUMP_AST=$withval DUMP_AST_TARGET='$(empty)'],
[DUMP_AST='./dump_ast$(EXEEXT)' DUMP_AST_TARGET='$(DUMP_AST)'])
+dnl Without baseruby, .rbinc files cannot be regenerated, so clear the
+dnl dependency on dump_ast to avoid rebuilding pre-generated .rbinc files.
+AS_IF([test "$HAVE_BASERUBY" = no], [DUMP_AST_TARGET='$(empty)'])
AC_SUBST(X_DUMP_AST, "${DUMP_AST}")
AC_SUBST(X_DUMP_AST_TARGET, "${DUMP_AST_TARGET}")
diff --git a/doc/extension.rdoc b/doc/extension.rdoc
index 18dc5817d45830..4be150c9f5d7c8 100644
--- a/doc/extension.rdoc
+++ b/doc/extension.rdoc
@@ -317,11 +317,11 @@ rb_ary_aref(int argc, const VALUE *argv, VALUE ary) ::
rb_ary_entry(VALUE ary, long offset) ::
- \ary[offset]
+ ary\[offset]
rb_ary_store(VALUE ary, long offset, VALUE obj) ::
- \ary[offset] = obj
+ ary\[offset] = obj
rb_ary_subseq(VALUE ary, long beg, long len) ::
diff --git a/iseq.c b/iseq.c
index 9a0c66490d2221..6f87b2df3e085b 100644
--- a/iseq.c
+++ b/iseq.c
@@ -1096,41 +1096,15 @@ rb_iseq_new_with_opt(VALUE ast_value, VALUE name, VALUE path, VALUE realpath,
return iseq_translate(iseq);
}
-struct pm_iseq_new_with_opt_data {
- rb_iseq_t *iseq;
- pm_scope_node_t *node;
-};
-
-VALUE
-pm_iseq_new_with_opt_try(VALUE d)
-{
- struct pm_iseq_new_with_opt_data *data = (struct pm_iseq_new_with_opt_data *)d;
-
- // This can compile child iseqs, which can raise syntax errors
- pm_iseq_compile_node(data->iseq, data->node);
-
- // This raises an exception if there is a syntax error
- finish_iseq_build(data->iseq);
-
- return Qundef;
-}
-
/**
- * This is a step in the prism compiler that is called once all of the various
- * options have been established. It is called from one of the pm_iseq_new_*
- * functions or from the RubyVM::InstructionSequence APIs. It is responsible for
- * allocating the instruction sequence, calling into the compiler, and returning
- * the built instruction sequence.
- *
- * Importantly, this is also the function where the compiler is re-entered to
- * compile child instruction sequences. A child instruction sequence is always
- * compiled using a scope node, which is why we cast it explicitly to that here
- * in the parameters (as opposed to accepting a generic pm_node_t *).
+ * Core implementation for building a prism iseq. This does not use rb_protect,
+ * so any exceptions (e.g. from finish_iseq_build) propagate normally up the
+ * call stack — matching the parse.y compiler's behavior.
*/
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 type, const rb_compile_option_t *option, int *error_state)
+pm_iseq_build(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 type, const rb_compile_option_t *option)
{
rb_iseq_t *iseq = iseq_alloc();
ISEQ_BODY(iseq)->prism = true;
@@ -1157,15 +1131,59 @@ pm_iseq_new_with_opt(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpa
prepare_iseq_build(iseq, name, path, realpath, first_lineno, &code_location, node->ast_node->node_id,
parent, isolated_depth, type, node->script_lines == NULL ? Qnil : *node->script_lines, option);
+ pm_iseq_compile_node(iseq, node);
+ finish_iseq_build(iseq);
+
+ return iseq_translate(iseq);
+}
+
+struct pm_iseq_new_with_opt_data {
+ rb_iseq_t *iseq;
+ pm_scope_node_t *node;
+ VALUE name, path, realpath;
+ int first_lineno, isolated_depth;
+ const rb_iseq_t *parent;
+ enum rb_iseq_type type;
+ const rb_compile_option_t *option;
+};
+
+static VALUE
+pm_iseq_new_with_opt_try(VALUE d)
+{
+ struct pm_iseq_new_with_opt_data *data = (struct pm_iseq_new_with_opt_data *)d;
+ data->iseq = pm_iseq_build(data->node, data->name, data->path, data->realpath,
+ data->first_lineno, data->parent, data->isolated_depth,
+ data->type, data->option);
+ return Qundef;
+}
+
+/**
+ * This is a step in the prism compiler that is called once all of the various
+ * options have been established. It is called from one of the pm_iseq_new_*
+ * functions or from the RubyVM::InstructionSequence APIs.
+ *
+ * This function uses rb_protect to catch exceptions, storing the error state
+ * in the provided out parameter. This is only needed at top-level entry points
+ * where the caller wants to handle errors gracefully. Child iseqs compiled
+ * during the compilation process do NOT go through this function — they use
+ * pm_iseq_build directly, letting exceptions propagate naturally (matching
+ * the parse.y compiler's behavior).
+ */
+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 type, const rb_compile_option_t *option, int *error_state)
+{
struct pm_iseq_new_with_opt_data data = {
- .iseq = iseq,
- .node = node
+ .node = node, .name = name, .path = path, .realpath = realpath,
+ .first_lineno = first_lineno, .parent = parent,
+ .isolated_depth = isolated_depth, .type = type, .option = option
};
rb_protect(pm_iseq_new_with_opt_try, (VALUE)&data, error_state);
if (*error_state) return NULL;
- return iseq_translate(iseq);
+ return data.iseq;
}
rb_iseq_t *
diff --git a/lib/prism.rb b/lib/prism.rb
index 6b34ab12bfc6e5..8f0342724a30d3 100644
--- a/lib/prism.rb
+++ b/lib/prism.rb
@@ -23,6 +23,7 @@ module Prism
autoload :InspectVisitor, "prism/inspect_visitor"
autoload :LexCompat, "prism/lex_compat"
autoload :MutationCompiler, "prism/mutation_compiler"
+ autoload :NodeFind, "prism/node_find"
autoload :Pattern, "prism/pattern"
autoload :Reflection, "prism/reflection"
autoload :Relocation, "prism/relocation"
@@ -34,7 +35,10 @@ module Prism
# Some of these constants are not meant to be exposed, so marking them as
# private here.
- private_constant :LexCompat
+ if RUBY_ENGINE != "jruby"
+ private_constant :LexCompat
+ private_constant :NodeFind
+ end
# Raised when requested to parse as the currently running Ruby version but Prism has no support for it.
class CurrentVersionError < ArgumentError
@@ -81,6 +85,16 @@ def self.load(source, serialized, freeze = false)
Serialize.load_parse(source, serialized, freeze)
end
+ # Given a Method, UnboundMethod, Proc, or Thread::Backtrace::Location,
+ # returns the Prism node representing it. On CRuby, this uses node_id for
+ # an exact match. On other implementations, it falls back to best-effort
+ # matching by source location line number.
+ #--
+ #: (Method | UnboundMethod | Proc | Thread::Backtrace::Location callable, ?rubyvm: bool) -> Node?
+ def self.find(callable, rubyvm: !!defined?(RubyVM))
+ NodeFind.find(callable, rubyvm)
+ end
+
# @rbs!
# VERSION: String
# BACKEND: :CEXT | :FFI
diff --git a/lib/prism/node_find.rb b/lib/prism/node_find.rb
new file mode 100644
index 00000000000000..697ee430e8b90e
--- /dev/null
+++ b/lib/prism/node_find.rb
@@ -0,0 +1,185 @@
+# frozen_string_literal: true
+# :markup: markdown
+#--
+# rbs_inline: enabled
+
+module Prism
+ # Finds the Prism AST node corresponding to a given Method, UnboundMethod,
+ # Proc, or Thread::Backtrace::Location. On CRuby, uses node_id from the
+ # instruction sequence for an exact match. On other implementations, falls
+ # back to best-effort matching by source location line number.
+ #
+ # This module is autoloaded so that programs that don't use Prism.find don't
+ # pay for its definition.
+ module NodeFind # :nodoc:
+ # Find the node for the given callable or backtrace location.
+ #--
+ #: (Method | UnboundMethod | Proc | Thread::Backtrace::Location callable, bool rubyvm) -> Node?
+ def self.find(callable, rubyvm)
+ case callable
+ when Proc
+ if rubyvm
+ RubyVMCallableFind.new.find(callable)
+ elsif callable.lambda?
+ LineLambdaFind.new.find(callable)
+ else
+ LineProcFind.new.find(callable)
+ end
+ when Method, UnboundMethod
+ if rubyvm
+ RubyVMCallableFind.new.find(callable)
+ else
+ LineMethodFind.new.find(callable)
+ end
+ when Thread::Backtrace::Location
+ if rubyvm
+ RubyVMBacktraceLocationFind.new.find(callable)
+ else
+ LineBacktraceLocationFind.new.find(callable)
+ end
+ else
+ raise ArgumentError, "Expected a Method, UnboundMethod, Proc, or Thread::Backtrace::Location, got #{callable.class}"
+ end
+ end
+
+ # Base class that handles parsing a file.
+ class Find
+ private
+
+ # Parse the given file path, returning a ParseResult or nil.
+ #--
+ #: (String? file) -> ParseResult?
+ def parse_file(file)
+ return unless file && File.readable?(file)
+ result = Prism.parse_file(file)
+ result if result.success?
+ end
+ end
+
+ # Finds the AST node for a Method, UnboundMethod, or Proc using the node_id
+ # from the instruction sequence.
+ class RubyVMCallableFind < Find
+ # Find the node for the given callable using the ISeq node_id.
+ #--
+ #: (Method | UnboundMethod | Proc callable) -> Node?
+ def find(callable)
+ return unless (source_location = callable.source_location)
+ return unless (result = parse_file(source_location[0]))
+ return unless (iseq = RubyVM::InstructionSequence.of(callable))
+
+ header = iseq.to_a[4]
+ return unless header[:parser] == :prism
+
+ result.value.find { |node| node.node_id == header[:node_id] }
+ end
+ end
+
+ # Finds the AST node for a Thread::Backtrace::Location using the node_id
+ # from the backtrace location.
+ class RubyVMBacktraceLocationFind < Find
+ # Find the node for the given backtrace location using node_id.
+ #--
+ #: (Thread::Backtrace::Location location) -> Node?
+ def find(location)
+ file = location.absolute_path || location.path
+ return unless (result = parse_file(file))
+ return unless RubyVM::AbstractSyntaxTree.respond_to?(:node_id_for_backtrace_location)
+
+ node_id = RubyVM::AbstractSyntaxTree.node_id_for_backtrace_location(location)
+
+ result.value.find { |node| node.node_id == node_id }
+ end
+ end
+
+ # Finds the AST node for a Method or UnboundMethod using best-effort line
+ # matching. Used on non-CRuby implementations.
+ class LineMethodFind < Find
+ # Find the node for the given method by matching on name and line.
+ #--
+ #: (Method | UnboundMethod callable) -> Node?
+ def find(callable)
+ return unless (source_location = callable.source_location)
+ return unless (result = parse_file(source_location[0]))
+
+ name = callable.name
+ start_line = source_location[1]
+
+ result.value.find do |node|
+ case node
+ when DefNode
+ node.name == name && node.location.start_line == start_line
+ when CallNode
+ node.block.is_a?(BlockNode) && node.location.start_line == start_line
+ else
+ false
+ end
+ end
+ end
+ end
+
+ # Finds the AST node for a lambda using best-effort line matching. Used
+ # on non-CRuby implementations.
+ class LineLambdaFind < Find
+ # Find the node for the given lambda by matching on line.
+ #--
+ #: (Proc callable) -> Node?
+ def find(callable)
+ return unless (source_location = callable.source_location)
+ return unless (result = parse_file(source_location[0]))
+
+ start_line = source_location[1]
+
+ result.value.find do |node|
+ case node
+ when LambdaNode
+ node.location.start_line == start_line
+ when CallNode
+ node.block.is_a?(BlockNode) && node.location.start_line == start_line
+ else
+ false
+ end
+ end
+ end
+ end
+
+ # Finds the AST node for a non-lambda Proc using best-effort line
+ # matching. Used on non-CRuby implementations.
+ class LineProcFind < Find
+ # Find the node for the given proc by matching on line.
+ #--
+ #: (Proc callable) -> Node?
+ def find(callable)
+ return unless (source_location = callable.source_location)
+ return unless (result = parse_file(source_location[0]))
+
+ start_line = source_location[1]
+
+ result.value.find do |node|
+ case node
+ when ForNode
+ node.location.start_line == start_line
+ when CallNode
+ node.block.is_a?(BlockNode) && node.location.start_line == start_line
+ else
+ false
+ end
+ end
+ end
+ end
+
+ # Finds the AST node for a Thread::Backtrace::Location using best-effort
+ # line matching. Used on non-CRuby implementations.
+ class LineBacktraceLocationFind < Find
+ # Find the node for the given backtrace location by matching on line.
+ #--
+ #: (Thread::Backtrace::Location location) -> Node?
+ def find(location)
+ file = location.absolute_path || location.path
+ return unless (result = parse_file(file))
+
+ start_line = location.lineno
+ result.value.find { |node| node.location.start_line == start_line }
+ end
+ end
+ end
+end
diff --git a/lib/prism/parse_result.rb b/lib/prism/parse_result.rb
index 4d1fa2c2965121..4f7bcf07d6bd01 100644
--- a/lib/prism/parse_result.rb
+++ b/lib/prism/parse_result.rb
@@ -26,7 +26,8 @@ class Source
# source is a subset of a larger source or if this is an eval. offsets is an
# array of byte offsets for the start of each line in the source code, which
# can be calculated by iterating through the source code and recording the
- # byte offset whenever a newline character is encountered.
+ # byte offset whenever a newline character is encountered. The first
+ # element is always 0 to mark the first line.
#--
#: (String source, Integer start_line, Array[Integer] offsets) -> Source
def self.for(source, start_line, offsets)
diff --git a/lib/prism/prism.gemspec b/lib/prism/prism.gemspec
index d489a37af4798d..aac056b3f889e8 100644
--- a/lib/prism/prism.gemspec
+++ b/lib/prism/prism.gemspec
@@ -117,6 +117,7 @@ Gem::Specification.new do |spec|
"lib/prism/lex_compat.rb",
"lib/prism/mutation_compiler.rb",
"lib/prism/node_ext.rb",
+ "lib/prism/node_find.rb",
"lib/prism/node.rb",
"lib/prism/parse_result.rb",
"lib/prism/parse_result/comments.rb",
@@ -158,6 +159,7 @@ Gem::Specification.new do |spec|
"rbi/generated/prism/mutation_compiler.rbi",
"rbi/generated/prism/node.rbi",
"rbi/generated/prism/node_ext.rbi",
+ "rbi/generated/prism/node_find.rbi",
"rbi/generated/prism/parse_result.rbi",
"rbi/generated/prism/pattern.rbi",
"rbi/generated/prism/reflection.rbi",
@@ -172,6 +174,7 @@ Gem::Specification.new do |spec|
"rbi/prism/translation/parser.rbi",
"rbi/prism/translation/parser_versions.rbi",
"rbi/prism/translation/ripper.rbi",
+ "rbi/rubyvm/node_find.rbi",
"sig/generated/prism.rbs",
"sig/generated/prism/compiler.rbs",
"sig/generated/prism/desugar_compiler.rbs",
@@ -183,6 +186,7 @@ Gem::Specification.new do |spec|
"sig/generated/prism/mutation_compiler.rbs",
"sig/generated/prism/node.rbs",
"sig/generated/prism/node_ext.rbs",
+ "sig/generated/prism/node_find.rbs",
"sig/generated/prism/parse_result.rbs",
"sig/generated/prism/pattern.rbs",
"sig/generated/prism/reflection.rbs",
diff --git a/pathname_builtin.rb b/pathname_builtin.rb
index c85a865d1a8d86..d69707e34a7dd3 100644
--- a/pathname_builtin.rb
+++ b/pathname_builtin.rb
@@ -236,10 +236,18 @@ def freeze
self
end
+ # call-seq:
+ # self == other -> true or false
+ #
+ # Returns whether the stored paths in +self+ and +other+ are equal:
+ #
+ # pn = Pathname.new('lib')
+ # pn == Pathname.new('lib') # => true
+ # pn == Pathname.new('./lib') # => false
#
- # Compare this pathname with +other+. The comparison is string-based.
- # Be aware that two different paths (foo.txt and ./foo.txt)
- # can refer to the same file.
+ # Returns +false+ if +other+ is not a pathname:
+ #
+ # pn == 'lib' # => false
#
def ==(other)
return false unless Pathname === other
@@ -628,17 +636,19 @@ def root?
chop_basename(@path) == nil && SEPARATOR_PAT.match?(@path)
end
- # Predicate method for testing whether a path is absolute.
+ # call-seq:
+ # absolute? -> true or false
#
- # It returns +true+ if the pathname begins with a slash.
+ # Returns whether +self+ contains an absolute path:
#
- # p = Pathname.new('/im/sure')
- # p.absolute?
- # #=> true
+ # Pathname.new('/home').absolute? # => true
+ # Pathname.new('lib').absolute? # => false
+ #
+ # OS-dependent for some paths:
+ #
+ # Pathname.new('C:/').absolute? # => true # On Windows.
+ # Pathname.new('C:/').absolute? # => false # Elsewhere.
#
- # p = Pathname.new('not/so/sure')
- # p.absolute?
- # #=> false
def absolute?
ABSOLUTE_PATH.match? @path
end
@@ -750,8 +760,14 @@ def ascend
# call-seq:
# self + other -> new_pathname
#
- # Returns a new \Pathname object;
- # argument +other+ may be a string or another pathname.
+ # Returns a new \Pathname object based on the content of +self+ and +other+;
+ # argument +other+ may be a String, a File, a Dir, or another \Pathname:
+ #
+ # pn = Pathname.new('foo') # => #
+ # pn + 'bar' # => #
+ # pn + File.new('LEGAL') # => #
+ # pn + Dir.new('lib') # => #
+ # pn + Pathname.new('bar') # => #
#
# When +other+ specifies a relative path (see #relative?),
# it is combined with +self+ to form a new pathname:
diff --git a/prism/json.c b/prism/json.c
deleted file mode 100644
index 72975db72480d7..00000000000000
--- a/prism/json.c
+++ /dev/null
@@ -1,5723 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* This file is generated by the templates/template.rb script and should not */
-/* be modified manually. See */
-/* templates/src/json.c.erb */
-/* if you are looking to modify the */
-/* template */
-/*----------------------------------------------------------------------------*/
-
-#include "prism/json.h"
-
-// Ensure this translation unit is never empty, even when JSON is excluded.
-typedef int pm_json_unused_t;
-
-#ifndef PRISM_EXCLUDE_JSON
-
-#include "prism/internal/buffer.h"
-#include "prism/internal/constant_pool.h"
-#include "prism/internal/integer.h"
-#include "prism/internal/parser.h"
-
-#include
-
-static void
-pm_dump_json_constant(pm_buffer_t *buffer, const pm_parser_t *parser, pm_constant_id_t constant_id) {
- const pm_constant_t *constant = pm_constant_pool_id_to_constant(&parser->constant_pool, constant_id);
- pm_buffer_append_byte(buffer, '"');
- pm_buffer_append_source(buffer, constant->start, constant->length, PM_BUFFER_ESCAPING_JSON);
- pm_buffer_append_byte(buffer, '"');
-}
-
-static void
-pm_dump_json_location(pm_buffer_t *buffer, const pm_location_t *location) {
- pm_buffer_append_format(buffer, "{\"start\":%" PRIu32 ",\"length\":%" PRIu32 "}", location->start, location->length);
-}
-
-/**
- * Dump JSON to the given buffer.
- */
-void
-pm_dump_json(pm_buffer_t *buffer, const pm_parser_t *parser, const pm_node_t *node) {
- switch (PM_NODE_TYPE(node)) {
- case PM_ALIAS_GLOBAL_VARIABLE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"AliasGlobalVariableNode\",\"location\":", 45);
-
- const pm_alias_global_variable_node_t *cast = (const pm_alias_global_variable_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the new_name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"new_name\":", 11);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->new_name);
-
- // Dump the old_name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"old_name\":", 11);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->old_name);
-
- // Dump the keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"keyword_loc\":", 14);
- pm_dump_json_location(buffer, &cast->keyword_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_ALIAS_METHOD_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"AliasMethodNode\",\"location\":", 37);
-
- const pm_alias_method_node_t *cast = (const pm_alias_method_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the new_name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"new_name\":", 11);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->new_name);
-
- // Dump the old_name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"old_name\":", 11);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->old_name);
-
- // Dump the keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"keyword_loc\":", 14);
- pm_dump_json_location(buffer, &cast->keyword_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_ALTERNATION_PATTERN_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"AlternationPatternNode\",\"location\":", 44);
-
- const pm_alternation_pattern_node_t *cast = (const pm_alternation_pattern_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the left field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"left\":", 7);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->left);
-
- // Dump the right field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"right\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->right);
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_AND_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"AndNode\",\"location\":", 29);
-
- const pm_and_node_t *cast = (const pm_and_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the left field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"left\":", 7);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->left);
-
- // Dump the right field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"right\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->right);
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_ARGUMENTS_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"ArgumentsNode\",\"location\":", 35);
-
- const pm_arguments_node_t *cast = (const pm_arguments_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the ArgumentsNodeFlags field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"flags\":", 8);
- size_t flags = 0;
- pm_buffer_append_byte(buffer, '[');
- if (PM_NODE_FLAG_P(cast, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_FORWARDING)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"CONTAINS_FORWARDING\"", 21);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"CONTAINS_KEYWORDS\"", 19);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"CONTAINS_KEYWORD_SPLAT\"", 24);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"CONTAINS_SPLAT\"", 16);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_MULTIPLE_SPLATS)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"CONTAINS_MULTIPLE_SPLATS\"", 26);
- flags++;
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the arguments field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"arguments\":", 12);
- const pm_node_list_t *arguments = &cast->arguments;
- pm_buffer_append_byte(buffer, '[');
-
- for (size_t index = 0; index < arguments->size; index++) {
- if (index != 0) pm_buffer_append_byte(buffer, ',');
- pm_dump_json(buffer, parser, arguments->nodes[index]);
- }
- pm_buffer_append_byte(buffer, ']');
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_ARRAY_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"ArrayNode\",\"location\":", 31);
-
- const pm_array_node_t *cast = (const pm_array_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the ArrayNodeFlags field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"flags\":", 8);
- size_t flags = 0;
- pm_buffer_append_byte(buffer, '[');
- if (PM_NODE_FLAG_P(cast, PM_ARRAY_NODE_FLAGS_CONTAINS_SPLAT)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"CONTAINS_SPLAT\"", 16);
- flags++;
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the elements field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"elements\":", 11);
- const pm_node_list_t *elements = &cast->elements;
- pm_buffer_append_byte(buffer, '[');
-
- for (size_t index = 0; index < elements->size; index++) {
- if (index != 0) pm_buffer_append_byte(buffer, ',');
- pm_dump_json(buffer, parser, elements->nodes[index]);
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the opening_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"opening_loc\":", 14);
- if (cast->opening_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->opening_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the closing_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"closing_loc\":", 14);
- if (cast->closing_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->closing_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_ARRAY_PATTERN_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"ArrayPatternNode\",\"location\":", 38);
-
- const pm_array_pattern_node_t *cast = (const pm_array_pattern_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the constant field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"constant\":", 11);
- if (cast->constant != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->constant);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the requireds field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"requireds\":", 12);
- const pm_node_list_t *requireds = &cast->requireds;
- pm_buffer_append_byte(buffer, '[');
-
- for (size_t index = 0; index < requireds->size; index++) {
- if (index != 0) pm_buffer_append_byte(buffer, ',');
- pm_dump_json(buffer, parser, requireds->nodes[index]);
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the rest field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"rest\":", 7);
- if (cast->rest != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->rest);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the posts field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"posts\":", 8);
- const pm_node_list_t *posts = &cast->posts;
- pm_buffer_append_byte(buffer, '[');
-
- for (size_t index = 0; index < posts->size; index++) {
- if (index != 0) pm_buffer_append_byte(buffer, ',');
- pm_dump_json(buffer, parser, posts->nodes[index]);
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the opening_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"opening_loc\":", 14);
- if (cast->opening_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->opening_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the closing_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"closing_loc\":", 14);
- if (cast->closing_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->closing_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_ASSOC_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"AssocNode\",\"location\":", 31);
-
- const pm_assoc_node_t *cast = (const pm_assoc_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the key field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"key\":", 6);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->key);
-
- // Dump the value field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"value\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->value);
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- if (cast->operator_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->operator_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_ASSOC_SPLAT_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"AssocSplatNode\",\"location\":", 36);
-
- const pm_assoc_splat_node_t *cast = (const pm_assoc_splat_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the value field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"value\":", 8);
- if (cast->value != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->value);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_BACK_REFERENCE_READ_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"BackReferenceReadNode\",\"location\":", 43);
-
- const pm_back_reference_read_node_t *cast = (const pm_back_reference_read_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- pm_dump_json_constant(buffer, parser, cast->name);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_BEGIN_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"BeginNode\",\"location\":", 31);
-
- const pm_begin_node_t *cast = (const pm_begin_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the begin_keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"begin_keyword_loc\":", 20);
- if (cast->begin_keyword_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->begin_keyword_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the statements field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"statements\":", 13);
- if (cast->statements != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the rescue_clause field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"rescue_clause\":", 16);
- if (cast->rescue_clause != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->rescue_clause);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the else_clause field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"else_clause\":", 14);
- if (cast->else_clause != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->else_clause);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the ensure_clause field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"ensure_clause\":", 16);
- if (cast->ensure_clause != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->ensure_clause);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the end_keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"end_keyword_loc\":", 18);
- if (cast->end_keyword_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->end_keyword_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_BLOCK_ARGUMENT_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"BlockArgumentNode\",\"location\":", 39);
-
- const pm_block_argument_node_t *cast = (const pm_block_argument_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the expression field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"expression\":", 13);
- if (cast->expression != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->expression);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_BLOCK_LOCAL_VARIABLE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"BlockLocalVariableNode\",\"location\":", 44);
-
- const pm_block_local_variable_node_t *cast = (const pm_block_local_variable_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the ParameterFlags field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"flags\":", 8);
- size_t flags = 0;
- pm_buffer_append_byte(buffer, '[');
- if (PM_NODE_FLAG_P(cast, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"REPEATED_PARAMETER\"", 20);
- flags++;
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- pm_dump_json_constant(buffer, parser, cast->name);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_BLOCK_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"BlockNode\",\"location\":", 31);
-
- const pm_block_node_t *cast = (const pm_block_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the locals field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"locals\":", 9);
- const pm_constant_id_list_t *locals = &cast->locals;
- pm_buffer_append_byte(buffer, '[');
-
- for (size_t index = 0; index < locals->size; index++) {
- if (index != 0) pm_buffer_append_byte(buffer, ',');
- pm_dump_json_constant(buffer, parser, locals->ids[index]);
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the parameters field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"parameters\":", 13);
- if (cast->parameters != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->parameters);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the body field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"body\":", 7);
- if (cast->body != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->body);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the opening_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"opening_loc\":", 14);
- pm_dump_json_location(buffer, &cast->opening_loc);
-
- // Dump the closing_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"closing_loc\":", 14);
- pm_dump_json_location(buffer, &cast->closing_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_BLOCK_PARAMETER_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"BlockParameterNode\",\"location\":", 40);
-
- const pm_block_parameter_node_t *cast = (const pm_block_parameter_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the ParameterFlags field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"flags\":", 8);
- size_t flags = 0;
- pm_buffer_append_byte(buffer, '[');
- if (PM_NODE_FLAG_P(cast, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"REPEATED_PARAMETER\"", 20);
- flags++;
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- if (cast->name != PM_CONSTANT_ID_UNSET) {
- pm_dump_json_constant(buffer, parser, cast->name);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the name_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name_loc\":", 11);
- if (cast->name_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->name_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_BLOCK_PARAMETERS_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"BlockParametersNode\",\"location\":", 41);
-
- const pm_block_parameters_node_t *cast = (const pm_block_parameters_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the parameters field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"parameters\":", 13);
- if (cast->parameters != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->parameters);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the locals field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"locals\":", 9);
- const pm_node_list_t *locals = &cast->locals;
- pm_buffer_append_byte(buffer, '[');
-
- for (size_t index = 0; index < locals->size; index++) {
- if (index != 0) pm_buffer_append_byte(buffer, ',');
- pm_dump_json(buffer, parser, locals->nodes[index]);
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the opening_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"opening_loc\":", 14);
- if (cast->opening_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->opening_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the closing_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"closing_loc\":", 14);
- if (cast->closing_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->closing_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_BREAK_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"BreakNode\",\"location\":", 31);
-
- const pm_break_node_t *cast = (const pm_break_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the arguments field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"arguments\":", 12);
- if (cast->arguments != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->arguments);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"keyword_loc\":", 14);
- pm_dump_json_location(buffer, &cast->keyword_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_CALL_AND_WRITE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"CallAndWriteNode\",\"location\":", 38);
-
- const pm_call_and_write_node_t *cast = (const pm_call_and_write_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the CallNodeFlags field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"flags\":", 8);
- size_t flags = 0;
- pm_buffer_append_byte(buffer, '[');
- if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"SAFE_NAVIGATION\"", 17);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"VARIABLE_CALL\"", 15);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"ATTRIBUTE_WRITE\"", 17);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"IGNORE_VISIBILITY\"", 19);
- flags++;
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the receiver field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"receiver\":", 11);
- if (cast->receiver != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->receiver);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the call_operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"call_operator_loc\":", 20);
- if (cast->call_operator_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->call_operator_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the message_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"message_loc\":", 14);
- if (cast->message_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->message_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the read_name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"read_name\":", 12);
- pm_dump_json_constant(buffer, parser, cast->read_name);
-
- // Dump the write_name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"write_name\":", 13);
- pm_dump_json_constant(buffer, parser, cast->write_name);
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- // Dump the value field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"value\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->value);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_CALL_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"CallNode\",\"location\":", 30);
-
- const pm_call_node_t *cast = (const pm_call_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the CallNodeFlags field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"flags\":", 8);
- size_t flags = 0;
- pm_buffer_append_byte(buffer, '[');
- if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"SAFE_NAVIGATION\"", 17);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"VARIABLE_CALL\"", 15);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"ATTRIBUTE_WRITE\"", 17);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"IGNORE_VISIBILITY\"", 19);
- flags++;
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the receiver field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"receiver\":", 11);
- if (cast->receiver != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->receiver);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the call_operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"call_operator_loc\":", 20);
- if (cast->call_operator_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->call_operator_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- pm_dump_json_constant(buffer, parser, cast->name);
-
- // Dump the message_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"message_loc\":", 14);
- if (cast->message_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->message_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the opening_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"opening_loc\":", 14);
- if (cast->opening_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->opening_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the arguments field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"arguments\":", 12);
- if (cast->arguments != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->arguments);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the closing_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"closing_loc\":", 14);
- if (cast->closing_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->closing_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the equal_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"equal_loc\":", 12);
- if (cast->equal_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->equal_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the block field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"block\":", 8);
- if (cast->block != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->block);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_CALL_OPERATOR_WRITE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"CallOperatorWriteNode\",\"location\":", 43);
-
- const pm_call_operator_write_node_t *cast = (const pm_call_operator_write_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the CallNodeFlags field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"flags\":", 8);
- size_t flags = 0;
- pm_buffer_append_byte(buffer, '[');
- if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"SAFE_NAVIGATION\"", 17);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"VARIABLE_CALL\"", 15);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"ATTRIBUTE_WRITE\"", 17);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"IGNORE_VISIBILITY\"", 19);
- flags++;
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the receiver field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"receiver\":", 11);
- if (cast->receiver != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->receiver);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the call_operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"call_operator_loc\":", 20);
- if (cast->call_operator_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->call_operator_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the message_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"message_loc\":", 14);
- if (cast->message_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->message_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the read_name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"read_name\":", 12);
- pm_dump_json_constant(buffer, parser, cast->read_name);
-
- // Dump the write_name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"write_name\":", 13);
- pm_dump_json_constant(buffer, parser, cast->write_name);
-
- // Dump the binary_operator field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"binary_operator\":", 18);
- pm_dump_json_constant(buffer, parser, cast->binary_operator);
-
- // Dump the binary_operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"binary_operator_loc\":", 22);
- pm_dump_json_location(buffer, &cast->binary_operator_loc);
-
- // Dump the value field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"value\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->value);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_CALL_OR_WRITE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"CallOrWriteNode\",\"location\":", 37);
-
- const pm_call_or_write_node_t *cast = (const pm_call_or_write_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the CallNodeFlags field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"flags\":", 8);
- size_t flags = 0;
- pm_buffer_append_byte(buffer, '[');
- if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"SAFE_NAVIGATION\"", 17);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"VARIABLE_CALL\"", 15);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"ATTRIBUTE_WRITE\"", 17);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"IGNORE_VISIBILITY\"", 19);
- flags++;
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the receiver field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"receiver\":", 11);
- if (cast->receiver != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->receiver);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the call_operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"call_operator_loc\":", 20);
- if (cast->call_operator_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->call_operator_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the message_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"message_loc\":", 14);
- if (cast->message_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->message_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the read_name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"read_name\":", 12);
- pm_dump_json_constant(buffer, parser, cast->read_name);
-
- // Dump the write_name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"write_name\":", 13);
- pm_dump_json_constant(buffer, parser, cast->write_name);
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- // Dump the value field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"value\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->value);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_CALL_TARGET_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"CallTargetNode\",\"location\":", 36);
-
- const pm_call_target_node_t *cast = (const pm_call_target_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the CallNodeFlags field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"flags\":", 8);
- size_t flags = 0;
- pm_buffer_append_byte(buffer, '[');
- if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"SAFE_NAVIGATION\"", 17);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"VARIABLE_CALL\"", 15);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"ATTRIBUTE_WRITE\"", 17);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"IGNORE_VISIBILITY\"", 19);
- flags++;
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the receiver field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"receiver\":", 11);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->receiver);
-
- // Dump the call_operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"call_operator_loc\":", 20);
- pm_dump_json_location(buffer, &cast->call_operator_loc);
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- pm_dump_json_constant(buffer, parser, cast->name);
-
- // Dump the message_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"message_loc\":", 14);
- pm_dump_json_location(buffer, &cast->message_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_CAPTURE_PATTERN_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"CapturePatternNode\",\"location\":", 40);
-
- const pm_capture_pattern_node_t *cast = (const pm_capture_pattern_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the value field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"value\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->value);
-
- // Dump the target field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"target\":", 9);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->target);
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_CASE_MATCH_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"CaseMatchNode\",\"location\":", 35);
-
- const pm_case_match_node_t *cast = (const pm_case_match_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the predicate field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"predicate\":", 12);
- if (cast->predicate != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->predicate);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the conditions field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"conditions\":", 13);
- const pm_node_list_t *conditions = &cast->conditions;
- pm_buffer_append_byte(buffer, '[');
-
- for (size_t index = 0; index < conditions->size; index++) {
- if (index != 0) pm_buffer_append_byte(buffer, ',');
- pm_dump_json(buffer, parser, conditions->nodes[index]);
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the else_clause field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"else_clause\":", 14);
- if (cast->else_clause != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->else_clause);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the case_keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"case_keyword_loc\":", 19);
- pm_dump_json_location(buffer, &cast->case_keyword_loc);
-
- // Dump the end_keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"end_keyword_loc\":", 18);
- pm_dump_json_location(buffer, &cast->end_keyword_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_CASE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"CaseNode\",\"location\":", 30);
-
- const pm_case_node_t *cast = (const pm_case_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the predicate field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"predicate\":", 12);
- if (cast->predicate != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->predicate);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the conditions field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"conditions\":", 13);
- const pm_node_list_t *conditions = &cast->conditions;
- pm_buffer_append_byte(buffer, '[');
-
- for (size_t index = 0; index < conditions->size; index++) {
- if (index != 0) pm_buffer_append_byte(buffer, ',');
- pm_dump_json(buffer, parser, conditions->nodes[index]);
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the else_clause field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"else_clause\":", 14);
- if (cast->else_clause != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->else_clause);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the case_keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"case_keyword_loc\":", 19);
- pm_dump_json_location(buffer, &cast->case_keyword_loc);
-
- // Dump the end_keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"end_keyword_loc\":", 18);
- pm_dump_json_location(buffer, &cast->end_keyword_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_CLASS_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"ClassNode\",\"location\":", 31);
-
- const pm_class_node_t *cast = (const pm_class_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the locals field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"locals\":", 9);
- const pm_constant_id_list_t *locals = &cast->locals;
- pm_buffer_append_byte(buffer, '[');
-
- for (size_t index = 0; index < locals->size; index++) {
- if (index != 0) pm_buffer_append_byte(buffer, ',');
- pm_dump_json_constant(buffer, parser, locals->ids[index]);
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the class_keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"class_keyword_loc\":", 20);
- pm_dump_json_location(buffer, &cast->class_keyword_loc);
-
- // Dump the constant_path field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"constant_path\":", 16);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->constant_path);
-
- // Dump the inheritance_operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"inheritance_operator_loc\":", 27);
- if (cast->inheritance_operator_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->inheritance_operator_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the superclass field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"superclass\":", 13);
- if (cast->superclass != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->superclass);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the body field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"body\":", 7);
- if (cast->body != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->body);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the end_keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"end_keyword_loc\":", 18);
- pm_dump_json_location(buffer, &cast->end_keyword_loc);
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- pm_dump_json_constant(buffer, parser, cast->name);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_CLASS_VARIABLE_AND_WRITE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"ClassVariableAndWriteNode\",\"location\":", 47);
-
- const pm_class_variable_and_write_node_t *cast = (const pm_class_variable_and_write_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- pm_dump_json_constant(buffer, parser, cast->name);
-
- // Dump the name_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name_loc\":", 11);
- pm_dump_json_location(buffer, &cast->name_loc);
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- // Dump the value field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"value\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->value);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_CLASS_VARIABLE_OPERATOR_WRITE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"ClassVariableOperatorWriteNode\",\"location\":", 52);
-
- const pm_class_variable_operator_write_node_t *cast = (const pm_class_variable_operator_write_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- pm_dump_json_constant(buffer, parser, cast->name);
-
- // Dump the name_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name_loc\":", 11);
- pm_dump_json_location(buffer, &cast->name_loc);
-
- // Dump the binary_operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"binary_operator_loc\":", 22);
- pm_dump_json_location(buffer, &cast->binary_operator_loc);
-
- // Dump the value field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"value\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->value);
-
- // Dump the binary_operator field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"binary_operator\":", 18);
- pm_dump_json_constant(buffer, parser, cast->binary_operator);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_CLASS_VARIABLE_OR_WRITE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"ClassVariableOrWriteNode\",\"location\":", 46);
-
- const pm_class_variable_or_write_node_t *cast = (const pm_class_variable_or_write_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- pm_dump_json_constant(buffer, parser, cast->name);
-
- // Dump the name_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name_loc\":", 11);
- pm_dump_json_location(buffer, &cast->name_loc);
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- // Dump the value field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"value\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->value);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_CLASS_VARIABLE_READ_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"ClassVariableReadNode\",\"location\":", 43);
-
- const pm_class_variable_read_node_t *cast = (const pm_class_variable_read_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- pm_dump_json_constant(buffer, parser, cast->name);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_CLASS_VARIABLE_TARGET_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"ClassVariableTargetNode\",\"location\":", 45);
-
- const pm_class_variable_target_node_t *cast = (const pm_class_variable_target_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- pm_dump_json_constant(buffer, parser, cast->name);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_CLASS_VARIABLE_WRITE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"ClassVariableWriteNode\",\"location\":", 44);
-
- const pm_class_variable_write_node_t *cast = (const pm_class_variable_write_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- pm_dump_json_constant(buffer, parser, cast->name);
-
- // Dump the name_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name_loc\":", 11);
- pm_dump_json_location(buffer, &cast->name_loc);
-
- // Dump the value field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"value\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->value);
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_CONSTANT_AND_WRITE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"ConstantAndWriteNode\",\"location\":", 42);
-
- const pm_constant_and_write_node_t *cast = (const pm_constant_and_write_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- pm_dump_json_constant(buffer, parser, cast->name);
-
- // Dump the name_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name_loc\":", 11);
- pm_dump_json_location(buffer, &cast->name_loc);
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- // Dump the value field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"value\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->value);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_CONSTANT_OPERATOR_WRITE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"ConstantOperatorWriteNode\",\"location\":", 47);
-
- const pm_constant_operator_write_node_t *cast = (const pm_constant_operator_write_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- pm_dump_json_constant(buffer, parser, cast->name);
-
- // Dump the name_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name_loc\":", 11);
- pm_dump_json_location(buffer, &cast->name_loc);
-
- // Dump the binary_operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"binary_operator_loc\":", 22);
- pm_dump_json_location(buffer, &cast->binary_operator_loc);
-
- // Dump the value field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"value\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->value);
-
- // Dump the binary_operator field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"binary_operator\":", 18);
- pm_dump_json_constant(buffer, parser, cast->binary_operator);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_CONSTANT_OR_WRITE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"ConstantOrWriteNode\",\"location\":", 41);
-
- const pm_constant_or_write_node_t *cast = (const pm_constant_or_write_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- pm_dump_json_constant(buffer, parser, cast->name);
-
- // Dump the name_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name_loc\":", 11);
- pm_dump_json_location(buffer, &cast->name_loc);
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- // Dump the value field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"value\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->value);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_CONSTANT_PATH_AND_WRITE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"ConstantPathAndWriteNode\",\"location\":", 46);
-
- const pm_constant_path_and_write_node_t *cast = (const pm_constant_path_and_write_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the target field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"target\":", 9);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->target);
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- // Dump the value field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"value\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->value);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_CONSTANT_PATH_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"ConstantPathNode\",\"location\":", 38);
-
- const pm_constant_path_node_t *cast = (const pm_constant_path_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the parent field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"parent\":", 9);
- if (cast->parent != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->parent);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- if (cast->name != PM_CONSTANT_ID_UNSET) {
- pm_dump_json_constant(buffer, parser, cast->name);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the delimiter_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"delimiter_loc\":", 16);
- pm_dump_json_location(buffer, &cast->delimiter_loc);
-
- // Dump the name_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name_loc\":", 11);
- pm_dump_json_location(buffer, &cast->name_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_CONSTANT_PATH_OPERATOR_WRITE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"ConstantPathOperatorWriteNode\",\"location\":", 51);
-
- const pm_constant_path_operator_write_node_t *cast = (const pm_constant_path_operator_write_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the target field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"target\":", 9);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->target);
-
- // Dump the binary_operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"binary_operator_loc\":", 22);
- pm_dump_json_location(buffer, &cast->binary_operator_loc);
-
- // Dump the value field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"value\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->value);
-
- // Dump the binary_operator field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"binary_operator\":", 18);
- pm_dump_json_constant(buffer, parser, cast->binary_operator);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_CONSTANT_PATH_OR_WRITE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"ConstantPathOrWriteNode\",\"location\":", 45);
-
- const pm_constant_path_or_write_node_t *cast = (const pm_constant_path_or_write_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the target field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"target\":", 9);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->target);
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- // Dump the value field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"value\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->value);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_CONSTANT_PATH_TARGET_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"ConstantPathTargetNode\",\"location\":", 44);
-
- const pm_constant_path_target_node_t *cast = (const pm_constant_path_target_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the parent field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"parent\":", 9);
- if (cast->parent != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->parent);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- if (cast->name != PM_CONSTANT_ID_UNSET) {
- pm_dump_json_constant(buffer, parser, cast->name);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the delimiter_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"delimiter_loc\":", 16);
- pm_dump_json_location(buffer, &cast->delimiter_loc);
-
- // Dump the name_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name_loc\":", 11);
- pm_dump_json_location(buffer, &cast->name_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_CONSTANT_PATH_WRITE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"ConstantPathWriteNode\",\"location\":", 43);
-
- const pm_constant_path_write_node_t *cast = (const pm_constant_path_write_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the target field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"target\":", 9);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->target);
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- // Dump the value field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"value\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->value);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_CONSTANT_READ_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"ConstantReadNode\",\"location\":", 38);
-
- const pm_constant_read_node_t *cast = (const pm_constant_read_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- pm_dump_json_constant(buffer, parser, cast->name);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_CONSTANT_TARGET_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"ConstantTargetNode\",\"location\":", 40);
-
- const pm_constant_target_node_t *cast = (const pm_constant_target_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- pm_dump_json_constant(buffer, parser, cast->name);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_CONSTANT_WRITE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"ConstantWriteNode\",\"location\":", 39);
-
- const pm_constant_write_node_t *cast = (const pm_constant_write_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- pm_dump_json_constant(buffer, parser, cast->name);
-
- // Dump the name_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name_loc\":", 11);
- pm_dump_json_location(buffer, &cast->name_loc);
-
- // Dump the value field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"value\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->value);
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_DEF_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"DefNode\",\"location\":", 29);
-
- const pm_def_node_t *cast = (const pm_def_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- pm_dump_json_constant(buffer, parser, cast->name);
-
- // Dump the name_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name_loc\":", 11);
- pm_dump_json_location(buffer, &cast->name_loc);
-
- // Dump the receiver field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"receiver\":", 11);
- if (cast->receiver != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->receiver);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the parameters field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"parameters\":", 13);
- if (cast->parameters != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->parameters);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the body field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"body\":", 7);
- if (cast->body != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->body);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the locals field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"locals\":", 9);
- const pm_constant_id_list_t *locals = &cast->locals;
- pm_buffer_append_byte(buffer, '[');
-
- for (size_t index = 0; index < locals->size; index++) {
- if (index != 0) pm_buffer_append_byte(buffer, ',');
- pm_dump_json_constant(buffer, parser, locals->ids[index]);
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the def_keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"def_keyword_loc\":", 18);
- pm_dump_json_location(buffer, &cast->def_keyword_loc);
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- if (cast->operator_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->operator_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the lparen_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"lparen_loc\":", 13);
- if (cast->lparen_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->lparen_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the rparen_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"rparen_loc\":", 13);
- if (cast->rparen_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->rparen_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the equal_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"equal_loc\":", 12);
- if (cast->equal_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->equal_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the end_keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"end_keyword_loc\":", 18);
- if (cast->end_keyword_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->end_keyword_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_DEFINED_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"DefinedNode\",\"location\":", 33);
-
- const pm_defined_node_t *cast = (const pm_defined_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the lparen_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"lparen_loc\":", 13);
- if (cast->lparen_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->lparen_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the value field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"value\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->value);
-
- // Dump the rparen_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"rparen_loc\":", 13);
- if (cast->rparen_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->rparen_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"keyword_loc\":", 14);
- pm_dump_json_location(buffer, &cast->keyword_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_ELSE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"ElseNode\",\"location\":", 30);
-
- const pm_else_node_t *cast = (const pm_else_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the else_keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"else_keyword_loc\":", 19);
- pm_dump_json_location(buffer, &cast->else_keyword_loc);
-
- // Dump the statements field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"statements\":", 13);
- if (cast->statements != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the end_keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"end_keyword_loc\":", 18);
- if (cast->end_keyword_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->end_keyword_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_EMBEDDED_STATEMENTS_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"EmbeddedStatementsNode\",\"location\":", 44);
-
- const pm_embedded_statements_node_t *cast = (const pm_embedded_statements_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the opening_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"opening_loc\":", 14);
- pm_dump_json_location(buffer, &cast->opening_loc);
-
- // Dump the statements field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"statements\":", 13);
- if (cast->statements != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the closing_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"closing_loc\":", 14);
- pm_dump_json_location(buffer, &cast->closing_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_EMBEDDED_VARIABLE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"EmbeddedVariableNode\",\"location\":", 42);
-
- const pm_embedded_variable_node_t *cast = (const pm_embedded_variable_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- // Dump the variable field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"variable\":", 11);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->variable);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_ENSURE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"EnsureNode\",\"location\":", 32);
-
- const pm_ensure_node_t *cast = (const pm_ensure_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the ensure_keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"ensure_keyword_loc\":", 21);
- pm_dump_json_location(buffer, &cast->ensure_keyword_loc);
-
- // Dump the statements field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"statements\":", 13);
- if (cast->statements != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the end_keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"end_keyword_loc\":", 18);
- pm_dump_json_location(buffer, &cast->end_keyword_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_FALSE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"FalseNode\",\"location\":", 31);
-
- const pm_false_node_t *cast = (const pm_false_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_FIND_PATTERN_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"FindPatternNode\",\"location\":", 37);
-
- const pm_find_pattern_node_t *cast = (const pm_find_pattern_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the constant field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"constant\":", 11);
- if (cast->constant != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->constant);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the left field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"left\":", 7);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->left);
-
- // Dump the requireds field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"requireds\":", 12);
- const pm_node_list_t *requireds = &cast->requireds;
- pm_buffer_append_byte(buffer, '[');
-
- for (size_t index = 0; index < requireds->size; index++) {
- if (index != 0) pm_buffer_append_byte(buffer, ',');
- pm_dump_json(buffer, parser, requireds->nodes[index]);
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the right field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"right\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->right);
-
- // Dump the opening_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"opening_loc\":", 14);
- if (cast->opening_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->opening_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the closing_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"closing_loc\":", 14);
- if (cast->closing_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->closing_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_FLIP_FLOP_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"FlipFlopNode\",\"location\":", 34);
-
- const pm_flip_flop_node_t *cast = (const pm_flip_flop_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the RangeFlags field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"flags\":", 8);
- size_t flags = 0;
- pm_buffer_append_byte(buffer, '[');
- if (PM_NODE_FLAG_P(cast, PM_RANGE_FLAGS_EXCLUDE_END)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"EXCLUDE_END\"", 13);
- flags++;
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the left field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"left\":", 7);
- if (cast->left != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->left);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the right field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"right\":", 8);
- if (cast->right != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->right);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_FLOAT_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"FloatNode\",\"location\":", 31);
-
- const pm_float_node_t *cast = (const pm_float_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the value field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"value\":", 8);
- pm_buffer_append_format(buffer, "%f", cast->value);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_FOR_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"ForNode\",\"location\":", 29);
-
- const pm_for_node_t *cast = (const pm_for_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the index field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"index\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->index);
-
- // Dump the collection field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"collection\":", 13);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->collection);
-
- // Dump the statements field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"statements\":", 13);
- if (cast->statements != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the for_keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"for_keyword_loc\":", 18);
- pm_dump_json_location(buffer, &cast->for_keyword_loc);
-
- // Dump the in_keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"in_keyword_loc\":", 17);
- pm_dump_json_location(buffer, &cast->in_keyword_loc);
-
- // Dump the do_keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"do_keyword_loc\":", 17);
- if (cast->do_keyword_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->do_keyword_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the end_keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"end_keyword_loc\":", 18);
- pm_dump_json_location(buffer, &cast->end_keyword_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_FORWARDING_ARGUMENTS_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"ForwardingArgumentsNode\",\"location\":", 45);
-
- const pm_forwarding_arguments_node_t *cast = (const pm_forwarding_arguments_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_FORWARDING_PARAMETER_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"ForwardingParameterNode\",\"location\":", 45);
-
- const pm_forwarding_parameter_node_t *cast = (const pm_forwarding_parameter_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_FORWARDING_SUPER_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"ForwardingSuperNode\",\"location\":", 41);
-
- const pm_forwarding_super_node_t *cast = (const pm_forwarding_super_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the block field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"block\":", 8);
- if (cast->block != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->block);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_GLOBAL_VARIABLE_AND_WRITE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"GlobalVariableAndWriteNode\",\"location\":", 48);
-
- const pm_global_variable_and_write_node_t *cast = (const pm_global_variable_and_write_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- pm_dump_json_constant(buffer, parser, cast->name);
-
- // Dump the name_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name_loc\":", 11);
- pm_dump_json_location(buffer, &cast->name_loc);
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- // Dump the value field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"value\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->value);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"GlobalVariableOperatorWriteNode\",\"location\":", 53);
-
- const pm_global_variable_operator_write_node_t *cast = (const pm_global_variable_operator_write_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- pm_dump_json_constant(buffer, parser, cast->name);
-
- // Dump the name_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name_loc\":", 11);
- pm_dump_json_location(buffer, &cast->name_loc);
-
- // Dump the binary_operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"binary_operator_loc\":", 22);
- pm_dump_json_location(buffer, &cast->binary_operator_loc);
-
- // Dump the value field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"value\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->value);
-
- // Dump the binary_operator field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"binary_operator\":", 18);
- pm_dump_json_constant(buffer, parser, cast->binary_operator);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_GLOBAL_VARIABLE_OR_WRITE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"GlobalVariableOrWriteNode\",\"location\":", 47);
-
- const pm_global_variable_or_write_node_t *cast = (const pm_global_variable_or_write_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- pm_dump_json_constant(buffer, parser, cast->name);
-
- // Dump the name_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name_loc\":", 11);
- pm_dump_json_location(buffer, &cast->name_loc);
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- // Dump the value field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"value\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->value);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_GLOBAL_VARIABLE_READ_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"GlobalVariableReadNode\",\"location\":", 44);
-
- const pm_global_variable_read_node_t *cast = (const pm_global_variable_read_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- pm_dump_json_constant(buffer, parser, cast->name);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_GLOBAL_VARIABLE_TARGET_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"GlobalVariableTargetNode\",\"location\":", 46);
-
- const pm_global_variable_target_node_t *cast = (const pm_global_variable_target_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- pm_dump_json_constant(buffer, parser, cast->name);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_GLOBAL_VARIABLE_WRITE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"GlobalVariableWriteNode\",\"location\":", 45);
-
- const pm_global_variable_write_node_t *cast = (const pm_global_variable_write_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- pm_dump_json_constant(buffer, parser, cast->name);
-
- // Dump the name_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name_loc\":", 11);
- pm_dump_json_location(buffer, &cast->name_loc);
-
- // Dump the value field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"value\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->value);
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_HASH_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"HashNode\",\"location\":", 30);
-
- const pm_hash_node_t *cast = (const pm_hash_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the opening_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"opening_loc\":", 14);
- pm_dump_json_location(buffer, &cast->opening_loc);
-
- // Dump the elements field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"elements\":", 11);
- const pm_node_list_t *elements = &cast->elements;
- pm_buffer_append_byte(buffer, '[');
-
- for (size_t index = 0; index < elements->size; index++) {
- if (index != 0) pm_buffer_append_byte(buffer, ',');
- pm_dump_json(buffer, parser, elements->nodes[index]);
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the closing_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"closing_loc\":", 14);
- pm_dump_json_location(buffer, &cast->closing_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_HASH_PATTERN_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"HashPatternNode\",\"location\":", 37);
-
- const pm_hash_pattern_node_t *cast = (const pm_hash_pattern_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the constant field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"constant\":", 11);
- if (cast->constant != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->constant);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the elements field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"elements\":", 11);
- const pm_node_list_t *elements = &cast->elements;
- pm_buffer_append_byte(buffer, '[');
-
- for (size_t index = 0; index < elements->size; index++) {
- if (index != 0) pm_buffer_append_byte(buffer, ',');
- pm_dump_json(buffer, parser, elements->nodes[index]);
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the rest field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"rest\":", 7);
- if (cast->rest != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->rest);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the opening_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"opening_loc\":", 14);
- if (cast->opening_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->opening_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the closing_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"closing_loc\":", 14);
- if (cast->closing_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->closing_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_IF_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"IfNode\",\"location\":", 28);
-
- const pm_if_node_t *cast = (const pm_if_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the if_keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"if_keyword_loc\":", 17);
- if (cast->if_keyword_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->if_keyword_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the predicate field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"predicate\":", 12);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->predicate);
-
- // Dump the then_keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"then_keyword_loc\":", 19);
- if (cast->then_keyword_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->then_keyword_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the statements field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"statements\":", 13);
- if (cast->statements != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the subsequent field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"subsequent\":", 13);
- if (cast->subsequent != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->subsequent);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the end_keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"end_keyword_loc\":", 18);
- if (cast->end_keyword_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->end_keyword_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_IMAGINARY_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"ImaginaryNode\",\"location\":", 35);
-
- const pm_imaginary_node_t *cast = (const pm_imaginary_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the numeric field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"numeric\":", 10);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->numeric);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_IMPLICIT_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"ImplicitNode\",\"location\":", 34);
-
- const pm_implicit_node_t *cast = (const pm_implicit_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the value field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"value\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->value);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_IMPLICIT_REST_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"ImplicitRestNode\",\"location\":", 38);
-
- const pm_implicit_rest_node_t *cast = (const pm_implicit_rest_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_IN_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"InNode\",\"location\":", 28);
-
- const pm_in_node_t *cast = (const pm_in_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the pattern field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"pattern\":", 10);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->pattern);
-
- // Dump the statements field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"statements\":", 13);
- if (cast->statements != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the in_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"in_loc\":", 9);
- pm_dump_json_location(buffer, &cast->in_loc);
-
- // Dump the then_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"then_loc\":", 11);
- if (cast->then_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->then_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_INDEX_AND_WRITE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"IndexAndWriteNode\",\"location\":", 39);
-
- const pm_index_and_write_node_t *cast = (const pm_index_and_write_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the CallNodeFlags field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"flags\":", 8);
- size_t flags = 0;
- pm_buffer_append_byte(buffer, '[');
- if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"SAFE_NAVIGATION\"", 17);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"VARIABLE_CALL\"", 15);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"ATTRIBUTE_WRITE\"", 17);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"IGNORE_VISIBILITY\"", 19);
- flags++;
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the receiver field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"receiver\":", 11);
- if (cast->receiver != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->receiver);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the call_operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"call_operator_loc\":", 20);
- if (cast->call_operator_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->call_operator_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the opening_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"opening_loc\":", 14);
- pm_dump_json_location(buffer, &cast->opening_loc);
-
- // Dump the arguments field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"arguments\":", 12);
- if (cast->arguments != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->arguments);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the closing_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"closing_loc\":", 14);
- pm_dump_json_location(buffer, &cast->closing_loc);
-
- // Dump the block field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"block\":", 8);
- if (cast->block != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->block);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- // Dump the value field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"value\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->value);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_INDEX_OPERATOR_WRITE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"IndexOperatorWriteNode\",\"location\":", 44);
-
- const pm_index_operator_write_node_t *cast = (const pm_index_operator_write_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the CallNodeFlags field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"flags\":", 8);
- size_t flags = 0;
- pm_buffer_append_byte(buffer, '[');
- if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"SAFE_NAVIGATION\"", 17);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"VARIABLE_CALL\"", 15);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"ATTRIBUTE_WRITE\"", 17);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"IGNORE_VISIBILITY\"", 19);
- flags++;
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the receiver field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"receiver\":", 11);
- if (cast->receiver != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->receiver);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the call_operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"call_operator_loc\":", 20);
- if (cast->call_operator_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->call_operator_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the opening_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"opening_loc\":", 14);
- pm_dump_json_location(buffer, &cast->opening_loc);
-
- // Dump the arguments field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"arguments\":", 12);
- if (cast->arguments != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->arguments);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the closing_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"closing_loc\":", 14);
- pm_dump_json_location(buffer, &cast->closing_loc);
-
- // Dump the block field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"block\":", 8);
- if (cast->block != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->block);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the binary_operator field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"binary_operator\":", 18);
- pm_dump_json_constant(buffer, parser, cast->binary_operator);
-
- // Dump the binary_operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"binary_operator_loc\":", 22);
- pm_dump_json_location(buffer, &cast->binary_operator_loc);
-
- // Dump the value field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"value\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->value);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_INDEX_OR_WRITE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"IndexOrWriteNode\",\"location\":", 38);
-
- const pm_index_or_write_node_t *cast = (const pm_index_or_write_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the CallNodeFlags field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"flags\":", 8);
- size_t flags = 0;
- pm_buffer_append_byte(buffer, '[');
- if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"SAFE_NAVIGATION\"", 17);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"VARIABLE_CALL\"", 15);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"ATTRIBUTE_WRITE\"", 17);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"IGNORE_VISIBILITY\"", 19);
- flags++;
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the receiver field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"receiver\":", 11);
- if (cast->receiver != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->receiver);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the call_operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"call_operator_loc\":", 20);
- if (cast->call_operator_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->call_operator_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the opening_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"opening_loc\":", 14);
- pm_dump_json_location(buffer, &cast->opening_loc);
-
- // Dump the arguments field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"arguments\":", 12);
- if (cast->arguments != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->arguments);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the closing_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"closing_loc\":", 14);
- pm_dump_json_location(buffer, &cast->closing_loc);
-
- // Dump the block field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"block\":", 8);
- if (cast->block != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->block);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- // Dump the value field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"value\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->value);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_INDEX_TARGET_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"IndexTargetNode\",\"location\":", 37);
-
- const pm_index_target_node_t *cast = (const pm_index_target_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the CallNodeFlags field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"flags\":", 8);
- size_t flags = 0;
- pm_buffer_append_byte(buffer, '[');
- if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"SAFE_NAVIGATION\"", 17);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"VARIABLE_CALL\"", 15);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"ATTRIBUTE_WRITE\"", 17);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"IGNORE_VISIBILITY\"", 19);
- flags++;
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the receiver field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"receiver\":", 11);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->receiver);
-
- // Dump the opening_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"opening_loc\":", 14);
- pm_dump_json_location(buffer, &cast->opening_loc);
-
- // Dump the arguments field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"arguments\":", 12);
- if (cast->arguments != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->arguments);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the closing_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"closing_loc\":", 14);
- pm_dump_json_location(buffer, &cast->closing_loc);
-
- // Dump the block field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"block\":", 8);
- if (cast->block != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->block);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_INSTANCE_VARIABLE_AND_WRITE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"InstanceVariableAndWriteNode\",\"location\":", 50);
-
- const pm_instance_variable_and_write_node_t *cast = (const pm_instance_variable_and_write_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- pm_dump_json_constant(buffer, parser, cast->name);
-
- // Dump the name_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name_loc\":", 11);
- pm_dump_json_location(buffer, &cast->name_loc);
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- // Dump the value field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"value\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->value);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"InstanceVariableOperatorWriteNode\",\"location\":", 55);
-
- const pm_instance_variable_operator_write_node_t *cast = (const pm_instance_variable_operator_write_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- pm_dump_json_constant(buffer, parser, cast->name);
-
- // Dump the name_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name_loc\":", 11);
- pm_dump_json_location(buffer, &cast->name_loc);
-
- // Dump the binary_operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"binary_operator_loc\":", 22);
- pm_dump_json_location(buffer, &cast->binary_operator_loc);
-
- // Dump the value field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"value\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->value);
-
- // Dump the binary_operator field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"binary_operator\":", 18);
- pm_dump_json_constant(buffer, parser, cast->binary_operator);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_INSTANCE_VARIABLE_OR_WRITE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"InstanceVariableOrWriteNode\",\"location\":", 49);
-
- const pm_instance_variable_or_write_node_t *cast = (const pm_instance_variable_or_write_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- pm_dump_json_constant(buffer, parser, cast->name);
-
- // Dump the name_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name_loc\":", 11);
- pm_dump_json_location(buffer, &cast->name_loc);
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- // Dump the value field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"value\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->value);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_INSTANCE_VARIABLE_READ_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"InstanceVariableReadNode\",\"location\":", 46);
-
- const pm_instance_variable_read_node_t *cast = (const pm_instance_variable_read_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- pm_dump_json_constant(buffer, parser, cast->name);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_INSTANCE_VARIABLE_TARGET_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"InstanceVariableTargetNode\",\"location\":", 48);
-
- const pm_instance_variable_target_node_t *cast = (const pm_instance_variable_target_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- pm_dump_json_constant(buffer, parser, cast->name);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_INSTANCE_VARIABLE_WRITE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"InstanceVariableWriteNode\",\"location\":", 47);
-
- const pm_instance_variable_write_node_t *cast = (const pm_instance_variable_write_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- pm_dump_json_constant(buffer, parser, cast->name);
-
- // Dump the name_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name_loc\":", 11);
- pm_dump_json_location(buffer, &cast->name_loc);
-
- // Dump the value field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"value\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->value);
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_INTEGER_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"IntegerNode\",\"location\":", 33);
-
- const pm_integer_node_t *cast = (const pm_integer_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the IntegerBaseFlags field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"flags\":", 8);
- size_t flags = 0;
- pm_buffer_append_byte(buffer, '[');
- if (PM_NODE_FLAG_P(cast, PM_INTEGER_BASE_FLAGS_BINARY)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"BINARY\"", 8);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_INTEGER_BASE_FLAGS_DECIMAL)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"DECIMAL\"", 9);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_INTEGER_BASE_FLAGS_OCTAL)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"OCTAL\"", 7);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_INTEGER_BASE_FLAGS_HEXADECIMAL)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"HEXADECIMAL\"", 13);
- flags++;
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the value field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"value\":", 8);
- pm_integer_string(buffer, &cast->value);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_INTERPOLATED_MATCH_LAST_LINE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"InterpolatedMatchLastLineNode\",\"location\":", 51);
-
- const pm_interpolated_match_last_line_node_t *cast = (const pm_interpolated_match_last_line_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the RegularExpressionFlags field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"flags\":", 8);
- size_t flags = 0;
- pm_buffer_append_byte(buffer, '[');
- if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"IGNORE_CASE\"", 13);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"EXTENDED\"", 10);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"MULTI_LINE\"", 12);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_ONCE)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"ONCE\"", 6);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_EUC_JP)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"EUC_JP\"", 8);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"ASCII_8BIT\"", 12);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"WINDOWS_31J\"", 13);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_UTF_8)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"UTF_8\"", 7);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"FORCED_UTF8_ENCODING\"", 22);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"FORCED_BINARY_ENCODING\"", 24);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"FORCED_US_ASCII_ENCODING\"", 26);
- flags++;
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the opening_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"opening_loc\":", 14);
- pm_dump_json_location(buffer, &cast->opening_loc);
-
- // Dump the parts field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"parts\":", 8);
- const pm_node_list_t *parts = &cast->parts;
- pm_buffer_append_byte(buffer, '[');
-
- for (size_t index = 0; index < parts->size; index++) {
- if (index != 0) pm_buffer_append_byte(buffer, ',');
- pm_dump_json(buffer, parser, parts->nodes[index]);
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the closing_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"closing_loc\":", 14);
- pm_dump_json_location(buffer, &cast->closing_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"InterpolatedRegularExpressionNode\",\"location\":", 55);
-
- const pm_interpolated_regular_expression_node_t *cast = (const pm_interpolated_regular_expression_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the RegularExpressionFlags field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"flags\":", 8);
- size_t flags = 0;
- pm_buffer_append_byte(buffer, '[');
- if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"IGNORE_CASE\"", 13);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"EXTENDED\"", 10);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"MULTI_LINE\"", 12);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_ONCE)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"ONCE\"", 6);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_EUC_JP)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"EUC_JP\"", 8);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"ASCII_8BIT\"", 12);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"WINDOWS_31J\"", 13);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_UTF_8)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"UTF_8\"", 7);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"FORCED_UTF8_ENCODING\"", 22);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"FORCED_BINARY_ENCODING\"", 24);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"FORCED_US_ASCII_ENCODING\"", 26);
- flags++;
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the opening_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"opening_loc\":", 14);
- pm_dump_json_location(buffer, &cast->opening_loc);
-
- // Dump the parts field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"parts\":", 8);
- const pm_node_list_t *parts = &cast->parts;
- pm_buffer_append_byte(buffer, '[');
-
- for (size_t index = 0; index < parts->size; index++) {
- if (index != 0) pm_buffer_append_byte(buffer, ',');
- pm_dump_json(buffer, parser, parts->nodes[index]);
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the closing_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"closing_loc\":", 14);
- pm_dump_json_location(buffer, &cast->closing_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_INTERPOLATED_STRING_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"InterpolatedStringNode\",\"location\":", 44);
-
- const pm_interpolated_string_node_t *cast = (const pm_interpolated_string_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the InterpolatedStringNodeFlags field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"flags\":", 8);
- size_t flags = 0;
- pm_buffer_append_byte(buffer, '[');
- if (PM_NODE_FLAG_P(cast, PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"FROZEN\"", 8);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"MUTABLE\"", 9);
- flags++;
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the opening_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"opening_loc\":", 14);
- if (cast->opening_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->opening_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the parts field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"parts\":", 8);
- const pm_node_list_t *parts = &cast->parts;
- pm_buffer_append_byte(buffer, '[');
-
- for (size_t index = 0; index < parts->size; index++) {
- if (index != 0) pm_buffer_append_byte(buffer, ',');
- pm_dump_json(buffer, parser, parts->nodes[index]);
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the closing_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"closing_loc\":", 14);
- if (cast->closing_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->closing_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_INTERPOLATED_SYMBOL_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"InterpolatedSymbolNode\",\"location\":", 44);
-
- const pm_interpolated_symbol_node_t *cast = (const pm_interpolated_symbol_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the opening_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"opening_loc\":", 14);
- if (cast->opening_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->opening_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the parts field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"parts\":", 8);
- const pm_node_list_t *parts = &cast->parts;
- pm_buffer_append_byte(buffer, '[');
-
- for (size_t index = 0; index < parts->size; index++) {
- if (index != 0) pm_buffer_append_byte(buffer, ',');
- pm_dump_json(buffer, parser, parts->nodes[index]);
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the closing_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"closing_loc\":", 14);
- if (cast->closing_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->closing_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_INTERPOLATED_X_STRING_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"InterpolatedXStringNode\",\"location\":", 45);
-
- const pm_interpolated_x_string_node_t *cast = (const pm_interpolated_x_string_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the opening_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"opening_loc\":", 14);
- pm_dump_json_location(buffer, &cast->opening_loc);
-
- // Dump the parts field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"parts\":", 8);
- const pm_node_list_t *parts = &cast->parts;
- pm_buffer_append_byte(buffer, '[');
-
- for (size_t index = 0; index < parts->size; index++) {
- if (index != 0) pm_buffer_append_byte(buffer, ',');
- pm_dump_json(buffer, parser, parts->nodes[index]);
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the closing_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"closing_loc\":", 14);
- pm_dump_json_location(buffer, &cast->closing_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_IT_LOCAL_VARIABLE_READ_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"ItLocalVariableReadNode\",\"location\":", 45);
-
- const pm_it_local_variable_read_node_t *cast = (const pm_it_local_variable_read_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_IT_PARAMETERS_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"ItParametersNode\",\"location\":", 38);
-
- const pm_it_parameters_node_t *cast = (const pm_it_parameters_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_KEYWORD_HASH_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"KeywordHashNode\",\"location\":", 37);
-
- const pm_keyword_hash_node_t *cast = (const pm_keyword_hash_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the KeywordHashNodeFlags field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"flags\":", 8);
- size_t flags = 0;
- pm_buffer_append_byte(buffer, '[');
- if (PM_NODE_FLAG_P(cast, PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"SYMBOL_KEYS\"", 13);
- flags++;
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the elements field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"elements\":", 11);
- const pm_node_list_t *elements = &cast->elements;
- pm_buffer_append_byte(buffer, '[');
-
- for (size_t index = 0; index < elements->size; index++) {
- if (index != 0) pm_buffer_append_byte(buffer, ',');
- pm_dump_json(buffer, parser, elements->nodes[index]);
- }
- pm_buffer_append_byte(buffer, ']');
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_KEYWORD_REST_PARAMETER_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"KeywordRestParameterNode\",\"location\":", 46);
-
- const pm_keyword_rest_parameter_node_t *cast = (const pm_keyword_rest_parameter_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the ParameterFlags field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"flags\":", 8);
- size_t flags = 0;
- pm_buffer_append_byte(buffer, '[');
- if (PM_NODE_FLAG_P(cast, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"REPEATED_PARAMETER\"", 20);
- flags++;
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- if (cast->name != PM_CONSTANT_ID_UNSET) {
- pm_dump_json_constant(buffer, parser, cast->name);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the name_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name_loc\":", 11);
- if (cast->name_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->name_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_LAMBDA_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"LambdaNode\",\"location\":", 32);
-
- const pm_lambda_node_t *cast = (const pm_lambda_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the locals field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"locals\":", 9);
- const pm_constant_id_list_t *locals = &cast->locals;
- pm_buffer_append_byte(buffer, '[');
-
- for (size_t index = 0; index < locals->size; index++) {
- if (index != 0) pm_buffer_append_byte(buffer, ',');
- pm_dump_json_constant(buffer, parser, locals->ids[index]);
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- // Dump the opening_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"opening_loc\":", 14);
- pm_dump_json_location(buffer, &cast->opening_loc);
-
- // Dump the closing_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"closing_loc\":", 14);
- pm_dump_json_location(buffer, &cast->closing_loc);
-
- // Dump the parameters field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"parameters\":", 13);
- if (cast->parameters != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->parameters);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the body field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"body\":", 7);
- if (cast->body != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->body);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_LOCAL_VARIABLE_AND_WRITE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"LocalVariableAndWriteNode\",\"location\":", 47);
-
- const pm_local_variable_and_write_node_t *cast = (const pm_local_variable_and_write_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the name_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name_loc\":", 11);
- pm_dump_json_location(buffer, &cast->name_loc);
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- // Dump the value field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"value\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->value);
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- pm_dump_json_constant(buffer, parser, cast->name);
-
- // Dump the depth field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"depth\":", 8);
- pm_buffer_append_format(buffer, "%" PRIu32, cast->depth);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_LOCAL_VARIABLE_OPERATOR_WRITE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"LocalVariableOperatorWriteNode\",\"location\":", 52);
-
- const pm_local_variable_operator_write_node_t *cast = (const pm_local_variable_operator_write_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the name_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name_loc\":", 11);
- pm_dump_json_location(buffer, &cast->name_loc);
-
- // Dump the binary_operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"binary_operator_loc\":", 22);
- pm_dump_json_location(buffer, &cast->binary_operator_loc);
-
- // Dump the value field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"value\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->value);
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- pm_dump_json_constant(buffer, parser, cast->name);
-
- // Dump the binary_operator field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"binary_operator\":", 18);
- pm_dump_json_constant(buffer, parser, cast->binary_operator);
-
- // Dump the depth field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"depth\":", 8);
- pm_buffer_append_format(buffer, "%" PRIu32, cast->depth);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_LOCAL_VARIABLE_OR_WRITE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"LocalVariableOrWriteNode\",\"location\":", 46);
-
- const pm_local_variable_or_write_node_t *cast = (const pm_local_variable_or_write_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the name_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name_loc\":", 11);
- pm_dump_json_location(buffer, &cast->name_loc);
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- // Dump the value field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"value\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->value);
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- pm_dump_json_constant(buffer, parser, cast->name);
-
- // Dump the depth field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"depth\":", 8);
- pm_buffer_append_format(buffer, "%" PRIu32, cast->depth);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_LOCAL_VARIABLE_READ_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"LocalVariableReadNode\",\"location\":", 43);
-
- const pm_local_variable_read_node_t *cast = (const pm_local_variable_read_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- pm_dump_json_constant(buffer, parser, cast->name);
-
- // Dump the depth field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"depth\":", 8);
- pm_buffer_append_format(buffer, "%" PRIu32, cast->depth);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_LOCAL_VARIABLE_TARGET_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"LocalVariableTargetNode\",\"location\":", 45);
-
- const pm_local_variable_target_node_t *cast = (const pm_local_variable_target_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- pm_dump_json_constant(buffer, parser, cast->name);
-
- // Dump the depth field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"depth\":", 8);
- pm_buffer_append_format(buffer, "%" PRIu32, cast->depth);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_LOCAL_VARIABLE_WRITE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"LocalVariableWriteNode\",\"location\":", 44);
-
- const pm_local_variable_write_node_t *cast = (const pm_local_variable_write_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- pm_dump_json_constant(buffer, parser, cast->name);
-
- // Dump the depth field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"depth\":", 8);
- pm_buffer_append_format(buffer, "%" PRIu32, cast->depth);
-
- // Dump the name_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name_loc\":", 11);
- pm_dump_json_location(buffer, &cast->name_loc);
-
- // Dump the value field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"value\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->value);
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_MATCH_LAST_LINE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"MatchLastLineNode\",\"location\":", 39);
-
- const pm_match_last_line_node_t *cast = (const pm_match_last_line_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the RegularExpressionFlags field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"flags\":", 8);
- size_t flags = 0;
- pm_buffer_append_byte(buffer, '[');
- if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"IGNORE_CASE\"", 13);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"EXTENDED\"", 10);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"MULTI_LINE\"", 12);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_ONCE)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"ONCE\"", 6);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_EUC_JP)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"EUC_JP\"", 8);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"ASCII_8BIT\"", 12);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"WINDOWS_31J\"", 13);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_UTF_8)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"UTF_8\"", 7);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"FORCED_UTF8_ENCODING\"", 22);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"FORCED_BINARY_ENCODING\"", 24);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"FORCED_US_ASCII_ENCODING\"", 26);
- flags++;
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the opening_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"opening_loc\":", 14);
- pm_dump_json_location(buffer, &cast->opening_loc);
-
- // Dump the content_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"content_loc\":", 14);
- pm_dump_json_location(buffer, &cast->content_loc);
-
- // Dump the closing_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"closing_loc\":", 14);
- pm_dump_json_location(buffer, &cast->closing_loc);
-
- // Dump the unescaped field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"unescaped\":", 12);
- const pm_string_t *unescaped = &cast->unescaped;
- pm_buffer_append_byte(buffer, '"');
- pm_buffer_append_source(buffer, pm_string_source(unescaped), pm_string_length(unescaped), PM_BUFFER_ESCAPING_JSON);
- pm_buffer_append_byte(buffer, '"');
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_MATCH_PREDICATE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"MatchPredicateNode\",\"location\":", 40);
-
- const pm_match_predicate_node_t *cast = (const pm_match_predicate_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the value field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"value\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->value);
-
- // Dump the pattern field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"pattern\":", 10);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->pattern);
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_MATCH_REQUIRED_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"MatchRequiredNode\",\"location\":", 39);
-
- const pm_match_required_node_t *cast = (const pm_match_required_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the value field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"value\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->value);
-
- // Dump the pattern field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"pattern\":", 10);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->pattern);
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_MATCH_WRITE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"MatchWriteNode\",\"location\":", 36);
-
- const pm_match_write_node_t *cast = (const pm_match_write_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the call field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"call\":", 7);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->call);
-
- // Dump the targets field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"targets\":", 10);
- const pm_node_list_t *targets = &cast->targets;
- pm_buffer_append_byte(buffer, '[');
-
- for (size_t index = 0; index < targets->size; index++) {
- if (index != 0) pm_buffer_append_byte(buffer, ',');
- pm_dump_json(buffer, parser, targets->nodes[index]);
- }
- pm_buffer_append_byte(buffer, ']');
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_MISSING_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"MissingNode\",\"location\":", 33);
-
- const pm_missing_node_t *cast = (const pm_missing_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_MODULE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"ModuleNode\",\"location\":", 32);
-
- const pm_module_node_t *cast = (const pm_module_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the locals field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"locals\":", 9);
- const pm_constant_id_list_t *locals = &cast->locals;
- pm_buffer_append_byte(buffer, '[');
-
- for (size_t index = 0; index < locals->size; index++) {
- if (index != 0) pm_buffer_append_byte(buffer, ',');
- pm_dump_json_constant(buffer, parser, locals->ids[index]);
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the module_keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"module_keyword_loc\":", 21);
- pm_dump_json_location(buffer, &cast->module_keyword_loc);
-
- // Dump the constant_path field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"constant_path\":", 16);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->constant_path);
-
- // Dump the body field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"body\":", 7);
- if (cast->body != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->body);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the end_keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"end_keyword_loc\":", 18);
- pm_dump_json_location(buffer, &cast->end_keyword_loc);
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- pm_dump_json_constant(buffer, parser, cast->name);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_MULTI_TARGET_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"MultiTargetNode\",\"location\":", 37);
-
- const pm_multi_target_node_t *cast = (const pm_multi_target_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the lefts field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"lefts\":", 8);
- const pm_node_list_t *lefts = &cast->lefts;
- pm_buffer_append_byte(buffer, '[');
-
- for (size_t index = 0; index < lefts->size; index++) {
- if (index != 0) pm_buffer_append_byte(buffer, ',');
- pm_dump_json(buffer, parser, lefts->nodes[index]);
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the rest field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"rest\":", 7);
- if (cast->rest != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->rest);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the rights field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"rights\":", 9);
- const pm_node_list_t *rights = &cast->rights;
- pm_buffer_append_byte(buffer, '[');
-
- for (size_t index = 0; index < rights->size; index++) {
- if (index != 0) pm_buffer_append_byte(buffer, ',');
- pm_dump_json(buffer, parser, rights->nodes[index]);
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the lparen_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"lparen_loc\":", 13);
- if (cast->lparen_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->lparen_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the rparen_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"rparen_loc\":", 13);
- if (cast->rparen_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->rparen_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_MULTI_WRITE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"MultiWriteNode\",\"location\":", 36);
-
- const pm_multi_write_node_t *cast = (const pm_multi_write_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the lefts field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"lefts\":", 8);
- const pm_node_list_t *lefts = &cast->lefts;
- pm_buffer_append_byte(buffer, '[');
-
- for (size_t index = 0; index < lefts->size; index++) {
- if (index != 0) pm_buffer_append_byte(buffer, ',');
- pm_dump_json(buffer, parser, lefts->nodes[index]);
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the rest field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"rest\":", 7);
- if (cast->rest != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->rest);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the rights field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"rights\":", 9);
- const pm_node_list_t *rights = &cast->rights;
- pm_buffer_append_byte(buffer, '[');
-
- for (size_t index = 0; index < rights->size; index++) {
- if (index != 0) pm_buffer_append_byte(buffer, ',');
- pm_dump_json(buffer, parser, rights->nodes[index]);
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the lparen_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"lparen_loc\":", 13);
- if (cast->lparen_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->lparen_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the rparen_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"rparen_loc\":", 13);
- if (cast->rparen_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->rparen_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- // Dump the value field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"value\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->value);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_NEXT_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"NextNode\",\"location\":", 30);
-
- const pm_next_node_t *cast = (const pm_next_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the arguments field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"arguments\":", 12);
- if (cast->arguments != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->arguments);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"keyword_loc\":", 14);
- pm_dump_json_location(buffer, &cast->keyword_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_NIL_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"NilNode\",\"location\":", 29);
-
- const pm_nil_node_t *cast = (const pm_nil_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_NO_BLOCK_PARAMETER_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"NoBlockParameterNode\",\"location\":", 42);
-
- const pm_no_block_parameter_node_t *cast = (const pm_no_block_parameter_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- // Dump the keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"keyword_loc\":", 14);
- pm_dump_json_location(buffer, &cast->keyword_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_NO_KEYWORDS_PARAMETER_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"NoKeywordsParameterNode\",\"location\":", 45);
-
- const pm_no_keywords_parameter_node_t *cast = (const pm_no_keywords_parameter_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- // Dump the keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"keyword_loc\":", 14);
- pm_dump_json_location(buffer, &cast->keyword_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_NUMBERED_PARAMETERS_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"NumberedParametersNode\",\"location\":", 44);
-
- const pm_numbered_parameters_node_t *cast = (const pm_numbered_parameters_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the maximum field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"maximum\":", 10);
- pm_buffer_append_format(buffer, "%" PRIu8, cast->maximum);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_NUMBERED_REFERENCE_READ_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"NumberedReferenceReadNode\",\"location\":", 47);
-
- const pm_numbered_reference_read_node_t *cast = (const pm_numbered_reference_read_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the number field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"number\":", 9);
- pm_buffer_append_format(buffer, "%" PRIu32, cast->number);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_OPTIONAL_KEYWORD_PARAMETER_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"OptionalKeywordParameterNode\",\"location\":", 50);
-
- const pm_optional_keyword_parameter_node_t *cast = (const pm_optional_keyword_parameter_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the ParameterFlags field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"flags\":", 8);
- size_t flags = 0;
- pm_buffer_append_byte(buffer, '[');
- if (PM_NODE_FLAG_P(cast, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"REPEATED_PARAMETER\"", 20);
- flags++;
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- pm_dump_json_constant(buffer, parser, cast->name);
-
- // Dump the name_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name_loc\":", 11);
- pm_dump_json_location(buffer, &cast->name_loc);
-
- // Dump the value field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"value\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->value);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_OPTIONAL_PARAMETER_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"OptionalParameterNode\",\"location\":", 43);
-
- const pm_optional_parameter_node_t *cast = (const pm_optional_parameter_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the ParameterFlags field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"flags\":", 8);
- size_t flags = 0;
- pm_buffer_append_byte(buffer, '[');
- if (PM_NODE_FLAG_P(cast, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"REPEATED_PARAMETER\"", 20);
- flags++;
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- pm_dump_json_constant(buffer, parser, cast->name);
-
- // Dump the name_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name_loc\":", 11);
- pm_dump_json_location(buffer, &cast->name_loc);
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- // Dump the value field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"value\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->value);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_OR_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"OrNode\",\"location\":", 28);
-
- const pm_or_node_t *cast = (const pm_or_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the left field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"left\":", 7);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->left);
-
- // Dump the right field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"right\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->right);
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_PARAMETERS_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"ParametersNode\",\"location\":", 36);
-
- const pm_parameters_node_t *cast = (const pm_parameters_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the requireds field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"requireds\":", 12);
- const pm_node_list_t *requireds = &cast->requireds;
- pm_buffer_append_byte(buffer, '[');
-
- for (size_t index = 0; index < requireds->size; index++) {
- if (index != 0) pm_buffer_append_byte(buffer, ',');
- pm_dump_json(buffer, parser, requireds->nodes[index]);
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the optionals field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"optionals\":", 12);
- const pm_node_list_t *optionals = &cast->optionals;
- pm_buffer_append_byte(buffer, '[');
-
- for (size_t index = 0; index < optionals->size; index++) {
- if (index != 0) pm_buffer_append_byte(buffer, ',');
- pm_dump_json(buffer, parser, optionals->nodes[index]);
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the rest field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"rest\":", 7);
- if (cast->rest != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->rest);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the posts field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"posts\":", 8);
- const pm_node_list_t *posts = &cast->posts;
- pm_buffer_append_byte(buffer, '[');
-
- for (size_t index = 0; index < posts->size; index++) {
- if (index != 0) pm_buffer_append_byte(buffer, ',');
- pm_dump_json(buffer, parser, posts->nodes[index]);
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the keywords field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"keywords\":", 11);
- const pm_node_list_t *keywords = &cast->keywords;
- pm_buffer_append_byte(buffer, '[');
-
- for (size_t index = 0; index < keywords->size; index++) {
- if (index != 0) pm_buffer_append_byte(buffer, ',');
- pm_dump_json(buffer, parser, keywords->nodes[index]);
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the keyword_rest field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"keyword_rest\":", 15);
- if (cast->keyword_rest != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->keyword_rest);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the block field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"block\":", 8);
- if (cast->block != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->block);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_PARENTHESES_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"ParenthesesNode\",\"location\":", 37);
-
- const pm_parentheses_node_t *cast = (const pm_parentheses_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the ParenthesesNodeFlags field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"flags\":", 8);
- size_t flags = 0;
- pm_buffer_append_byte(buffer, '[');
- if (PM_NODE_FLAG_P(cast, PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"MULTIPLE_STATEMENTS\"", 21);
- flags++;
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the body field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"body\":", 7);
- if (cast->body != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->body);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the opening_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"opening_loc\":", 14);
- pm_dump_json_location(buffer, &cast->opening_loc);
-
- // Dump the closing_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"closing_loc\":", 14);
- pm_dump_json_location(buffer, &cast->closing_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_PINNED_EXPRESSION_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"PinnedExpressionNode\",\"location\":", 42);
-
- const pm_pinned_expression_node_t *cast = (const pm_pinned_expression_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the expression field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"expression\":", 13);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->expression);
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- // Dump the lparen_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"lparen_loc\":", 13);
- pm_dump_json_location(buffer, &cast->lparen_loc);
-
- // Dump the rparen_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"rparen_loc\":", 13);
- pm_dump_json_location(buffer, &cast->rparen_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_PINNED_VARIABLE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"PinnedVariableNode\",\"location\":", 40);
-
- const pm_pinned_variable_node_t *cast = (const pm_pinned_variable_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the variable field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"variable\":", 11);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->variable);
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_POST_EXECUTION_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"PostExecutionNode\",\"location\":", 39);
-
- const pm_post_execution_node_t *cast = (const pm_post_execution_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the statements field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"statements\":", 13);
- if (cast->statements != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"keyword_loc\":", 14);
- pm_dump_json_location(buffer, &cast->keyword_loc);
-
- // Dump the opening_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"opening_loc\":", 14);
- pm_dump_json_location(buffer, &cast->opening_loc);
-
- // Dump the closing_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"closing_loc\":", 14);
- pm_dump_json_location(buffer, &cast->closing_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_PRE_EXECUTION_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"PreExecutionNode\",\"location\":", 38);
-
- const pm_pre_execution_node_t *cast = (const pm_pre_execution_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the statements field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"statements\":", 13);
- if (cast->statements != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"keyword_loc\":", 14);
- pm_dump_json_location(buffer, &cast->keyword_loc);
-
- // Dump the opening_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"opening_loc\":", 14);
- pm_dump_json_location(buffer, &cast->opening_loc);
-
- // Dump the closing_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"closing_loc\":", 14);
- pm_dump_json_location(buffer, &cast->closing_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_PROGRAM_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"ProgramNode\",\"location\":", 33);
-
- const pm_program_node_t *cast = (const pm_program_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the locals field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"locals\":", 9);
- const pm_constant_id_list_t *locals = &cast->locals;
- pm_buffer_append_byte(buffer, '[');
-
- for (size_t index = 0; index < locals->size; index++) {
- if (index != 0) pm_buffer_append_byte(buffer, ',');
- pm_dump_json_constant(buffer, parser, locals->ids[index]);
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the statements field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"statements\":", 13);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_RANGE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"RangeNode\",\"location\":", 31);
-
- const pm_range_node_t *cast = (const pm_range_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the RangeFlags field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"flags\":", 8);
- size_t flags = 0;
- pm_buffer_append_byte(buffer, '[');
- if (PM_NODE_FLAG_P(cast, PM_RANGE_FLAGS_EXCLUDE_END)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"EXCLUDE_END\"", 13);
- flags++;
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the left field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"left\":", 7);
- if (cast->left != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->left);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the right field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"right\":", 8);
- if (cast->right != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->right);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_RATIONAL_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"RationalNode\",\"location\":", 34);
-
- const pm_rational_node_t *cast = (const pm_rational_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the IntegerBaseFlags field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"flags\":", 8);
- size_t flags = 0;
- pm_buffer_append_byte(buffer, '[');
- if (PM_NODE_FLAG_P(cast, PM_INTEGER_BASE_FLAGS_BINARY)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"BINARY\"", 8);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_INTEGER_BASE_FLAGS_DECIMAL)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"DECIMAL\"", 9);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_INTEGER_BASE_FLAGS_OCTAL)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"OCTAL\"", 7);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_INTEGER_BASE_FLAGS_HEXADECIMAL)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"HEXADECIMAL\"", 13);
- flags++;
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the numerator field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"numerator\":", 12);
- pm_integer_string(buffer, &cast->numerator);
-
- // Dump the denominator field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"denominator\":", 14);
- pm_integer_string(buffer, &cast->denominator);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_REDO_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"RedoNode\",\"location\":", 30);
-
- const pm_redo_node_t *cast = (const pm_redo_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_REGULAR_EXPRESSION_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"RegularExpressionNode\",\"location\":", 43);
-
- const pm_regular_expression_node_t *cast = (const pm_regular_expression_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the RegularExpressionFlags field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"flags\":", 8);
- size_t flags = 0;
- pm_buffer_append_byte(buffer, '[');
- if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"IGNORE_CASE\"", 13);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"EXTENDED\"", 10);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"MULTI_LINE\"", 12);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_ONCE)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"ONCE\"", 6);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_EUC_JP)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"EUC_JP\"", 8);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"ASCII_8BIT\"", 12);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"WINDOWS_31J\"", 13);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_UTF_8)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"UTF_8\"", 7);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"FORCED_UTF8_ENCODING\"", 22);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"FORCED_BINARY_ENCODING\"", 24);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"FORCED_US_ASCII_ENCODING\"", 26);
- flags++;
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the opening_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"opening_loc\":", 14);
- pm_dump_json_location(buffer, &cast->opening_loc);
-
- // Dump the content_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"content_loc\":", 14);
- pm_dump_json_location(buffer, &cast->content_loc);
-
- // Dump the closing_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"closing_loc\":", 14);
- pm_dump_json_location(buffer, &cast->closing_loc);
-
- // Dump the unescaped field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"unescaped\":", 12);
- const pm_string_t *unescaped = &cast->unescaped;
- pm_buffer_append_byte(buffer, '"');
- pm_buffer_append_source(buffer, pm_string_source(unescaped), pm_string_length(unescaped), PM_BUFFER_ESCAPING_JSON);
- pm_buffer_append_byte(buffer, '"');
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_REQUIRED_KEYWORD_PARAMETER_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"RequiredKeywordParameterNode\",\"location\":", 50);
-
- const pm_required_keyword_parameter_node_t *cast = (const pm_required_keyword_parameter_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the ParameterFlags field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"flags\":", 8);
- size_t flags = 0;
- pm_buffer_append_byte(buffer, '[');
- if (PM_NODE_FLAG_P(cast, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"REPEATED_PARAMETER\"", 20);
- flags++;
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- pm_dump_json_constant(buffer, parser, cast->name);
-
- // Dump the name_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name_loc\":", 11);
- pm_dump_json_location(buffer, &cast->name_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_REQUIRED_PARAMETER_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"RequiredParameterNode\",\"location\":", 43);
-
- const pm_required_parameter_node_t *cast = (const pm_required_parameter_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the ParameterFlags field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"flags\":", 8);
- size_t flags = 0;
- pm_buffer_append_byte(buffer, '[');
- if (PM_NODE_FLAG_P(cast, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"REPEATED_PARAMETER\"", 20);
- flags++;
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- pm_dump_json_constant(buffer, parser, cast->name);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_RESCUE_MODIFIER_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"RescueModifierNode\",\"location\":", 40);
-
- const pm_rescue_modifier_node_t *cast = (const pm_rescue_modifier_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the expression field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"expression\":", 13);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->expression);
-
- // Dump the keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"keyword_loc\":", 14);
- pm_dump_json_location(buffer, &cast->keyword_loc);
-
- // Dump the rescue_expression field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"rescue_expression\":", 20);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->rescue_expression);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_RESCUE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"RescueNode\",\"location\":", 32);
-
- const pm_rescue_node_t *cast = (const pm_rescue_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"keyword_loc\":", 14);
- pm_dump_json_location(buffer, &cast->keyword_loc);
-
- // Dump the exceptions field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"exceptions\":", 13);
- const pm_node_list_t *exceptions = &cast->exceptions;
- pm_buffer_append_byte(buffer, '[');
-
- for (size_t index = 0; index < exceptions->size; index++) {
- if (index != 0) pm_buffer_append_byte(buffer, ',');
- pm_dump_json(buffer, parser, exceptions->nodes[index]);
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- if (cast->operator_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->operator_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the reference field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"reference\":", 12);
- if (cast->reference != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->reference);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the then_keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"then_keyword_loc\":", 19);
- if (cast->then_keyword_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->then_keyword_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the statements field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"statements\":", 13);
- if (cast->statements != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the subsequent field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"subsequent\":", 13);
- if (cast->subsequent != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->subsequent);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_REST_PARAMETER_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"RestParameterNode\",\"location\":", 39);
-
- const pm_rest_parameter_node_t *cast = (const pm_rest_parameter_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the ParameterFlags field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"flags\":", 8);
- size_t flags = 0;
- pm_buffer_append_byte(buffer, '[');
- if (PM_NODE_FLAG_P(cast, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"REPEATED_PARAMETER\"", 20);
- flags++;
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the name field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name\":", 7);
- if (cast->name != PM_CONSTANT_ID_UNSET) {
- pm_dump_json_constant(buffer, parser, cast->name);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the name_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"name_loc\":", 11);
- if (cast->name_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->name_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_RETRY_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"RetryNode\",\"location\":", 31);
-
- const pm_retry_node_t *cast = (const pm_retry_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_RETURN_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"ReturnNode\",\"location\":", 32);
-
- const pm_return_node_t *cast = (const pm_return_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"keyword_loc\":", 14);
- pm_dump_json_location(buffer, &cast->keyword_loc);
-
- // Dump the arguments field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"arguments\":", 12);
- if (cast->arguments != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->arguments);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_SELF_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"SelfNode\",\"location\":", 30);
-
- const pm_self_node_t *cast = (const pm_self_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_SHAREABLE_CONSTANT_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"ShareableConstantNode\",\"location\":", 43);
-
- const pm_shareable_constant_node_t *cast = (const pm_shareable_constant_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the ShareableConstantNodeFlags field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"flags\":", 8);
- size_t flags = 0;
- pm_buffer_append_byte(buffer, '[');
- if (PM_NODE_FLAG_P(cast, PM_SHAREABLE_CONSTANT_NODE_FLAGS_LITERAL)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"LITERAL\"", 9);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_SHAREABLE_CONSTANT_NODE_FLAGS_EXPERIMENTAL_EVERYTHING)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"EXPERIMENTAL_EVERYTHING\"", 25);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_SHAREABLE_CONSTANT_NODE_FLAGS_EXPERIMENTAL_COPY)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"EXPERIMENTAL_COPY\"", 19);
- flags++;
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the write field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"write\":", 8);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->write);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_SINGLETON_CLASS_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"SingletonClassNode\",\"location\":", 40);
-
- const pm_singleton_class_node_t *cast = (const pm_singleton_class_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the locals field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"locals\":", 9);
- const pm_constant_id_list_t *locals = &cast->locals;
- pm_buffer_append_byte(buffer, '[');
-
- for (size_t index = 0; index < locals->size; index++) {
- if (index != 0) pm_buffer_append_byte(buffer, ',');
- pm_dump_json_constant(buffer, parser, locals->ids[index]);
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the class_keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"class_keyword_loc\":", 20);
- pm_dump_json_location(buffer, &cast->class_keyword_loc);
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- // Dump the expression field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"expression\":", 13);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->expression);
-
- // Dump the body field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"body\":", 7);
- if (cast->body != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->body);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the end_keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"end_keyword_loc\":", 18);
- pm_dump_json_location(buffer, &cast->end_keyword_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_SOURCE_ENCODING_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"SourceEncodingNode\",\"location\":", 40);
-
- const pm_source_encoding_node_t *cast = (const pm_source_encoding_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_SOURCE_FILE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"SourceFileNode\",\"location\":", 36);
-
- const pm_source_file_node_t *cast = (const pm_source_file_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the StringFlags field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"flags\":", 8);
- size_t flags = 0;
- pm_buffer_append_byte(buffer, '[');
- if (PM_NODE_FLAG_P(cast, PM_STRING_FLAGS_FORCED_UTF8_ENCODING)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"FORCED_UTF8_ENCODING\"", 22);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_STRING_FLAGS_FORCED_BINARY_ENCODING)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"FORCED_BINARY_ENCODING\"", 24);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_STRING_FLAGS_FROZEN)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"FROZEN\"", 8);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_STRING_FLAGS_MUTABLE)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"MUTABLE\"", 9);
- flags++;
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the filepath field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"filepath\":", 11);
- const pm_string_t *filepath = &cast->filepath;
- pm_buffer_append_byte(buffer, '"');
- pm_buffer_append_source(buffer, pm_string_source(filepath), pm_string_length(filepath), PM_BUFFER_ESCAPING_JSON);
- pm_buffer_append_byte(buffer, '"');
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_SOURCE_LINE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"SourceLineNode\",\"location\":", 36);
-
- const pm_source_line_node_t *cast = (const pm_source_line_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_SPLAT_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"SplatNode\",\"location\":", 31);
-
- const pm_splat_node_t *cast = (const pm_splat_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the operator_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"operator_loc\":", 15);
- pm_dump_json_location(buffer, &cast->operator_loc);
-
- // Dump the expression field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"expression\":", 13);
- if (cast->expression != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->expression);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_STATEMENTS_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"StatementsNode\",\"location\":", 36);
-
- const pm_statements_node_t *cast = (const pm_statements_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the body field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"body\":", 7);
- const pm_node_list_t *body = &cast->body;
- pm_buffer_append_byte(buffer, '[');
-
- for (size_t index = 0; index < body->size; index++) {
- if (index != 0) pm_buffer_append_byte(buffer, ',');
- pm_dump_json(buffer, parser, body->nodes[index]);
- }
- pm_buffer_append_byte(buffer, ']');
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_STRING_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"StringNode\",\"location\":", 32);
-
- const pm_string_node_t *cast = (const pm_string_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the StringFlags field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"flags\":", 8);
- size_t flags = 0;
- pm_buffer_append_byte(buffer, '[');
- if (PM_NODE_FLAG_P(cast, PM_STRING_FLAGS_FORCED_UTF8_ENCODING)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"FORCED_UTF8_ENCODING\"", 22);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_STRING_FLAGS_FORCED_BINARY_ENCODING)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"FORCED_BINARY_ENCODING\"", 24);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_STRING_FLAGS_FROZEN)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"FROZEN\"", 8);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_STRING_FLAGS_MUTABLE)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"MUTABLE\"", 9);
- flags++;
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the opening_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"opening_loc\":", 14);
- if (cast->opening_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->opening_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the content_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"content_loc\":", 14);
- pm_dump_json_location(buffer, &cast->content_loc);
-
- // Dump the closing_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"closing_loc\":", 14);
- if (cast->closing_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->closing_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the unescaped field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"unescaped\":", 12);
- const pm_string_t *unescaped = &cast->unescaped;
- pm_buffer_append_byte(buffer, '"');
- pm_buffer_append_source(buffer, pm_string_source(unescaped), pm_string_length(unescaped), PM_BUFFER_ESCAPING_JSON);
- pm_buffer_append_byte(buffer, '"');
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_SUPER_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"SuperNode\",\"location\":", 31);
-
- const pm_super_node_t *cast = (const pm_super_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"keyword_loc\":", 14);
- pm_dump_json_location(buffer, &cast->keyword_loc);
-
- // Dump the lparen_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"lparen_loc\":", 13);
- if (cast->lparen_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->lparen_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the arguments field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"arguments\":", 12);
- if (cast->arguments != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->arguments);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the rparen_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"rparen_loc\":", 13);
- if (cast->rparen_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->rparen_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the block field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"block\":", 8);
- if (cast->block != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->block);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_SYMBOL_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"SymbolNode\",\"location\":", 32);
-
- const pm_symbol_node_t *cast = (const pm_symbol_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the SymbolFlags field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"flags\":", 8);
- size_t flags = 0;
- pm_buffer_append_byte(buffer, '[');
- if (PM_NODE_FLAG_P(cast, PM_SYMBOL_FLAGS_FORCED_UTF8_ENCODING)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"FORCED_UTF8_ENCODING\"", 22);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_SYMBOL_FLAGS_FORCED_BINARY_ENCODING)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"FORCED_BINARY_ENCODING\"", 24);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"FORCED_US_ASCII_ENCODING\"", 26);
- flags++;
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the opening_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"opening_loc\":", 14);
- if (cast->opening_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->opening_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the value_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"value_loc\":", 12);
- if (cast->value_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->value_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the closing_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"closing_loc\":", 14);
- if (cast->closing_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->closing_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the unescaped field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"unescaped\":", 12);
- const pm_string_t *unescaped = &cast->unescaped;
- pm_buffer_append_byte(buffer, '"');
- pm_buffer_append_source(buffer, pm_string_source(unescaped), pm_string_length(unescaped), PM_BUFFER_ESCAPING_JSON);
- pm_buffer_append_byte(buffer, '"');
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_TRUE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"TrueNode\",\"location\":", 30);
-
- const pm_true_node_t *cast = (const pm_true_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_UNDEF_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"UndefNode\",\"location\":", 31);
-
- const pm_undef_node_t *cast = (const pm_undef_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the names field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"names\":", 8);
- const pm_node_list_t *names = &cast->names;
- pm_buffer_append_byte(buffer, '[');
-
- for (size_t index = 0; index < names->size; index++) {
- if (index != 0) pm_buffer_append_byte(buffer, ',');
- pm_dump_json(buffer, parser, names->nodes[index]);
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"keyword_loc\":", 14);
- pm_dump_json_location(buffer, &cast->keyword_loc);
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_UNLESS_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"UnlessNode\",\"location\":", 32);
-
- const pm_unless_node_t *cast = (const pm_unless_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"keyword_loc\":", 14);
- pm_dump_json_location(buffer, &cast->keyword_loc);
-
- // Dump the predicate field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"predicate\":", 12);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->predicate);
-
- // Dump the then_keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"then_keyword_loc\":", 19);
- if (cast->then_keyword_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->then_keyword_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the statements field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"statements\":", 13);
- if (cast->statements != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the else_clause field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"else_clause\":", 14);
- if (cast->else_clause != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->else_clause);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the end_keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"end_keyword_loc\":", 18);
- if (cast->end_keyword_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->end_keyword_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_UNTIL_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"UntilNode\",\"location\":", 31);
-
- const pm_until_node_t *cast = (const pm_until_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the LoopFlags field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"flags\":", 8);
- size_t flags = 0;
- pm_buffer_append_byte(buffer, '[');
- if (PM_NODE_FLAG_P(cast, PM_LOOP_FLAGS_BEGIN_MODIFIER)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"BEGIN_MODIFIER\"", 16);
- flags++;
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"keyword_loc\":", 14);
- pm_dump_json_location(buffer, &cast->keyword_loc);
-
- // Dump the do_keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"do_keyword_loc\":", 17);
- if (cast->do_keyword_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->do_keyword_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the closing_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"closing_loc\":", 14);
- if (cast->closing_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->closing_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the predicate field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"predicate\":", 12);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->predicate);
-
- // Dump the statements field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"statements\":", 13);
- if (cast->statements != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_WHEN_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"WhenNode\",\"location\":", 30);
-
- const pm_when_node_t *cast = (const pm_when_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"keyword_loc\":", 14);
- pm_dump_json_location(buffer, &cast->keyword_loc);
-
- // Dump the conditions field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"conditions\":", 13);
- const pm_node_list_t *conditions = &cast->conditions;
- pm_buffer_append_byte(buffer, '[');
-
- for (size_t index = 0; index < conditions->size; index++) {
- if (index != 0) pm_buffer_append_byte(buffer, ',');
- pm_dump_json(buffer, parser, conditions->nodes[index]);
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the then_keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"then_keyword_loc\":", 19);
- if (cast->then_keyword_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->then_keyword_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the statements field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"statements\":", 13);
- if (cast->statements != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_WHILE_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"WhileNode\",\"location\":", 31);
-
- const pm_while_node_t *cast = (const pm_while_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the LoopFlags field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"flags\":", 8);
- size_t flags = 0;
- pm_buffer_append_byte(buffer, '[');
- if (PM_NODE_FLAG_P(cast, PM_LOOP_FLAGS_BEGIN_MODIFIER)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"BEGIN_MODIFIER\"", 16);
- flags++;
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"keyword_loc\":", 14);
- pm_dump_json_location(buffer, &cast->keyword_loc);
-
- // Dump the do_keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"do_keyword_loc\":", 17);
- if (cast->do_keyword_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->do_keyword_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the closing_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"closing_loc\":", 14);
- if (cast->closing_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->closing_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the predicate field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"predicate\":", 12);
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->predicate);
-
- // Dump the statements field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"statements\":", 13);
- if (cast->statements != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->statements);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_X_STRING_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"XStringNode\",\"location\":", 33);
-
- const pm_x_string_node_t *cast = (const pm_x_string_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the EncodingFlags field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"flags\":", 8);
- size_t flags = 0;
- pm_buffer_append_byte(buffer, '[');
- if (PM_NODE_FLAG_P(cast, PM_ENCODING_FLAGS_FORCED_UTF8_ENCODING)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"FORCED_UTF8_ENCODING\"", 22);
- flags++;
- }
- if (PM_NODE_FLAG_P(cast, PM_ENCODING_FLAGS_FORCED_BINARY_ENCODING)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"FORCED_BINARY_ENCODING\"", 24);
- flags++;
- }
- pm_buffer_append_byte(buffer, ']');
-
- // Dump the opening_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"opening_loc\":", 14);
- pm_dump_json_location(buffer, &cast->opening_loc);
-
- // Dump the content_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"content_loc\":", 14);
- pm_dump_json_location(buffer, &cast->content_loc);
-
- // Dump the closing_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"closing_loc\":", 14);
- pm_dump_json_location(buffer, &cast->closing_loc);
-
- // Dump the unescaped field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"unescaped\":", 12);
- const pm_string_t *unescaped = &cast->unescaped;
- pm_buffer_append_byte(buffer, '"');
- pm_buffer_append_source(buffer, pm_string_source(unescaped), pm_string_length(unescaped), PM_BUFFER_ESCAPING_JSON);
- pm_buffer_append_byte(buffer, '"');
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_YIELD_NODE: {
- pm_buffer_append_string(buffer, "{\"type\":\"YieldNode\",\"location\":", 31);
-
- const pm_yield_node_t *cast = (const pm_yield_node_t *) node;
- pm_dump_json_location(buffer, &cast->base.location);
-
- // Dump the keyword_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"keyword_loc\":", 14);
- pm_dump_json_location(buffer, &cast->keyword_loc);
-
- // Dump the lparen_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"lparen_loc\":", 13);
- if (cast->lparen_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->lparen_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the arguments field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"arguments\":", 12);
- if (cast->arguments != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast->arguments);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- // Dump the rparen_loc field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"rparen_loc\":", 13);
- if (cast->rparen_loc.length != 0) {
- pm_dump_json_location(buffer, &cast->rparen_loc);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- case PM_SCOPE_NODE:
- break;
- }
-}
-
-#endif
diff --git a/prism/templates/lib/prism/dsl.rb.erb b/prism/templates/lib/prism/dsl.rb.erb
index 6dcbbec100994a..95c4dac71a95a1 100644
--- a/prism/templates/lib/prism/dsl.rb.erb
+++ b/prism/templates/lib/prism/dsl.rb.erb
@@ -5,7 +5,7 @@ module Prism
# The DSL module provides a set of methods that can be used to create prism
# nodes in a more concise manner. For example, instead of writing:
#
- # source = Prism::Source.for("[1]", 1, [])
+ # source = Prism::Source.for("[1]", 1, [0])
#
# Prism::ArrayNode.new(
# source,
@@ -62,7 +62,7 @@ module Prism
#--
#: (String string) -> Source
def source(string)
- Source.for(string, 1, [])
+ Source.for(string, 1, build_offsets(string))
end
# Create a new Location object.
@@ -136,7 +136,7 @@ module Prism
#--
#: () -> Source
def default_source
- Source.for("", 1, [])
+ Source.for("", 1, [0])
end
# The default location object that gets attached to nodes if no location is
@@ -154,5 +154,19 @@ module Prism
def default_node(source, location)
MissingNode.new(source, -1, location, 0)
end
+
+ private
+
+ # Build the newline byte offset array for the given source string.
+ #--
+ #: (String source) -> Array[Integer]
+ def build_offsets(source)
+ offsets = [0]
+ start = 0
+ while (index = source.byteindex("\n", start))
+ offsets << (start = index + 1)
+ end
+ offsets
+ end
end
end
diff --git a/prism_compile.c b/prism_compile.c
index 66f7d6f2fa32f7..063febb193b5d3 100644
--- a/prism_compile.c
+++ b/prism_compile.c
@@ -142,6 +142,19 @@ pm_iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, int line, int node
#define PM_COMPILE_NOT_POPPED(node) \
pm_compile_node(iseq, (node), ret, false, scope_node)
+// Direct-indexed lookup table. -1 means "not present".
+#define PM_INDEX_LOOKUP_TABLE_INIT { .values = NULL, .capacity = 0, .owned = false }
+
+static inline void
+pm_index_lookup_table_init(pm_index_lookup_table_t *table, int constants_size, rb_iseq_t *iseq)
+{
+ int capacity = constants_size + PM_INDEX_LOOKUP_SPECIALS;
+ table->values = compile_data_alloc2_type(iseq, int, capacity);
+ memset(table->values, -1, capacity * sizeof(int));
+ table->capacity = capacity;
+ table->owned = false;
+}
+
/**
* Cached line lookup that avoids repeated binary searches. Since the compiler
* walks the AST roughly in source order, consecutive lookups tend to be for
@@ -1311,14 +1324,15 @@ static pm_local_index_t
pm_lookup_local_index(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, pm_constant_id_t constant_id, int start_depth)
{
pm_local_index_t lindex = { 0 };
- st_data_t local_index;
+ int local_index;
int level;
for (level = 0; level < start_depth; level++) {
scope_node = scope_node->previous;
}
- while (!st_lookup(scope_node->index_lookup_table, constant_id, &local_index)) {
+ while (!pm_index_lookup_table_lookup(&scope_node->index_lookup_table, constant_id, &local_index))
+ {
level++;
if (scope_node->previous) {
@@ -1342,12 +1356,10 @@ pm_lookup_local_index(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, pm_con
// We add a constants mapping on the scope_node which is a mapping from
// these constant_id indexes to the CRuby IDs that they represent.
// This helper method allows easy access to those IDs
-static ID
+static inline ID
pm_constant_id_lookup(const pm_scope_node_t *scope_node, pm_constant_id_t constant_id)
{
- if (constant_id < 1 || constant_id > pm_parser_constants_size(scope_node->parser)) {
- rb_bug("constant_id out of range: %u", (unsigned int)constant_id);
- }
+ RUBY_ASSERT(constant_id >= 1 && constant_id <= pm_parser_constants_size(scope_node->parser));
return scope_node->constants[constant_id - 1];
}
@@ -1356,18 +1368,11 @@ pm_new_child_iseq(rb_iseq_t *iseq, pm_scope_node_t *node, VALUE name, const rb_i
{
debugs("[new_child_iseq]> ---------------------------------------\n");
int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
- int error_state;
- rb_iseq_t *ret_iseq = pm_iseq_new_with_opt(node, name,
+ rb_iseq_t *ret_iseq = pm_iseq_build(node, name,
rb_iseq_path(iseq), rb_iseq_realpath(iseq),
line_no, parent,
isolated_depth ? isolated_depth + 1 : 0,
- type, ISEQ_COMPILE_DATA(iseq)->option, &error_state);
-
- if (error_state) {
- pm_scope_node_destroy(node);
- RUBY_ASSERT(ret_iseq == NULL);
- rb_jump_tag(error_state);
- }
+ type, ISEQ_COMPILE_DATA(iseq)->option);
debugs("[new_child_iseq]< ---------------------------------------\n");
return ret_iseq;
}
@@ -3307,30 +3312,27 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
void
pm_scope_node_init(const pm_node_t *node, pm_scope_node_t *scope, pm_scope_node_t *previous)
{
- // This is very important, otherwise the scope node could be seen as having
- // certain flags set that _should not_ be set.
- memset(scope, 0, sizeof(pm_scope_node_t));
+ if (previous) {
+ // Copy inherited fields from the parent scope in one shot, then
+ // zero out the fields that are scope-specific.
+ *scope = *previous;
+ scope->locals = (pm_constant_id_list_t) { 0 };
+ scope->parameters = NULL;
+ scope->body = NULL;
+ scope->local_table_for_iseq_size = 0;
+ scope->index_lookup_table = (pm_index_lookup_table_t) PM_INDEX_LOOKUP_TABLE_INIT;
+ scope->pre_execution_anchor = NULL;
+ }
+ else {
+ memset(scope, 0, sizeof(pm_scope_node_t));
+ }
scope->base.type = PM_SCOPE_NODE;
scope->base.location.start = node->location.start;
scope->base.location.length = node->location.length;
-
scope->previous = previous;
scope->ast_node = (pm_node_t *) node;
- if (previous) {
- scope->parser = previous->parser;
- scope->options = previous->options;
- scope->line_offsets = previous->line_offsets;
- scope->start_line = previous->start_line;
- scope->encoding = previous->encoding;
- scope->filepath_encoding = previous->filepath_encoding;
- scope->constants = previous->constants;
- scope->coverage_enabled = previous->coverage_enabled;
- scope->script_lines = previous->script_lines;
- scope->last_line = previous->last_line;
- }
-
switch (PM_NODE_TYPE(node)) {
case PM_BLOCK_NODE: {
const pm_block_node_t *cast = (const pm_block_node_t *) node;
@@ -3427,8 +3429,8 @@ pm_scope_node_init(const pm_node_t *node, pm_scope_node_t *scope, pm_scope_node_
void
pm_scope_node_destroy(pm_scope_node_t *scope_node)
{
- if (scope_node->index_lookup_table) {
- st_free_table(scope_node->index_lookup_table);
+ if (scope_node->index_lookup_table.owned) {
+ xfree(scope_node->index_lookup_table.values);
}
}
@@ -3618,8 +3620,7 @@ pm_compile_builtin_mandatory_only_method(rb_iseq_t *iseq, pm_scope_node_t *scope
pm_scope_node_t next_scope_node;
pm_scope_node_init(&def.base, &next_scope_node, scope_node);
- int error_state;
- const rb_iseq_t *mandatory_only_iseq = pm_iseq_new_with_opt(
+ const rb_iseq_t *mandatory_only_iseq = pm_iseq_build(
&next_scope_node,
rb_iseq_base_label(iseq),
rb_iseq_path(iseq),
@@ -3628,16 +3629,10 @@ pm_compile_builtin_mandatory_only_method(rb_iseq_t *iseq, pm_scope_node_t *scope
NULL,
0,
ISEQ_TYPE_METHOD,
- ISEQ_COMPILE_DATA(iseq)->option,
- &error_state
+ ISEQ_COMPILE_DATA(iseq)->option
);
RB_OBJ_WRITE(iseq, &ISEQ_BODY(iseq)->mandatory_only_iseq, (VALUE)mandatory_only_iseq);
- if (error_state) {
- RUBY_ASSERT(ISEQ_BODY(iseq)->mandatory_only_iseq == NULL);
- rb_jump_tag(error_state);
- }
-
pm_scope_node_destroy(&next_scope_node);
return COMPILE_OK;
}
@@ -4755,33 +4750,7 @@ pm_add_ensure_iseq(LINK_ANCHOR *const ret, rb_iseq_t *iseq, int is_return, pm_sc
PUSH_SEQ(ret, ensure);
}
-struct pm_local_table_insert_ctx {
- pm_scope_node_t *scope_node;
- rb_ast_id_table_t *local_table_for_iseq;
- int local_index;
-};
-
-static int
-pm_local_table_insert_func(st_data_t *key, st_data_t *value, st_data_t arg, int existing)
-{
- if (!existing) {
- pm_constant_id_t constant_id = (pm_constant_id_t) *key;
- struct pm_local_table_insert_ctx * ctx = (struct pm_local_table_insert_ctx *) arg;
-
- pm_scope_node_t *scope_node = ctx->scope_node;
- rb_ast_id_table_t *local_table_for_iseq = ctx->local_table_for_iseq;
- int local_index = ctx->local_index;
- ID local = pm_constant_id_lookup(scope_node, constant_id);
- local_table_for_iseq->ids[local_index] = local;
-
- *value = (st_data_t)local_index;
-
- ctx->local_index++;
- }
-
- return ST_CONTINUE;
-}
/**
* Insert a local into the local table for the iseq. This is used to create the
@@ -4789,24 +4758,23 @@ pm_local_table_insert_func(st_data_t *key, st_data_t *value, st_data_t arg, int
* inserted are regular named locals, as opposed to special forwarding locals.
*/
static void
-pm_insert_local_index(pm_constant_id_t constant_id, int local_index, st_table *index_lookup_table, rb_ast_id_table_t *local_table_for_iseq, pm_scope_node_t *scope_node)
+pm_insert_local_index(pm_constant_id_t constant_id, int local_index, pm_index_lookup_table_t *index_lookup_table, rb_ast_id_table_t *local_table_for_iseq, pm_scope_node_t *scope_node)
{
RUBY_ASSERT((constant_id & PM_SPECIAL_CONSTANT_FLAG) == 0);
ID local = pm_constant_id_lookup(scope_node, constant_id);
local_table_for_iseq->ids[local_index] = local;
- st_insert(index_lookup_table, (st_data_t) constant_id, (st_data_t) local_index);
+ pm_index_lookup_table_insert(index_lookup_table, constant_id, local_index);
}
/**
- * Insert a local into the local table for the iseq that is a special forwarding
- * local variable.
+ * Insert a special forwarding local (*, **, &, ...) into the local table.
*/
static void
-pm_insert_local_special(ID local_name, int local_index, st_table *index_lookup_table, rb_ast_id_table_t *local_table_for_iseq)
+pm_insert_local_special(pm_constant_id_t special_id, ID local_name, int local_index, pm_index_lookup_table_t *index_lookup_table, rb_ast_id_table_t *local_table_for_iseq)
{
local_table_for_iseq->ids[local_index] = local_name;
- st_insert(index_lookup_table, (st_data_t) (local_name | PM_SPECIAL_CONSTANT_FLAG), (st_data_t) local_index);
+ pm_index_lookup_table_insert(index_lookup_table, special_id, local_index);
}
/**
@@ -4816,7 +4784,7 @@ pm_insert_local_special(ID local_name, int local_index, st_table *index_lookup_t
* local and index lookup tables and increments the local index as necessary.
*/
static int
-pm_compile_destructured_param_locals(const pm_multi_target_node_t *node, st_table *index_lookup_table, rb_ast_id_table_t *local_table_for_iseq, pm_scope_node_t *scope_node, int local_index)
+pm_compile_destructured_param_locals(const pm_multi_target_node_t *node, pm_index_lookup_table_t *index_lookup_table, rb_ast_id_table_t *local_table_for_iseq, pm_scope_node_t *scope_node, int local_index)
{
for (size_t index = 0; index < node->lefts.size; index++) {
const pm_node_t *left = node->lefts.nodes[index];
@@ -6312,8 +6280,9 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
// hidden variables and multi target nodes
size_t locals_size = locals->size;
- // Index lookup table buffer size is only the number of the locals
- st_table *index_lookup_table = st_init_numtable();
+ // Index lookup table buffer size is only the number of the locals.
+ // We'll initialize it after computing table_size below.
+ pm_index_lookup_table_t index_lookup_table = PM_INDEX_LOOKUP_TABLE_INIT;
int table_size = (int) locals_size;
@@ -6437,6 +6406,10 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
rb_ast_id_table_t *local_table_for_iseq = ALLOCV(idtmp, sizeof(rb_ast_id_table_t) + table_size * sizeof(ID));
local_table_for_iseq->size = table_size;
+ // Init the direct-indexed lookup table. The capacity is based on the
+ // parser's constant pool size (for regular locals) plus special slots.
+ pm_index_lookup_table_init(&index_lookup_table, (int) pm_parser_constants_size(scope_node->parser), iseq);
+
//********END OF STEP 1**********
//********STEP 2**********
@@ -6489,7 +6462,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
local_table_for_iseq->ids[local_index] = local;
}
else {
- pm_insert_local_index(param->name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
+ pm_insert_local_index(param->name, local_index, &index_lookup_table, local_table_for_iseq, scope_node);
}
break;
@@ -6522,7 +6495,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
local_table_for_iseq->ids[local_index] = local;
}
else {
- pm_insert_local_index(name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
+ pm_insert_local_index(name, local_index, &index_lookup_table, local_table_for_iseq, scope_node);
}
}
}
@@ -6548,14 +6521,14 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
local_table_for_iseq->ids[local_index] = local;
}
else {
- pm_insert_local_index(name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
+ pm_insert_local_index(name, local_index, &index_lookup_table, local_table_for_iseq, scope_node);
}
}
else {
// def foo(a, (b, *c, d), e = 1, *, g, (h, *i, j), k:, l: 1, **m, &n)
// ^
body->param.flags.anon_rest = true;
- pm_insert_local_special(idMULT, local_index, index_lookup_table, local_table_for_iseq);
+ pm_insert_local_special(PM_CONSTANT_MULT, idMULT, local_index, &index_lookup_table, local_table_for_iseq);
}
local_index++;
@@ -6595,7 +6568,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
local_table_for_iseq->ids[local_index] = local;
}
else {
- pm_insert_local_index(param->name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
+ pm_insert_local_index(param->name, local_index, &index_lookup_table, local_table_for_iseq, scope_node);
}
break;
}
@@ -6630,7 +6603,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
local_table_for_iseq->ids[local_index] = local;
}
else {
- pm_insert_local_index(name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
+ pm_insert_local_index(name, local_index, &index_lookup_table, local_table_for_iseq, scope_node);
}
local_index++;
}
@@ -6660,7 +6633,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
local_table_for_iseq->ids[local_index] = local;
}
else {
- pm_insert_local_index(name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
+ pm_insert_local_index(name, local_index, &index_lookup_table, local_table_for_iseq, scope_node);
}
local_index++;
}
@@ -6722,12 +6695,12 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
local_table_for_iseq->ids[local_index] = local;
}
else {
- pm_insert_local_index(constant_id, local_index, index_lookup_table, local_table_for_iseq, scope_node);
+ pm_insert_local_index(constant_id, local_index, &index_lookup_table, local_table_for_iseq, scope_node);
}
}
else {
body->param.flags.anon_kwrest = true;
- pm_insert_local_special(idPow, local_index, index_lookup_table, local_table_for_iseq);
+ pm_insert_local_special(PM_CONSTANT_POW, idPow, local_index, &index_lookup_table, local_table_for_iseq);
}
local_index++;
@@ -6741,7 +6714,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
body->param.rest_start = local_index;
body->param.flags.has_rest = true;
body->param.flags.anon_rest = true;
- pm_insert_local_special(idMULT, local_index++, index_lookup_table, local_table_for_iseq);
+ pm_insert_local_special(PM_CONSTANT_MULT, idMULT, local_index++, &index_lookup_table, local_table_for_iseq);
// Add the anonymous **
RUBY_ASSERT(!body->param.flags.has_kw);
@@ -6750,16 +6723,16 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
body->param.flags.anon_kwrest = true;
body->param.keyword = keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
keyword->rest_start = local_index;
- pm_insert_local_special(idPow, local_index++, index_lookup_table, local_table_for_iseq);
+ pm_insert_local_special(PM_CONSTANT_POW, idPow, local_index++, &index_lookup_table, local_table_for_iseq);
// Add the anonymous &
body->param.block_start = local_index;
body->param.flags.has_block = true;
- pm_insert_local_special(idAnd, local_index++, index_lookup_table, local_table_for_iseq);
+ pm_insert_local_special(PM_CONSTANT_AND, idAnd, local_index++, &index_lookup_table, local_table_for_iseq);
}
// Add the ...
- pm_insert_local_special(idDot3, local_index++, index_lookup_table, local_table_for_iseq);
+ pm_insert_local_special(PM_CONSTANT_DOT3, idDot3, local_index++, &index_lookup_table, local_table_for_iseq);
break;
}
default:
@@ -6785,11 +6758,11 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
local_table_for_iseq->ids[local_index] = local;
}
else {
- pm_insert_local_index(name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
+ pm_insert_local_index(name, local_index, &index_lookup_table, local_table_for_iseq, scope_node);
}
}
else {
- pm_insert_local_special(idAnd, local_index, index_lookup_table, local_table_for_iseq);
+ pm_insert_local_special(PM_CONSTANT_AND, idAnd, local_index, &index_lookup_table, local_table_for_iseq);
}
local_index++;
@@ -6825,7 +6798,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
const pm_node_t *required = requireds_list->nodes[i];
if (PM_NODE_TYPE_P(required, PM_MULTI_TARGET_NODE)) {
- local_index = pm_compile_destructured_param_locals((const pm_multi_target_node_t *) required, index_lookup_table, local_table_for_iseq, scope_node, local_index);
+ local_index = pm_compile_destructured_param_locals((const pm_multi_target_node_t *) required, &index_lookup_table, local_table_for_iseq, scope_node, local_index);
}
}
}
@@ -6839,7 +6812,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
const pm_node_t *post = posts_list->nodes[i];
if (PM_NODE_TYPE_P(post, PM_MULTI_TARGET_NODE)) {
- local_index = pm_compile_destructured_param_locals((const pm_multi_target_node_t *) post, index_lookup_table, local_table_for_iseq, scope_node, local_index);
+ local_index = pm_compile_destructured_param_locals((const pm_multi_target_node_t *) post, &index_lookup_table, local_table_for_iseq, scope_node, local_index);
}
}
}
@@ -6867,7 +6840,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
const uint8_t param_name[] = { '_', '1' + i };
pm_constant_id_t constant_id = pm_parser_constant_find(scope_node->parser, param_name, 2);
RUBY_ASSERT(constant_id && "parser should fill in any gaps in numbered parameters");
- pm_insert_local_index(constant_id, local_index, index_lookup_table, local_table_for_iseq, scope_node);
+ pm_insert_local_index(constant_id, local_index, &index_lookup_table, local_table_for_iseq, scope_node);
}
body->param.lead_num = maximum;
body->param.flags.has_lead = true;
@@ -6890,7 +6863,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
if (block_locals && block_locals->size) {
for (size_t i = 0; i < block_locals->size; i++, local_index++) {
pm_constant_id_t constant_id = ((const pm_block_local_variable_node_t *) block_locals->nodes[i])->name;
- pm_insert_local_index(constant_id, local_index, index_lookup_table, local_table_for_iseq, scope_node);
+ pm_insert_local_index(constant_id, local_index, &index_lookup_table, local_table_for_iseq, scope_node);
}
}
@@ -6899,14 +6872,13 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
for (size_t i = 0; i < scope_node->locals.size; i++) {
pm_constant_id_t constant_id = locals->ids[i];
if (constant_id) {
- struct pm_local_table_insert_ctx ctx;
- ctx.scope_node = scope_node;
- ctx.local_table_for_iseq = local_table_for_iseq;
- ctx.local_index = local_index;
-
- st_update(index_lookup_table, (st_data_t)constant_id, pm_local_table_insert_func, (st_data_t)&ctx);
-
- local_index = ctx.local_index;
+ int existing;
+ if (!pm_index_lookup_table_lookup(&index_lookup_table, constant_id, &existing)) {
+ ID local = pm_constant_id_lookup(scope_node, constant_id);
+ local_table_for_iseq->ids[local_index] = local;
+ pm_index_lookup_table_insert(&index_lookup_table, constant_id, local_index);
+ local_index++;
+ }
}
}
}
@@ -6914,10 +6886,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
//********END OF STEP 4**********
// We set the index_lookup_table on the scope node so we can
- // refer to the parameters correctly
- if (scope_node->index_lookup_table) {
- st_free_table(scope_node->index_lookup_table);
- }
+ // refer to the parameters correctly.
scope_node->index_lookup_table = index_lookup_table;
iseq_calc_param_size(iseq);
@@ -11389,15 +11358,15 @@ pm_parse_process(pm_parse_result_t *result, pm_node_t *node, VALUE *script_lines
scope_node->line_offsets = pm_parser_line_offsets(parser);
scope_node->start_line = pm_parser_start_line(parser);
size_t constants_size = pm_parser_constants_size(parser);
- scope_node->constants = constants_size ? xcalloc(constants_size, sizeof(ID)) : NULL;
+ scope_node->constants = constants_size ? xmalloc(constants_size * sizeof(ID)) : NULL;
pm_intern_constants_ctx_t intern_ctx = { .constants = scope_node->constants, .encoding = scope_node->encoding, .index = 0 };
pm_parser_constants_each(parser, pm_intern_constants_callback, &intern_ctx);
- scope_node->index_lookup_table = st_init_numtable();
pm_constant_id_list_t *locals = &scope_node->locals;
+ pm_index_lookup_table_init_heap(&scope_node->index_lookup_table, (int) constants_size);
for (size_t index = 0; index < locals->size; index++) {
- st_insert(scope_node->index_lookup_table, locals->ids[index], index);
+ pm_index_lookup_table_insert(&scope_node->index_lookup_table, locals->ids[index], (int) index);
}
// If we got here, this is a success and we can return Qnil to indicate that
diff --git a/prism_compile.h b/prism_compile.h
index 09f611569db700..448579390259b6 100644
--- a/prism_compile.h
+++ b/prism_compile.h
@@ -16,6 +16,82 @@ typedef struct pm_local_index_struct {
// A declaration for the struct that lives in compile.c.
struct iseq_link_anchor;
+/**
+ * A direct-indexed lookup table mapping constant IDs to local variable indices.
+ * Regular constant IDs (1..constants_size) index directly. Special forwarding
+ * parameter IDs (idMULT|FLAG, etc.) are mapped to 4 extra slots at the end.
+ *
+ * All lookups are O(1) — a single array dereference.
+ * The table is arena-allocated for child scopes (no explicit free needed).
+ */
+typedef struct {
+ /** Array of local indices, indexed by constant_id. -1 means not present. */
+ int *values;
+
+ /** Total number of slots (constants_size + PM_INDEX_LOOKUP_SPECIALS). */
+ int capacity;
+
+ /** Whether the values array is heap-allocated and needs explicit free. */
+ bool owned;
+} pm_index_lookup_table_t;
+
+/** Number of extra slots for special forwarding parameter IDs. */
+#define PM_INDEX_LOOKUP_SPECIALS 4
+
+/** Slot offsets for special forwarding parameters (relative to constants_size). */
+#define PM_SPECIAL_CONSTANT_FLAG ((pm_constant_id_t) (1 << 31))
+#define PM_INDEX_LOOKUP_SPECIAL_MULT 0
+#define PM_INDEX_LOOKUP_SPECIAL_POW 1
+#define PM_INDEX_LOOKUP_SPECIAL_AND 2
+#define PM_INDEX_LOOKUP_SPECIAL_DOT3 3
+
+/**
+ * Special constant IDs for forwarding parameters. These use bit 31 to
+ * distinguish them from regular prism constant pool IDs. The lower bits
+ * encode which special slot (0-3) they map to in the lookup table.
+ */
+#define PM_CONSTANT_MULT ((pm_constant_id_t) (PM_SPECIAL_CONSTANT_FLAG | PM_INDEX_LOOKUP_SPECIAL_MULT))
+#define PM_CONSTANT_POW ((pm_constant_id_t) (PM_SPECIAL_CONSTANT_FLAG | PM_INDEX_LOOKUP_SPECIAL_POW))
+#define PM_CONSTANT_AND ((pm_constant_id_t) (PM_SPECIAL_CONSTANT_FLAG | PM_INDEX_LOOKUP_SPECIAL_AND))
+#define PM_CONSTANT_DOT3 ((pm_constant_id_t) (PM_SPECIAL_CONSTANT_FLAG | PM_INDEX_LOOKUP_SPECIAL_DOT3))
+
+static inline int
+pm_index_lookup_table_index(const pm_index_lookup_table_t *table, pm_constant_id_t key)
+{
+ if (LIKELY(!(key & PM_SPECIAL_CONSTANT_FLAG))) {
+ return (int) key - 1;
+ }
+ return table->capacity - PM_INDEX_LOOKUP_SPECIALS + (int)(key & ~PM_SPECIAL_CONSTANT_FLAG);
+}
+
+static inline void
+pm_index_lookup_table_insert(pm_index_lookup_table_t *table, pm_constant_id_t key, int value)
+{
+ int idx = pm_index_lookup_table_index(table, key);
+ RUBY_ASSERT(idx >= 0 && idx < table->capacity);
+ table->values[idx] = value;
+}
+
+static inline int
+pm_index_lookup_table_lookup(const pm_index_lookup_table_t *table, pm_constant_id_t key, int *value)
+{
+ int idx = pm_index_lookup_table_index(table, key);
+ RUBY_ASSERT(idx >= 0 && idx < table->capacity);
+ if (table->values[idx] == -1) return 0;
+ *value = table->values[idx];
+ return 1;
+}
+
+static inline void
+pm_index_lookup_table_init_heap(pm_index_lookup_table_t *table, int constants_size)
+{
+ int cap = constants_size + PM_INDEX_LOOKUP_SPECIALS;
+ table->values = (int *) ruby_xmalloc(cap * sizeof(int));
+ memset(table->values, -1, cap * sizeof(int));
+ table->capacity = cap;
+ table->owned = true;
+}
+
// 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 {
@@ -54,7 +130,14 @@ typedef struct pm_scope_node {
int local_table_for_iseq_size;
ID *constants;
- st_table *index_lookup_table;
+
+ /**
+ * A flat lookup table mapping constant IDs (or special IDs) to local
+ * variable indices. When allocated from the compile data arena (child
+ * scopes), no explicit free is needed. When heap-allocated (top-level
+ * scope in pm_parse_process), owned is set to true so destroy can free it.
+ */
+ pm_index_lookup_table_t index_lookup_table;
// The current coverage setting, passed down through the various scopes.
int coverage_enabled;
@@ -96,12 +179,6 @@ typedef struct {
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))
-
void pm_parse_result_init(pm_parse_result_t *result);
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);
@@ -116,5 +193,6 @@ rb_iseq_t *pm_iseq_new_top(pm_scope_node_t *node, VALUE name, VALUE path, VALUE
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);
+rb_iseq_t *pm_iseq_build(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);
VALUE pm_iseq_compile_node(rb_iseq_t *iseq, pm_scope_node_t *node);
diff --git a/test/prism/newline_test.rb b/test/prism/newline_test.rb
index fefe9def91f1e6..c8914b57dcfac8 100644
--- a/test/prism/newline_test.rb
+++ b/test/prism/newline_test.rb
@@ -17,6 +17,8 @@ class NewlineTest < TestCase
result/breadth_first_search_test.rb
result/static_literals_test.rb
result/warnings_test.rb
+ ruby/find_fixtures.rb
+ ruby/find_test.rb
ruby/parser_test.rb
ruby/ruby_parser_test.rb
]
diff --git a/test/prism/ruby/find_fixtures.rb b/test/prism/ruby/find_fixtures.rb
new file mode 100644
index 00000000000000..df82cc700408b1
--- /dev/null
+++ b/test/prism/ruby/find_fixtures.rb
@@ -0,0 +1,70 @@
+# frozen_string_literal: true
+
+# Test fixtures for Prism.find. These must be in a separate file because
+# source_location returns the file path and Prism.find re-parses the file.
+
+module Prism
+ module FindFixtures
+ module Methods
+ def simple_method
+ 42
+ end
+
+ def method_with_params(a, b, c)
+ a + b + c
+ end
+
+ def method_with_block(&block)
+ block.call
+ end
+
+ def self.singleton_method_fixture
+ :singleton
+ end
+
+ def été
+ :utf8
+ end
+
+ def inline_method; :inline; end
+ end
+
+ module Procs
+ SIMPLE_PROC = proc { 42 }
+ SIMPLE_LAMBDA = ->(x) { x * 2 }
+ MULTI_LINE_LAMBDA = lambda do |x|
+ x + 1
+ end
+ DO_BLOCK_PROC = proc do |x|
+ x - 1
+ end
+ end
+
+ module DefineMethod
+ define_method(:dynamic) { |x| x + 1 }
+ end
+
+ module ForLoop
+ items = [1, 2, 3]
+ for_proc = nil
+ o = Object.new
+ def o.each(&block) = block.call(block)
+ for for_proc in o; end
+ FOR_PROC = for_proc
+ end
+
+ module MultipleOnLine
+ def self.first; end; def self.second; end
+ end
+
+ module Errors
+ def self.divide(a, b)
+ a / b
+ end
+
+ def self.call_undefined
+ undefined_method_call
+ end
+ end
+ end
+end
diff --git a/test/prism/ruby/find_test.rb b/test/prism/ruby/find_test.rb
new file mode 100644
index 00000000000000..5b59113d30db69
--- /dev/null
+++ b/test/prism/ruby/find_test.rb
@@ -0,0 +1,242 @@
+# frozen_string_literal: true
+
+return if RUBY_ENGINE == "ruby" && RUBY_VERSION < "3.4"
+return if defined?(RubyVM::InstructionSequence) && RubyVM::InstructionSequence.compile("").to_a[4][:parser] != :prism
+
+require_relative "../test_helper"
+require_relative "find_fixtures"
+
+module Prism
+ class FindTest < TestCase
+ Fixtures = FindFixtures
+ FIXTURES_PATH = File.expand_path("find_fixtures.rb", __dir__)
+
+ # === Method / UnboundMethod tests ===
+
+ def test_simple_method
+ assert_def_node Prism.find(Fixtures::Methods.instance_method(:simple_method)), :simple_method
+ end
+
+ def test_method_with_params
+ node = Prism.find(Fixtures::Methods.instance_method(:method_with_params))
+ assert_def_node node, :method_with_params
+ assert_equal 3, node.parameters.requireds.length
+ end
+
+ def test_method_with_block_param
+ assert_def_node Prism.find(Fixtures::Methods.instance_method(:method_with_block)), :method_with_block
+ end
+
+ def test_singleton_method
+ assert_def_node Prism.find(Fixtures::Methods.method(:singleton_method_fixture)), :singleton_method_fixture
+ end
+
+ def test_utf8_method_name
+ assert_def_node Prism.find(Fixtures::Methods.instance_method(:été)), :été
+ end
+
+ def test_inline_method
+ assert_def_node Prism.find(Fixtures::Methods.instance_method(:inline_method)), :inline_method
+ end
+
+ def test_bound_method
+ obj = Object.new
+ obj.extend(Fixtures::Methods)
+ assert_def_node Prism.find(obj.method(:simple_method)), :simple_method
+ end
+
+ # === Proc / Lambda tests ===
+
+ def test_simple_proc
+ assert_not_nil Prism.find(Fixtures::Procs::SIMPLE_PROC)
+ end
+
+ def test_simple_lambda
+ assert_not_nil Prism.find(Fixtures::Procs::SIMPLE_LAMBDA)
+ end
+
+ def test_multi_line_lambda
+ assert_not_nil Prism.find(Fixtures::Procs::MULTI_LINE_LAMBDA)
+ end
+
+ def test_do_block_proc
+ assert_not_nil Prism.find(Fixtures::Procs::DO_BLOCK_PROC)
+ end
+
+ # === define_method tests ===
+
+ def test_define_method
+ assert_not_nil Prism.find(Fixtures::DefineMethod.instance_method(:dynamic))
+ end
+
+ def test_define_method_bound
+ obj = Object.new
+ obj.extend(Fixtures::DefineMethod)
+ assert_not_nil Prism.find(obj.method(:dynamic))
+ end
+
+ # === for loop test ===
+
+ def test_for_loop_proc
+ node = Prism.find(Fixtures::ForLoop::FOR_PROC)
+ assert_instance_of ForNode, node
+ end
+
+ # === Thread::Backtrace::Location tests ===
+
+ def test_backtrace_location_zero_division
+ location = zero_division_location
+ assert_not_nil location, "could not find backtrace location in fixtures file"
+ assert_not_nil Prism.find(location)
+ end
+
+ def test_backtrace_location_name_error
+ location = begin
+ Fixtures::Errors.call_undefined
+ rescue NameError => e
+ fixture_backtrace_location(e)
+ end
+
+ assert_not_nil location, "could not find backtrace location in fixtures file"
+ assert_not_nil Prism.find(location)
+ end
+
+ def test_backtrace_location_from_caller
+ # caller_locations returns locations for the current call stack
+ location = caller_locations(0, 1).first
+ node = Prism.find(location)
+ assert_not_nil node
+ end
+
+ def test_backtrace_location_eval_returns_nil
+ location = begin
+ eval("raise 'eval error'")
+ rescue RuntimeError => e
+ e.backtrace_locations.find { |loc| loc.path == "(eval)" || loc.label&.include?("eval") }
+ end
+
+ # eval locations have no file on disk
+ assert_nil Prism.find(location) if location
+ end
+
+ # === Edge cases ===
+
+ def test_nil_source_location
+ # Built-in methods have nil source_location
+ assert_nil Prism.find(method(:puts))
+ end
+
+ def test_argument_error_on_wrong_type
+ assert_raise(ArgumentError) { Prism.find("not a callable") }
+ assert_raise(ArgumentError) { Prism.find(42) }
+ assert_raise(ArgumentError) { Prism.find(nil) }
+ end
+
+ def test_eval_returns_nil
+ # eval'd code has no file on disk
+ m = eval("proc { 1 }")
+ assert_nil Prism.find(m)
+ end
+
+ def test_multiple_methods_on_same_line
+ assert_def_node Prism.find(Fixtures::MultipleOnLine.method(:first)), :first
+ assert_def_node Prism.find(Fixtures::MultipleOnLine.method(:second)), :second
+ end
+
+ # === Fallback (line-based) tests via rubyvm: false ===
+
+ def test_fallback_simple_method
+ assert_def_node Prism.find(Fixtures::Methods.instance_method(:simple_method), rubyvm: false), :simple_method
+ end
+
+ def test_fallback_singleton_method
+ assert_def_node Prism.find(Fixtures::Methods.method(:singleton_method_fixture), rubyvm: false), :singleton_method_fixture
+ end
+
+ def test_fallback_lambda
+ node = Prism.find(Fixtures::Procs::SIMPLE_LAMBDA, rubyvm: false)
+ assert_instance_of LambdaNode, node
+ end
+
+ def test_fallback_proc
+ node = Prism.find(Fixtures::Procs::SIMPLE_PROC, rubyvm: false)
+ assert_instance_of CallNode, node
+ assert node.block.is_a?(BlockNode)
+ end
+
+ def test_fallback_define_method
+ node = Prism.find(Fixtures::DefineMethod.instance_method(:dynamic), rubyvm: false)
+ assert_instance_of CallNode, node
+ assert node.block.is_a?(BlockNode)
+ end
+
+ def test_fallback_for_loop
+ node = Prism.find(Fixtures::ForLoop::FOR_PROC, rubyvm: false)
+ assert_instance_of ForNode, node
+ end
+
+ def test_fallback_backtrace_location
+ location = zero_division_location
+ assert_not_nil location
+ node = Prism.find(location, rubyvm: false)
+ assert_not_nil node
+ assert_equal location.lineno, node.location.start_line
+ end
+
+ # === Node identity with node_id (CRuby only) ===
+
+ if defined?(RubyVM::InstructionSequence)
+ def test_node_id_matches_iseq
+ m = Fixtures::Methods.instance_method(:simple_method)
+ node = Prism.find(m)
+ assert_equal node_id_of(m), node.node_id
+ end
+
+ def test_node_id_for_lambda
+ node = Prism.find(Fixtures::Procs::SIMPLE_LAMBDA)
+ assert_equal node_id_of(Fixtures::Procs::SIMPLE_LAMBDA), node.node_id
+ end
+
+ def test_node_id_for_proc
+ node = Prism.find(Fixtures::Procs::SIMPLE_PROC)
+ assert_equal node_id_of(Fixtures::Procs::SIMPLE_PROC), node.node_id
+ end
+
+ def test_node_id_for_define_method
+ m = Fixtures::DefineMethod.instance_method(:dynamic)
+ node = Prism.find(m)
+ assert_equal node_id_of(m), node.node_id
+ end
+
+ def test_node_id_for_backtrace_location
+ location = zero_division_location
+ assert_not_nil location
+ expected_node_id = RubyVM::AbstractSyntaxTree.node_id_for_backtrace_location(location)
+
+ node = Prism.find(location)
+ assert_equal expected_node_id, node.node_id
+ end
+ end
+
+ private
+
+ def assert_def_node(node, expected_name)
+ assert_instance_of DefNode, node
+ assert_equal expected_name, node.name
+ end
+
+ def fixture_backtrace_location(exception)
+ exception.backtrace_locations.find { |loc| loc.path == FIXTURES_PATH }
+ end
+
+ def zero_division_location
+ Fixtures::Errors.divide(1, 0)
+ rescue ZeroDivisionError => e
+ fixture_backtrace_location(e)
+ end
+
+ def node_id_of(callable)
+ RubyVM::InstructionSequence.of(callable).to_a[4][:node_id]
+ end
+ end
+end
diff --git a/tool/make-snapshot b/tool/make-snapshot
index 4af6a855ebb793..1b080d41683ac3 100755
--- a/tool/make-snapshot
+++ b/tool/make-snapshot
@@ -500,6 +500,36 @@ touch-unicode-files:
ENV["CACHE_SAVE"] = "no"
make = MAKE.new(args)
return unless make.run("update-download")
+ # Build dump_ast for mk_builtin_loader.rb. CC=false in prereq.status
+ # prevents make from compiling it, so we build it directly here.
+ # Generate prism sources/headers from templates first, then compile.
+ dump_ast = vars["DUMP_AST"]
+ if dump_ast && !dump_ast.empty? && !File.exist?(dump_ast) && File.exist?("tool/dump_ast.c")
+ prism_template = "prism/templates/template.rb"
+ if File.exist?(prism_template)
+ baseruby_cmd = baseruby.shellsplit
+ Dir.glob("prism/templates/src/*.c.erb") do |erb|
+ name = File.basename(erb, ".erb")
+ out = "prism/#{name}"
+ system(*baseruby_cmd, prism_template, "src/#{name}", out) unless File.exist?(out)
+ end
+ %w[include/prism/ast.h include/prism/internal/diagnostic.h].each do |hdr|
+ out = "prism/#{hdr.delete_prefix("include/prism/")}"
+ FileUtils.mkpath(File.dirname(out))
+ system(*baseruby_cmd, prism_template, hdr, out) unless File.exist?(out)
+ end
+ end
+ prism_srcs = Dir.glob("prism/*.c").reject {|f| %w[api_node extension].include?(File.basename(f, ".c"))}
+ unless prism_srcs.empty?
+ print "building dump_ast..."
+ if system("cc", "-o", dump_ast, "-Iprism", "-I.", "tool/dump_ast.c", *prism_srcs)
+ clean.add(dump_ast)
+ puts $colorize.pass(" done")
+ else
+ puts $colorize.fail(" failed")
+ end
+ end
+ end
clean.push("rbconfig.rb", ".rbconfig.time", "enc.mk", "ext/ripper/y.output", ".revision.time")
Dir.glob("**/*") do |dest|
next unless File.symlink?(dest)
diff --git a/vm_eval.c b/vm_eval.c
index 4216ec56f33291..25d366f5cd19e6 100644
--- a/vm_eval.c
+++ b/vm_eval.c
@@ -1840,9 +1840,8 @@ pm_eval_make_iseq(VALUE src, VALUE fname, int line,
const pm_options_scope_t *options_scope = pm_options_scope(result.options, scopes_count - scopes_index - 1);
parent_scope->coverage_enabled = coverage_enabled;
parent_scope->parser = result.parser;
- parent_scope->index_lookup_table = st_init_numtable();
-
int locals_count = ISEQ_BODY(iseq)->local_table_size;
+ pm_index_lookup_table_init_heap(&parent_scope->index_lookup_table, (int) pm_parser_constants_size(result.parser));
parent_scope->local_table_for_iseq_size = locals_count;
pm_constant_id_list_init(&parent_scope->locals);
@@ -1877,7 +1876,7 @@ pm_eval_make_iseq(VALUE src, VALUE fname, int line,
constant_id = pm_parser_constant_find(result.parser, source, length);
}
- st_insert(parent_scope->index_lookup_table, (st_data_t) constant_id, (st_data_t) local_index);
+ pm_index_lookup_table_insert(&parent_scope->index_lookup_table, constant_id, local_index);
}
pm_constant_id_list_append(result.arena, &parent_scope->locals, constant_id);
diff --git a/zjit/src/backend/lir.rs b/zjit/src/backend/lir.rs
index 062c8243642f4b..4640bac15c6b02 100644
--- a/zjit/src/backend/lir.rs
+++ b/zjit/src/backend/lir.rs
@@ -1810,7 +1810,7 @@ impl Assembler
let block_ids = self.block_order();
let num_blocks = block_ids.len();
- for block_id in block_ids {
+ for (i, block_id) in block_ids.iter().enumerate() {
let block = &self.basic_blocks[block_id.0];
// Entry blocks shouldn't ever be preceded by something that can
// stomp on this block.
@@ -1823,6 +1823,18 @@ impl Assembler
self.expand_branch_insn(insn, &mut insns);
}
+ // Eliminate redundant jumps: if the last instruction is an
+ // unconditional jump to the next block in the linear order,
+ // remove it and let execution fall through.
+ if let Some(next_block_id) = block_ids.get(i + 1) {
+ let next_label = self.block_label(*next_block_id);
+ if let Some(Insn::Jmp(Target::Label(label))) = insns.last() {
+ if *label == next_label {
+ insns.pop();
+ }
+ }
+ }
+
// Make sure we don't stomp on the next function
if block_id.0 == num_blocks - 1 {
insns.push(Insn::PadPatchPoint);
diff --git a/zjit/src/backend/x86_64/mod.rs b/zjit/src/backend/x86_64/mod.rs
index 476670ee4922ff..661093e78dc748 100644
--- a/zjit/src/backend/x86_64/mod.rs
+++ b/zjit/src/backend/x86_64/mod.rs
@@ -183,40 +183,12 @@ impl Assembler {
// being used. It is okay not to use their output here.
#[allow(unused_must_use)]
match &mut insn {
- Insn::Add { left, right, out } |
- Insn::Sub { left, right, out } |
- Insn::Mul { left, right, out } |
- Insn::And { left, right, out } |
- Insn::Or { left, right, out } |
- Insn::Xor { left, right, out } => {
- match (*left, *right) {
- (Opnd::Mem(_), Opnd::Mem(_)) => {
- *left = asm.load(*left);
- *right = asm.load(*right);
- },
- (Opnd::Mem(_), Opnd::UImm(_) | Opnd::Imm(_)) => {
- *left = asm.load(*left);
- },
- // Instruction output whose live range spans beyond this instruction
- (Opnd::VReg { idx: _, .. }, _) => {
- *left = asm.load(*left);
- },
- // We have to load memory operands to avoid corrupting them
- (Opnd::Mem(_), _) => {
- *left = asm.load(*left);
- },
- // We have to load register operands to avoid corrupting them
- (Opnd::Reg(_), _) => {
- if *left != *out {
- *left = asm.load(*left);
- }
- },
- // The first operand can't be an immediate value
- (Opnd::UImm(_), _) => {
- *left = asm.load(*left);
- }
- _ => {}
- }
+ Insn::Add { .. } |
+ Insn::Sub { .. } |
+ Insn::Mul { .. } |
+ Insn::And { .. } |
+ Insn::Or { .. } |
+ Insn::Xor { .. } => {
asm.push_insn(insn);
},
Insn::Cmp { left, right } => {
@@ -427,6 +399,13 @@ impl Assembler {
}
}
+ fn assert_out_is_phys_reg_or_stack_mem(out: Opnd) {
+ assert!(
+ matches!(out, Opnd::Reg(_) | Opnd::Mem(Mem { base: MemBase::Stack { .. }, .. })),
+ "x86_scratch_split expects out to be a physical register or stack memory, got {out:?}"
+ );
+ }
+
/// If both opnd and other are Opnd::Mem, split opnd with scratch_opnd.
fn split_if_both_memory(asm: &mut Assembler, opnd: Opnd, other: Opnd, scratch_opnd: Opnd) -> Opnd {
if let (Opnd::Mem(_), Opnd::Mem(_)) = (opnd, other) {
@@ -481,17 +460,59 @@ impl Assembler {
Insn::And { left, right, out } |
Insn::Or { left, right, out } |
Insn::Xor { left, right, out } => {
+ assert_out_is_phys_reg_or_stack_mem(*out);
+
+ // Sequential pipeline to lower binops into x86 two-operand form.
+ // Uses SCRATCH0 for left, SCRATCH1 for right to avoid conflicts.
+
+ // Phase 1: Protect right if it occupies the same location as out,
+ // since we'll overwrite out when moving left into it.
+ // Compare before lowering (Stack membases change during lowering).
+ let right_eq_out = out == right;
+ *out = lower_stack_membase(*out, &stack_state);
+ if right_eq_out {
+ asm.mov(SCRATCH1_OPND, *out);
+ *right = SCRATCH1_OPND;
+ }
+
+ // Phase 2: Lower stack memory bases
*left = split_stack_membase(asm, *left, SCRATCH0_OPND, &stack_state);
- *left = split_if_both_memory(asm, *left, *right, SCRATCH0_OPND);
- *right = split_stack_membase(asm, *right, SCRATCH1_OPND, &stack_state);
+ if !right_eq_out {
+ *right = split_stack_membase(asm, *right, SCRATCH1_OPND, &stack_state);
+ }
+
+ // Phase 3: If right is a Mem whose base register equals the out
+ // register, materialize it before we clobber out.
+ if let (Opnd::Reg(out_reg), Opnd::Mem(Mem { base: MemBase::Reg(base_reg_no), .. })) = (*out, *right) {
+ if out_reg.reg_no == base_reg_no {
+ asm.mov(SCRATCH1_OPND, *right);
+ *right = SCRATCH1_OPND;
+ }
+ }
+
+ // Phase 4: x86 can't encode two memory operands.
+ if let (Opnd::Mem(_), Opnd::Mem(_)) = (*out, *right) {
+ asm.mov(SCRATCH1_OPND, *right);
+ *right = SCRATCH1_OPND;
+ }
+
+ // Phase 5: Move left into out (x86 two-operand form: OP clobbers dst).
+ // For Mem out, split large left immediates first (mov [mem], imm64 is invalid).
+ if let Opnd::Mem(_) = *out {
+ *left = split_64bit_immediate(asm, *left, SCRATCH0_OPND);
+ }
+ asm_mov(asm, *out, *left, SCRATCH0_OPND);
+ *left = *out;
+
+ // Phase 6: Split large right immediates (>32-bit) into a register.
*right = split_64bit_immediate(asm, *right, SCRATCH1_OPND);
- *out = lower_stack_membase(*out, &stack_state);
- let (out, left) = (*out, *left);
+ // Phase 7: Emit the instruction.
asm.push_insn(insn);
- asm_mov(asm, out, left, SCRATCH0_OPND);
}
Insn::Mul { left, right, out } => {
+ assert_out_is_phys_reg_or_stack_mem(*out);
+
*left = split_stack_membase(asm, *left, SCRATCH0_OPND, &stack_state);
*left = split_if_both_memory(asm, *left, *right, SCRATCH0_OPND);
*right = split_stack_membase(asm, *right, SCRATCH1_OPND, &stack_state);
@@ -1243,6 +1264,119 @@ mod tests {
(asm, CodeBlock::new_dummy())
}
+ fn stack_mem(stack_idx: usize) -> Opnd {
+ Opnd::Mem(Mem {
+ base: MemBase::Stack { stack_idx, num_bits: 64 },
+ disp: 0,
+ num_bits: 64,
+ })
+ }
+
+ fn stack_indirect_mem(stack_idx: usize) -> Opnd {
+ Opnd::Mem(Mem {
+ base: MemBase::StackIndirect { stack_idx },
+ disp: 0,
+ num_bits: 64,
+ })
+ }
+
+ #[derive(Clone, Copy, Debug)]
+ enum BinOpKind {
+ Add,
+ Sub,
+ And,
+ Or,
+ Xor,
+ }
+
+ fn split_binop(kind: BinOpKind, left: Opnd, right: Opnd, out: Opnd) -> Assembler {
+ let (mut asm, _) = setup_asm();
+ match kind {
+ BinOpKind::Add => asm.push_insn(Insn::Add { left, right, out }),
+ BinOpKind::Sub => asm.push_insn(Insn::Sub { left, right, out }),
+ BinOpKind::And => asm.push_insn(Insn::And { left, right, out }),
+ BinOpKind::Or => asm.push_insn(Insn::Or { left, right, out }),
+ BinOpKind::Xor => asm.push_insn(Insn::Xor { left, right, out }),
+ }
+ asm.x86_scratch_split()
+ }
+
+ fn binop_mnemonic(kind: BinOpKind) -> &'static str {
+ match kind {
+ BinOpKind::Add => "add",
+ BinOpKind::Sub => "sub",
+ BinOpKind::And => "and",
+ BinOpKind::Or => "or",
+ BinOpKind::Xor => "xor",
+ }
+ }
+
+ fn split_binop_disasm_lines(kind: BinOpKind, left: Opnd, right: Opnd, out: Opnd) -> Vec {
+ let mut asm = split_binop(kind, left, right, out);
+ let mut cb = CodeBlock::new_dummy();
+ for name in &asm.label_names {
+ cb.new_label(name.to_string());
+ }
+ assert!(asm.x86_emit(&mut cb).is_some(), "{kind:?}: x86_emit failed");
+
+ cb.disasm()
+ .lines()
+ .map(str::trim)
+ .filter(|line| !line.is_empty())
+ .map(|line| {
+ line.split_once(": ")
+ .map(|(_, rest)| rest.to_string())
+ .unwrap_or_else(|| line.to_string())
+ })
+ .collect()
+ }
+
+ fn assert_split_binop_case(kind: BinOpKind, left: Opnd, right: Opnd, out: Opnd, case: &str) {
+ fn reg_names(reg: Reg) -> (&'static str, &'static str) {
+ const RAX_NO: u8 = RAX_REG.reg_no;
+ const RDI_NO: u8 = RDI_REG.reg_no;
+ const R13_NO: u8 = R13_REG.reg_no;
+ match reg.reg_no {
+ RAX_NO => ("rax", "eax"),
+ RDI_NO => ("rdi", "edi"),
+ R13_NO => ("r13", "r13d"),
+ _ => panic!("unexpected register in test helper: {reg:?}"),
+ }
+ }
+
+ let lines = split_binop_disasm_lines(kind, left, right, out);
+ let mnemonic = binop_mnemonic(kind);
+ let matching: Vec<(usize, &String)> = lines.iter()
+ .enumerate()
+ .filter(|(_, line)| line.starts_with(&format!("{mnemonic} ")))
+ .collect();
+
+ assert_eq!(matching.len(), 1, "{kind:?} {case}: expected exactly one `{mnemonic}` in disasm, got {lines:?}");
+ assert!(
+ !matching[0].1.contains("], qword ptr ["),
+ "{kind:?} {case}: emitted mem/mem `{mnemonic}` in disasm {lines:?}"
+ );
+
+ if let (Opnd::Reg(out_reg), Opnd::Imm(_) | Opnd::UImm(_)) = (out, left) {
+ let (out64, out32) = reg_names(out_reg);
+ let prelude = &lines[..matching[0].0];
+ assert!(
+ prelude.iter().any(|line|
+ line.starts_with(&format!("mov {out64}, ")) ||
+ line.starts_with(&format!("mov {out32}, ")) ||
+ line.starts_with(&format!("movabs {out64}, "))
+ ),
+ "{kind:?} {case}: expected left immediate to be materialized into output register before `{mnemonic}`, got {lines:?}"
+ );
+ }
+
+ if matches!(right, Opnd::Imm(value) if imm_num_bits(value) > 32)
+ || matches!(right, Opnd::UImm(value) if imm_num_bits(value as i64) > 32)
+ {
+ assert!(lines.iter().any(|line| line.starts_with("movabs ")), "{kind:?} {case}: expected movabs materialization for 64-bit immediate, got {lines:?}");
+ }
+ }
+
#[test]
fn test_lir_string() {
use crate::hir::SideExitReason;
@@ -1587,12 +1721,8 @@ mod tests {
asm.mov(CFP, sp); // should be merged to add
asm.compile_with_num_regs(&mut cb, 1);
- assert_disasm_snapshot!(cb.disasm(), @"
- 0x0: mov rdi, r13
- 0x3: add rdi, 0x40
- 0x7: mov r13, rdi
- ");
- assert_snapshot!(cb.hexdump(), @"4c89ef4883c7404989fd");
+ assert_disasm_snapshot!(cb.disasm(), @" 0x0: add r13, 0x40");
+ assert_snapshot!(cb.hexdump(), @"4983c540");
}
#[test]
@@ -1614,12 +1744,8 @@ mod tests {
asm.mov(CFP, sp); // should be merged to add
asm.compile_with_num_regs(&mut cb, 1);
- assert_disasm_snapshot!(cb.disasm(), @"
- 0x0: mov rdi, r13
- 0x3: sub rdi, 0x40
- 0x7: mov r13, rdi
- ");
- assert_snapshot!(cb.hexdump(), @"4c89ef4883ef404989fd");
+ assert_disasm_snapshot!(cb.disasm(), @" 0x0: sub r13, 0x40");
+ assert_snapshot!(cb.hexdump(), @"4983ed40");
}
#[test]
@@ -1641,12 +1767,8 @@ mod tests {
asm.mov(CFP, sp); // should be merged to add
asm.compile_with_num_regs(&mut cb, 1);
- assert_disasm_snapshot!(cb.disasm(), @"
- 0x0: mov rdi, r13
- 0x3: and rdi, 0x40
- 0x7: mov r13, rdi
- ");
- assert_snapshot!(cb.hexdump(), @"4c89ef4883e7404989fd");
+ assert_disasm_snapshot!(cb.disasm(), @" 0x0: and r13, 0x40");
+ assert_snapshot!(cb.hexdump(), @"4983e540");
}
#[test]
@@ -1657,12 +1779,8 @@ mod tests {
asm.mov(CFP, sp); // should be merged to add
asm.compile_with_num_regs(&mut cb, 1);
- assert_disasm_snapshot!(cb.disasm(), @"
- 0x0: mov rdi, r13
- 0x3: or rdi, 0x40
- 0x7: mov r13, rdi
- ");
- assert_snapshot!(cb.hexdump(), @"4c89ef4883cf404989fd");
+ assert_disasm_snapshot!(cb.disasm(), @" 0x0: or r13, 0x40");
+ assert_snapshot!(cb.hexdump(), @"4983cd40");
}
#[test]
@@ -1673,12 +1791,8 @@ mod tests {
asm.mov(CFP, sp); // should be merged to add
asm.compile_with_num_regs(&mut cb, 1);
- assert_disasm_snapshot!(cb.disasm(), @"
- 0x0: mov rdi, r13
- 0x3: xor rdi, 0x40
- 0x7: mov r13, rdi
- ");
- assert_snapshot!(cb.hexdump(), @"4c89ef4883f7404989fd");
+ assert_disasm_snapshot!(cb.disasm(), @" 0x0: xor r13, 0x40");
+ assert_snapshot!(cb.hexdump(), @"4983f540");
}
#[test]
@@ -1834,12 +1948,11 @@ mod tests {
0x20: pop rdx
0x21: pop rsi
0x22: pop rdi
- 0x23: mov rdi, rdi
- 0x26: add rdi, rsi
- 0x29: mov rdi, rdx
- 0x2c: add rdi, rcx
+ 0x23: add rdi, rsi
+ 0x26: mov rdi, rdx
+ 0x29: add rdi, rcx
");
- assert_snapshot!(cb.hexdump(), @"bf01000000be02000000ba03000000b90400000057565251b800000000ffd0595a5e5f4889ff4801f74889d74801cf");
+ assert_snapshot!(cb.hexdump(), @"bf01000000be02000000ba03000000b90400000057565251b800000000ffd0595a5e5f4801f74889d74801cf");
}
#[test]
@@ -1878,14 +1991,13 @@ mod tests {
0x2c: pop rdx
0x2d: pop rsi
0x2e: pop rdi
- 0x2f: mov rdi, rdi
- 0x32: add rdi, rsi
- 0x35: mov rdi, rdx
- 0x38: add rdi, rcx
- 0x3b: mov rdi, rdx
- 0x3e: add rdi, r8
+ 0x2f: add rdi, rsi
+ 0x32: mov rdi, rdx
+ 0x35: add rdi, rcx
+ 0x38: mov rdi, rdx
+ 0x3b: add rdi, r8
");
- assert_snapshot!(cb.hexdump(), @"bf01000000be02000000ba03000000b90400000041b80500000057565251415057b800000000ffd05f4158595a5e5f4889ff4801f74889d74801cf4889d74c01c7");
+ assert_snapshot!(cb.hexdump(), @"bf01000000be02000000ba03000000b90400000041b80500000057565251415057b800000000ffd05f4158595a5e5f4801f74889d74801cf4889d74c01c7");
}
#[test]
@@ -2078,4 +2190,271 @@ mod tests {
");
assert_snapshot!(cb.hexdump(), @"4c8d5df84c895df8");
}
+
+ #[test]
+ fn test_add_split_direct_mem() {
+ // RAX is safe to be clobbered because it's an output
+ // c_ret <- add stack[0], stack[1]
+ let lines = split_binop_disasm_lines(BinOpKind::Add, stack_mem(0), stack_mem(1), C_RET_OPND);
+
+ // load scratch0, [stack[0]]
+ // add scratch0, [stack[1]]
+ // mov c_ret, scratch0
+ assert_snapshot!(lines.join("\n"), @"
+ mov rax, qword ptr [rbp - 8]
+ add rax, qword ptr [rbp - 0x10]
+ ");
+ }
+
+ #[test]
+ fn test_add_split_stack_indirect_left_uses_scratch0_for_base_and_result() {
+ // stack[1] <- add stack[mem[0]], cfp
+ let lines = split_binop_disasm_lines(BinOpKind::Add, stack_indirect_mem(0), CFP, stack_mem(1));
+
+ // load scratch0, [stack[left_base]]
+ // load scratch0, [scratch0]
+ // seed [stack[out]] from scratch0, then add right in place
+ assert_snapshot!(lines.join("\n"), @"
+ mov r11, qword ptr [rbp - 8]
+ mov r11, qword ptr [r11]
+ mov qword ptr [rbp - 0x10], r11
+ add qword ptr [rbp - 0x10], r13
+ ");
+ }
+
+ #[test]
+ fn test_add_split_stack_indirect_right_uses_separate_base_scratch() {
+ // mem[1] <- add cfp, mem[stack[0]]
+ let lines = split_binop_disasm_lines(BinOpKind::Add, CFP, stack_indirect_mem(0), stack_mem(1));
+
+ // load scratch1, [stack[right_base]]
+ // load scratch1, [scratch1]
+ // seed [stack[out]] from left, then add scratch1 in place
+ assert_snapshot!(lines.join("\n"), @"
+ mov r10, qword ptr [rbp - 8]
+ mov r10, qword ptr [r10]
+ mov qword ptr [rbp - 0x10], r13
+ add qword ptr [rbp - 0x10], r10
+ ");
+ }
+
+ #[test]
+ fn test_add_split_two_stack_indirect_inputs_need_two_scratch_regs() {
+ // stack[2] <- add [stack[0]], [stack[1]]
+ let lines = split_binop_disasm_lines(BinOpKind::Add,
+ stack_indirect_mem(0), stack_indirect_mem(1), stack_mem(2));
+
+ // load scratch0, [stack[left_base]]
+ // load scratch0, [scratch0]
+ // load scratch1, [stack[right_base]]
+ // load scratch1, [scratch1]
+ // mov [stack[out]], scratch0; add [stack[out]], scratch1
+ assert_snapshot!(lines.join("\n"), @"
+ mov r11, qword ptr [rbp - 8]
+ mov r10, qword ptr [rbp - 0x10]
+ mov r10, qword ptr [r10]
+ mov r11, qword ptr [r11]
+ mov qword ptr [rbp - 0x18], r11
+ add qword ptr [rbp - 0x18], r10
+ ");
+ }
+
+ #[test]
+ fn test_add_split_memory_output_can_compute_in_place() {
+ // stack[1] <- add cfp, stack[0]
+ let lines = split_binop_disasm_lines(BinOpKind::Add, CFP, stack_mem(0), stack_mem(1));
+
+ // Seed the output slot with the left register, then perform the add in place.
+ assert_snapshot!(lines.join("\n"), @"
+ mov r10, qword ptr [rbp - 8]
+ mov qword ptr [rbp - 0x10], r13
+ add qword ptr [rbp - 0x10], r10
+ ");
+ }
+
+ #[test]
+ fn test_add_split_reg_mem_mem_when_right_equals_out() {
+ // stack[1] <- add cfp, stack[1]
+ //
+ // Preserve the original RHS/output value first, then seed the output
+ // slot with the left register and finish the add in place.
+ let lines = split_binop_disasm_lines(BinOpKind::Add, CFP, stack_mem(1), stack_mem(1));
+
+ assert_snapshot!(lines.join("\n"), @"
+ mov r10, qword ptr [rbp - 0x10]
+ mov qword ptr [rbp - 0x10], r13
+ add qword ptr [rbp - 0x10], r10
+ ");
+ }
+
+ #[test]
+ #[should_panic(expected = "x86_scratch_split expects out to be a physical register or stack memory")]
+ fn test_binop_split_rejects_non_stack_memory_output() {
+ let _ = split_binop(BinOpKind::Add, CFP, C_RET_OPND, Opnd::mem(64, CFP, 8));
+ }
+
+ #[test]
+ fn test_add_split_mem_mem_mem_when_right_equals_out() {
+ // stack[1] <- add stack[0], stack[1]
+ //
+ // Preserve the original RHS/output value first, then reload the LHS and
+ // write the result back to the output stack slot.
+ let mut asm = split_binop(BinOpKind::Add, stack_mem(0), stack_mem(1), stack_mem(1));
+ let mut cb = CodeBlock::new_dummy();
+ for name in &asm.label_names {
+ cb.new_label(name.to_string());
+ }
+ assert!(asm.x86_emit(&mut cb).is_some());
+
+ assert_disasm_snapshot!(cb.disasm(), @"
+ 0x0: mov r10, qword ptr [rbp - 0x10]
+ 0x4: mov r11, qword ptr [rbp - 8]
+ 0x8: mov qword ptr [rbp - 0x10], r11
+ 0xc: add qword ptr [rbp - 0x10], r10
+ ");
+ }
+
+ #[test]
+ fn test_add_split_output_reg_reused_as_input_memory_base() {
+ // cfp <- add [cfp + 8], [cfp + 16]
+ //
+ // Preserve the RHS first because reusing `out` for the LHS would otherwise
+ // clobber the base register needed to address the RHS memory operand.
+ let mut asm = split_binop(
+ BinOpKind::Add,
+ Opnd::mem(64, CFP, 8),
+ Opnd::mem(64, CFP, 16),
+ CFP,
+ );
+ let mut cb = CodeBlock::new_dummy();
+ for name in &asm.label_names {
+ cb.new_label(name.to_string());
+ }
+ assert!(asm.x86_emit(&mut cb).is_some());
+
+ assert_disasm_snapshot!(cb.disasm(), @"
+ 0x0: mov r10, qword ptr [r13 + 0x10]
+ 0x4: mov r13, qword ptr [r13 + 8]
+ 0x8: add r13, r10
+ ");
+ assert_snapshot!(cb.hexdump(), @"4d8b55104d8b6d084d01d5");
+ }
+
+ #[test]
+ fn test_add_split_output_reg_reused_as_stack_indirect_memory_base() {
+ // cfp <- add mem[stack[0]], mem[stack[1]]
+ //
+ // The LHS lowering reuses `out` as the temporary base register for the
+ // stack-indirect address, then the RHS uses the normal scratch register.
+ let mut asm = split_binop(
+ BinOpKind::Add,
+ stack_indirect_mem(0),
+ stack_indirect_mem(1),
+ CFP,
+ );
+ let mut cb = CodeBlock::new_dummy();
+ for name in &asm.label_names {
+ cb.new_label(name.to_string());
+ }
+ assert!(asm.x86_emit(&mut cb).is_some());
+
+ assert_disasm_snapshot!(cb.disasm(), @"
+ 0x0: mov r11, qword ptr [rbp - 8]
+ 0x4: mov r10, qword ptr [rbp - 0x10]
+ 0x8: mov r13, qword ptr [r11]
+ 0xb: add r13, qword ptr [r10]
+ ");
+ }
+
+ #[test]
+ fn test_add_split_output_reg_reused_as_input_memory_base_with_imm() {
+ // cfp <- add 7, [cfp + 16]
+ //
+ // Preserve the RHS first because reusing `out` for the immediate
+ // materialization would otherwise clobber the base register needed for
+ // the memory operand.
+ let lines = split_binop_disasm_lines(
+ BinOpKind::Add,
+ Opnd::Imm(7),
+ Opnd::mem(64, CFP, 16),
+ CFP,
+ );
+
+ assert_snapshot!(lines.join("\n"), @"
+ mov r10, qword ptr [r13 + 0x10]
+ mov r13d, 7
+ add r13, r10
+ ");
+ }
+
+ #[test]
+ fn test_binop_split_matrix() {
+ let left_cases = [
+ ("reg", CFP),
+ ("mem_reg", Opnd::mem(64, C_RET_OPND, 8)),
+ ("mem_stack", stack_mem(0)),
+ ("mem_stack_indirect", stack_indirect_mem(0)),
+ ("imm32", Opnd::Imm(7)),
+ ("imm64", Opnd::UImm(0x1_0000_0000)),
+ ];
+ let right_cases = [
+ ("reg", C_RET_OPND),
+ ("mem_reg", Opnd::mem(64, CFP, 16)),
+ ("mem_stack", stack_mem(1)),
+ ("mem_stack_indirect", stack_indirect_mem(1)),
+ ("imm32", Opnd::Imm(9)),
+ ("imm64", Opnd::UImm(0x2_0000_0000)),
+ ];
+ let out_cases = [
+ ("out_reg", C_ARG_OPNDS[0]),
+ ("out_mem_stack", stack_mem(2)),
+ ];
+ let alias_out_cases = [
+ ("alias_out_cfp", CFP),
+ ("alias_out_reg", C_RET_OPND),
+ ("alias_out_mem_stack", stack_mem(1)),
+ ];
+ let alias_mem_base_cases = [
+ (
+ "out_reused_as_left_mem_base",
+ Opnd::mem(64, CFP, 8),
+ C_RET_OPND,
+ CFP,
+ ),
+ (
+ "out_reused_as_right_mem_base",
+ C_RET_OPND,
+ Opnd::mem(64, CFP, 16),
+ CFP,
+ ),
+ (
+ "out_reused_as_both_mem_bases",
+ Opnd::mem(64, CFP, 8),
+ Opnd::mem(64, CFP, 16),
+ CFP,
+ ),
+ ];
+
+ for kind in [BinOpKind::Add, BinOpKind::Sub, BinOpKind::And, BinOpKind::Or, BinOpKind::Xor] {
+ for (left_name, left) in left_cases {
+ for (right_name, right) in right_cases {
+ for (out_name, out) in out_cases {
+ let case = format!("{left_name}/{right_name}/{out_name}");
+ assert_split_binop_case(kind, left, right, out, &case);
+ }
+ }
+ }
+
+ for (left_name, left) in left_cases {
+ for (alias_name, out) in alias_out_cases {
+ let case = format!("{left_name}/right_eq_out/{alias_name}");
+ assert_split_binop_case(kind, left, out, out, &case);
+ }
+ }
+
+ for (case, left, right, out) in alias_mem_base_cases {
+ assert_split_binop_case(kind, left, right, out, case);
+ }
+ }
+ }
}
diff --git a/zjit/src/codegen.rs b/zjit/src/codegen.rs
index e51ddafe33798e..a5ca214de2c5c4 100644
--- a/zjit/src/codegen.rs
+++ b/zjit/src/codegen.rs
@@ -630,7 +630,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
Insn::CCallVariadic { cfunc, recv, name, args, cme, state, blockiseq, return_type: _, elidable: _ } => {
gen_ccall_variadic(jit, asm, *cfunc, *name, opnd!(recv), opnds!(args), *cme, *blockiseq, &function.frame_state(*state))
}
- Insn::GetIvar { self_val, id, ic, state } => gen_getivar(jit, asm, opnd!(self_val), *id, *ic, &function.frame_state(*state)),
+ Insn::GetIvar { self_val, id, ic, state: _ } => gen_getivar(jit, asm, opnd!(self_val), *id, *ic),
Insn::SetGlobal { id, val, state } => no_output!(gen_setglobal(jit, asm, *id, opnd!(val), &function.frame_state(*state))),
Insn::GetGlobal { id, state } => gen_getglobal(jit, asm, *id, &function.frame_state(*state)),
&Insn::IsBlockParamModified { ep } => gen_is_block_param_modified(asm, opnd!(ep)),
@@ -675,9 +675,8 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
&Insn::DupArrayInclude { ary, target, state } => gen_dup_array_include(jit, asm, ary, opnd!(target), &function.frame_state(state)),
Insn::ArrayHash { elements, state } => gen_opt_newarray_hash(jit, asm, opnds!(elements), &function.frame_state(*state)),
&Insn::IsA { val, class } => gen_is_a(jit, asm, opnd!(val), opnd!(class)),
- &Insn::ArrayMax { state, .. }
- | &Insn::Throw { state, .. }
- => return Err(state),
+ &Insn::ArrayMax { ref elements, state } => gen_array_max(jit, asm, opnds!(elements), &function.frame_state(state)),
+ &Insn::Throw { state, .. } => return Err(state),
&Insn::IfFalse { .. } | Insn::IfTrue { .. }
| &Insn::Jump { .. } | Insn::Entries { .. } => unreachable!(),
};
@@ -1107,9 +1106,7 @@ fn gen_ccall_variadic(
}
/// Emit an uncached instance variable lookup
-fn gen_getivar(jit: &mut JITState, asm: &mut Assembler, recv: Opnd, id: ID, ic: *const iseq_inline_iv_cache_entry, state: &FrameState) -> Opnd {
- // rb_ivar_get can raise Ractor::IsolationError for class/module ivars from non-main Ractors
- gen_prepare_non_leaf_call(jit, asm, state);
+fn gen_getivar(jit: &mut JITState, asm: &mut Assembler, recv: Opnd, id: ID, ic: *const iseq_inline_iv_cache_entry) -> Opnd {
if ic.is_null() {
asm_ccall!(asm, rb_ivar_get, recv, id.0.into())
} else {
@@ -1826,6 +1823,32 @@ fn gen_opt_newarray_hash(
)
}
+/// Compile ArrayMax - find the maximum element among array elements
+fn gen_array_max(
+ jit: &JITState,
+ asm: &mut Assembler,
+ elements: Vec,
+ state: &FrameState,
+) -> lir::Opnd {
+ gen_prepare_non_leaf_call(jit, asm, state);
+
+ let array_len: u32 = elements.len().try_into().expect("Unable to fit length of elements into u32");
+
+ // After gen_prepare_non_leaf_call, the elements are spilled to the Ruby stack.
+ // Get a pointer to the first element on the Ruby stack.
+ let stack_bottom = state.stack().len() - elements.len();
+ let elements_ptr = asm.lea(Opnd::mem(VALUE_BITS, SP, stack_bottom as i32 * SIZEOF_VALUE_I32));
+
+ unsafe extern "C" {
+ fn rb_vm_opt_newarray_max(ec: EcPtr, num: u32, elts: *const VALUE) -> VALUE;
+ }
+
+ asm.ccall(
+ rb_vm_opt_newarray_max as *const u8,
+ vec![EC, array_len.into(), elements_ptr],
+ )
+}
+
fn gen_array_include(
jit: &JITState,
asm: &mut Assembler,
diff --git a/zjit/src/distribution.rs b/zjit/src/distribution.rs
index 9b3920396a13b9..aa4667b9399c09 100644
--- a/zjit/src/distribution.rs
+++ b/zjit/src/distribution.rs
@@ -1,5 +1,7 @@
//! Type frequency distribution tracker.
+use crate::options::NumProfiles;
+
/// This implementation was inspired by the type feedback module from Google's S6, which was
/// written in C++ for use with Python. This is a new implementation in Rust created for use with
/// Ruby instead of Python.
@@ -8,9 +10,9 @@ pub struct Distribution {
/// buckets and counts have the same length
/// `buckets[0]` is always the most common item
buckets: [T; N],
- counts: [usize; N],
+ counts: [NumProfiles; N],
/// if there is no more room, increment the fallback
- other: usize,
+ other: NumProfiles,
// TODO(max): Add count disparity, which can help determine when to reset the distribution
}
@@ -23,13 +25,13 @@ impl Distribution {
for (bucket, count) in self.buckets.iter_mut().zip(self.counts.iter_mut()) {
if *bucket == item || *count == 0 {
*bucket = item;
- *count += 1;
+ *count = count.saturating_add(1);
// Keep the most frequent item at the front
self.bubble_up();
return;
}
}
- self.other += 1;
+ self.other = self.other.saturating_add(1);
}
/// Keep the highest counted bucket at index 0
@@ -87,7 +89,7 @@ impl Distributi
assert!(first_count >= count, "First count should be the largest");
}
}
- let num_seen = dist.counts.iter().sum::() + dist.other;
+ let num_seen = dist.counts.iter().map(|&c| usize::from(c)).sum::() + usize::from(dist.other);
let kind = if dist.other == 0 {
// Seen <= N types total
if dist.counts[0] == 0 {
diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs
index 4471827986ce65..ebdf044a920daf 100644
--- a/zjit/src/hir.rs
+++ b/zjit/src/hir.rs
@@ -4214,6 +4214,93 @@ impl Function {
})
}
+ fn load_ivar_c_call(&mut self, block: BlockId, recv: InsnId, ivar_index: u16) -> InsnId {
+ // NOTE: it's fine to use rb_ivar_get_at_no_ractor_check because
+ // getinstancevariable does assume_single_ractor_mode()
+ let ivar_index_insn = self.push_insn(block, Insn::Const { val: Const::CUInt16(ivar_index) });
+ self.push_insn(block, Insn::CCall {
+ cfunc: rb_ivar_get_at_no_ractor_check as *const u8,
+ recv,
+ args: vec![ivar_index_insn],
+ name: ID!(rb_ivar_get_at_no_ractor_check),
+ return_type: types::BasicObject,
+ elidable: true })
+ }
+
+ fn load_ivar_heap(&mut self, block: BlockId, recv: InsnId, id: ID, ivar_index: u16) -> InsnId {
+ // See ROBJECT_FIELDS() from include/ruby/internal/core/robject.h
+ let ptr = self.push_insn(block, Insn::LoadField {
+ recv, id: ID!(_as_heap),
+ offset: ROBJECT_OFFSET_AS_HEAP_FIELDS as i32,
+ return_type: types::CPtr,
+ });
+ let offset = SIZEOF_VALUE_I32 * ivar_index as i32;
+ self.push_insn(block, Insn::LoadField {
+ recv: ptr, id, offset,
+ return_type: types::BasicObject,
+ })
+ }
+
+ fn load_ivar_embedded(&mut self, block: BlockId, recv: InsnId, id: ID, ivar_index: u16) -> InsnId {
+ // See ROBJECT_FIELDS() from include/ruby/internal/core/robject.h
+ let offset = ROBJECT_OFFSET_AS_ARY as i32
+ + (SIZEOF_VALUE * ivar_index.to_usize()) as i32;
+ self.push_insn(block, Insn::LoadField {
+ recv, id, offset,
+ return_type: types::BasicObject,
+ })
+ }
+
+ fn load_ivar_from_fields(&mut self, block: BlockId, recv: InsnId, is_embedded: bool, id: ID, ivar_index: u16) -> InsnId {
+ if is_embedded {
+ return self.load_ivar_embedded(block, recv, id, ivar_index);
+ } else {
+ return self.load_ivar_heap(block, recv, id, ivar_index);
+ }
+ }
+
+ fn load_ivar(&mut self, block: BlockId, self_val: InsnId, recv_type: ProfiledType, id: ID, state: InsnId) -> InsnId {
+ let mut ivar_index: u16 = 0;
+ if ! unsafe { rb_shape_get_iv_index(recv_type.shape().0, id, &mut ivar_index) } {
+ // If there is no IVAR index, then the ivar was undefined when we
+ // entered the compiler. That means we can just return nil for this
+ // shape + iv name
+ return self.push_insn(block, Insn::Const { val: Const::Value(Qnil) });
+ }
+ if recv_type.flags().is_t_class_or_module() {
+ // Class/module ivar: load from prime classext's fields_obj
+ if !self.assume_root_box(block, state) {
+ // Non-root box active: fall back to C call
+ // NOTE: it's fine to use rb_ivar_get_at_no_ractor_check because
+ // getinstancevariable does assume_single_ractor_mode()
+ return self.load_ivar_c_call(block, self_val, ivar_index);
+ }
+ // Root box only: load directly from prime classext
+ let fields_obj = self.push_insn(block, Insn::LoadField {
+ recv: self_val, id: ID!(_fields_obj),
+ offset: RCLASS_OFFSET_PRIME_FIELDS_OBJ as i32,
+ return_type: types::RubyValue,
+ });
+ return self.load_ivar_from_fields(block, fields_obj, recv_type.flags().is_fields_embedded(), id, ivar_index);
+ }
+ if recv_type.flags().is_typed_data() {
+ // Typed T_DATA: load from fields_obj at fixed offset in RTypedData
+ let fields_obj = self.push_insn(block, Insn::LoadField {
+ recv: self_val, id: ID!(_fields_obj),
+ offset: RTYPEDDATA_OFFSET_FIELDS_OBJ as i32,
+ return_type: types::RubyValue,
+ });
+ return self.load_ivar_from_fields(block, fields_obj, recv_type.flags().is_fields_embedded(), id, ivar_index);
+ }
+ if recv_type.flags().is_t_object() {
+ return self.load_ivar_from_fields(block, self_val, recv_type.flags().is_embedded(), id, ivar_index);
+ }
+ // Non-T_OBJECT, non-class/module, non-typed-data: fall back to C call
+ // NOTE: it's fine to use rb_ivar_get_at_no_ractor_check because
+ // getinstancevariable does assume_single_ractor_mode()
+ return self.load_ivar_c_call(block, self_val, ivar_index);
+ }
+
fn optimize_getivar(&mut self) {
for block in self.rpo() {
let old_insns = std::mem::take(&mut self.blocks[block.0].insns);
@@ -4241,101 +4328,7 @@ impl Function {
let self_val = self.push_insn(block, Insn::GuardType { val: self_val, guard_type: types::HeapBasicObject, state });
let shape = self.load_shape(block, self_val);
self.guard_shape(block, shape, recv_type.shape(), state);
- let mut ivar_index: u16 = 0;
- let replacement = if ! unsafe { rb_shape_get_iv_index(recv_type.shape().0, id, &mut ivar_index) } {
- // If there is no IVAR index, then the ivar was undefined when we
- // entered the compiler. That means we can just return nil for this
- // shape + iv name
- self.push_insn(block, Insn::Const { val: Const::Value(Qnil) })
- } else if recv_type.flags().is_t_class_or_module() {
- // Class/module ivar: load from prime classext's fields_obj
- if self.assume_root_box(block, state) {
- // Root box only: load directly from prime classext
- let fields_obj = self.push_insn(block, Insn::LoadField {
- recv: self_val, id: ID!(_fields_obj),
- offset: RCLASS_OFFSET_PRIME_FIELDS_OBJ as i32,
- return_type: types::RubyValue,
- });
- if recv_type.flags().is_fields_embedded() {
- let offset = ROBJECT_OFFSET_AS_ARY as i32
- + (SIZEOF_VALUE * ivar_index.to_usize()) as i32;
- self.push_insn(block, Insn::LoadField {
- recv: fields_obj, id, offset,
- return_type: types::BasicObject,
- })
- } else {
- let ptr = self.push_insn(block, Insn::LoadField {
- recv: fields_obj, id: ID!(_as_heap),
- offset: ROBJECT_OFFSET_AS_HEAP_FIELDS as i32,
- return_type: types::CPtr,
- });
- let offset = SIZEOF_VALUE_I32 * ivar_index as i32;
- self.push_insn(block, Insn::LoadField {
- recv: ptr, id, offset,
- return_type: types::BasicObject,
- })
- }
- } else {
- // Non-root box active: fall back to C call
- // NOTE: it's fine to use rb_ivar_get_at_no_ractor_check because
- // getinstancevariable does assume_single_ractor_mode()
- let ivar_index_insn = self.push_insn(block, Insn::Const { val: Const::CUInt16(ivar_index as u16) });
- self.push_insn(block, Insn::CCall {
- cfunc: rb_ivar_get_at_no_ractor_check as *const u8,
- recv: self_val,
- args: vec![ivar_index_insn],
- name: ID!(rb_ivar_get_at_no_ractor_check),
- return_type: types::BasicObject,
- elidable: true })
- }
- } else if recv_type.flags().is_typed_data() {
- // Typed T_DATA: load from fields_obj at fixed offset in RTypedData
- let fields_obj = self.push_insn(block, Insn::LoadField {
- recv: self_val, id: ID!(_fields_obj),
- offset: RTYPEDDATA_OFFSET_FIELDS_OBJ as i32,
- return_type: types::RubyValue,
- });
- if recv_type.flags().is_fields_embedded() {
- let offset = ROBJECT_OFFSET_AS_ARY as i32
- + (SIZEOF_VALUE * ivar_index.to_usize()) as i32;
- self.push_insn(block, Insn::LoadField {
- recv: fields_obj, id, offset,
- return_type: types::BasicObject,
- })
- } else {
- let ptr = self.push_insn(block, Insn::LoadField {
- recv: fields_obj, id: ID!(_as_heap),
- offset: ROBJECT_OFFSET_AS_HEAP_FIELDS as i32,
- return_type: types::CPtr,
- });
- let offset = SIZEOF_VALUE_I32 * ivar_index as i32;
- self.push_insn(block, Insn::LoadField {
- recv: ptr, id, offset,
- return_type: types::BasicObject,
- })
- }
- } else if !recv_type.flags().is_t_object() {
- // Non-T_OBJECT, non-class/module, non-typed-data: fall back to C call
- // NOTE: it's fine to use rb_ivar_get_at_no_ractor_check because
- // getinstancevariable does assume_single_ractor_mode()
- let ivar_index_insn = self.push_insn(block, Insn::Const { val: Const::CUInt16(ivar_index as u16) });
- self.push_insn(block, Insn::CCall {
- cfunc: rb_ivar_get_at_no_ractor_check as *const u8,
- recv: self_val,
- args: vec![ivar_index_insn],
- name: ID!(rb_ivar_get_at_no_ractor_check),
- return_type: types::BasicObject,
- elidable: true })
- } else if recv_type.flags().is_embedded() {
- // See ROBJECT_FIELDS() from include/ruby/internal/core/robject.h
- let offset = ROBJECT_OFFSET_AS_ARY as i32 + (SIZEOF_VALUE * ivar_index.to_usize()) as i32;
- self.push_insn(block, Insn::LoadField { recv: self_val, id, offset, return_type: types::BasicObject })
- } else {
- let as_heap = self.push_insn(block, Insn::LoadField { recv: self_val, id: ID!(_as_heap), offset: ROBJECT_OFFSET_AS_HEAP_FIELDS as i32, return_type: types::CPtr });
-
- let offset = SIZEOF_VALUE_I32 * ivar_index as i32;
- self.push_insn(block, Insn::LoadField { recv: as_heap, id, offset, return_type: types::BasicObject })
- };
+ let replacement = self.load_ivar(block, self_val, recv_type, id, state);
self.make_equal_to(insn_id, replacement);
}
Insn::DefinedIvar { self_val, id, pushval, state } => {
@@ -5071,6 +5064,13 @@ impl Function {
_ => insn_id,
}
}
+ Insn::UnboxFixnum { val } => {
+ let recv_type = self.type_of(val);
+ match recv_type.fixnum_value() {
+ Some(val) => self.new_insn(Insn::Const { val: Const::CInt64(val) }),
+ _ => insn_id,
+ }
+ },
Insn::GuardBitEquals { val, expected, .. } => {
let recv_type = self.type_of(val);
if recv_type.has_value(expected) {
diff --git a/zjit/src/hir/opt_tests.rs b/zjit/src/hir/opt_tests.rs
index aa706f7ddaeadd..bc3f92b83ab923 100644
--- a/zjit/src/hir/opt_tests.rs
+++ b/zjit/src/hir/opt_tests.rs
@@ -990,6 +990,41 @@ mod hir_opt_tests {
");
}
+ #[test]
+ fn test_fold_unbox_fixnum() {
+ eval("
+ def test(arr) = arr[0]
+ test([1,2,3])
+ ");
+ assert_snapshot!(hir_string("test"), @"
+ fn test@:2:
+ bb1():
+ EntryPoint interpreter
+ v1:BasicObject = LoadSelf
+ v2:CPtr = LoadSP
+ v3:BasicObject = LoadField v2, :arr@0x1000
+ Jump bb3(v1, v3)
+ bb2():
+ EntryPoint JIT(0)
+ v6:BasicObject = LoadArg :self@0
+ v7:BasicObject = LoadArg :arr@1
+ Jump bb3(v6, v7)
+ bb3(v9:BasicObject, v10:BasicObject):
+ v15:Fixnum[0] = Const Value(0)
+ PatchPoint NoSingletonClass(Array@0x1008)
+ PatchPoint MethodRedefined(Array@0x1008, []@0x1010, cme:0x1018)
+ v27:ArrayExact = GuardType v10, ArrayExact
+ v34:CInt64[0] = Const CInt64(0)
+ v29:CInt64 = ArrayLength v27
+ v30:CInt64[0] = GuardLess v34, v29
+ v31:CInt64[0] = Const CInt64(0)
+ v32:CInt64[0] = GuardGreaterEq v30, v31
+ v33:BasicObject = ArrayAref v27, v32
+ CheckInterrupts
+ Return v33
+ ");
+ }
+
#[test]
fn neq_with_side_effect_not_elided () {
let result = eval("
@@ -2249,9 +2284,9 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(Array@0x1008)
PatchPoint MethodRedefined(Array@0x1008, []@0x1010, cme:0x1018)
v27:ArrayExact = GuardType v10, ArrayExact
- v28:CInt64[0] = UnboxFixnum v15
+ v34:CInt64[0] = Const CInt64(0)
v29:CInt64 = ArrayLength v27
- v30:CInt64[0] = GuardLess v28, v29
+ v30:CInt64[0] = GuardLess v34, v29
v31:CInt64[0] = Const CInt64(0)
v32:CInt64[0] = GuardGreaterEq v30, v31
v33:BasicObject = ArrayAref v27, v32
@@ -5960,9 +5995,9 @@ mod hir_opt_tests {
v12:Fixnum[0] = Const Value(0)
PatchPoint NoSingletonClass(Array@0x1010)
PatchPoint MethodRedefined(Array@0x1010, []@0x1018, cme:0x1020)
- v27:CInt64[0] = UnboxFixnum v12
+ v33:CInt64[0] = Const CInt64(0)
v28:CInt64 = ArrayLength v23
- v29:CInt64[0] = GuardLess v27, v28
+ v29:CInt64[0] = GuardLess v33, v28
v30:CInt64[0] = Const CInt64(0)
v31:CInt64[0] = GuardGreaterEq v29, v30
v32:BasicObject = ArrayAref v23, v31
@@ -5994,14 +6029,14 @@ mod hir_opt_tests {
v13:Fixnum[1] = Const Value(1)
PatchPoint NoSingletonClass(Array@0x1008)
PatchPoint MethodRedefined(Array@0x1008, []@0x1010, cme:0x1018)
- v25:CInt64[1] = UnboxFixnum v13
+ v31:CInt64[1] = Const CInt64(1)
v26:CInt64 = ArrayLength v11
- v27:CInt64[1] = GuardLess v25, v26
+ v27:CInt64[1] = GuardLess v31, v26
v28:CInt64[0] = Const CInt64(0)
v29:CInt64[1] = GuardGreaterEq v27, v28
- v31:Fixnum[5] = Const Value(5)
+ v32:Fixnum[5] = Const Value(5)
CheckInterrupts
- Return v31
+ Return v32
");
}
@@ -6026,14 +6061,14 @@ mod hir_opt_tests {
v13:Fixnum[-3] = Const Value(-3)
PatchPoint NoSingletonClass(Array@0x1008)
PatchPoint MethodRedefined(Array@0x1008, []@0x1010, cme:0x1018)
- v25:CInt64[-3] = UnboxFixnum v13
+ v31:CInt64[-3] = Const CInt64(-3)
v26:CInt64 = ArrayLength v11
- v27:CInt64[-3] = GuardLess v25, v26
+ v27:CInt64[-3] = GuardLess v31, v26
v28:CInt64[0] = Const CInt64(0)
v29:CInt64[-3] = GuardGreaterEq v27, v28
- v31:Fixnum[4] = Const Value(4)
+ v32:Fixnum[4] = Const Value(4)
CheckInterrupts
- Return v31
+ Return v32
");
}
@@ -6058,14 +6093,14 @@ mod hir_opt_tests {
v13:Fixnum[-10] = Const Value(-10)
PatchPoint NoSingletonClass(Array@0x1008)
PatchPoint MethodRedefined(Array@0x1008, []@0x1010, cme:0x1018)
- v25:CInt64[-10] = UnboxFixnum v13
+ v31:CInt64[-10] = Const CInt64(-10)
v26:CInt64 = ArrayLength v11
- v27:CInt64[-10] = GuardLess v25, v26
+ v27:CInt64[-10] = GuardLess v31, v26
v28:CInt64[0] = Const CInt64(0)
v29:CInt64[-10] = GuardGreaterEq v27, v28
- v31:NilClass = Const Value(nil)
+ v32:NilClass = Const Value(nil)
CheckInterrupts
- Return v31
+ Return v32
");
}
@@ -6090,14 +6125,14 @@ mod hir_opt_tests {
v13:Fixnum[10] = Const Value(10)
PatchPoint NoSingletonClass(Array@0x1008)
PatchPoint MethodRedefined(Array@0x1008, []@0x1010, cme:0x1018)
- v25:CInt64[10] = UnboxFixnum v13
+ v31:CInt64[10] = Const CInt64(10)
v26:CInt64 = ArrayLength v11
- v27:CInt64[10] = GuardLess v25, v26
+ v27:CInt64[10] = GuardLess v31, v26
v28:CInt64[0] = Const CInt64(0)
v29:CInt64[10] = GuardGreaterEq v27, v28
- v31:NilClass = Const Value(nil)
+ v32:NilClass = Const Value(nil)
CheckInterrupts
- Return v31
+ Return v32
");
}
@@ -8324,9 +8359,9 @@ mod hir_opt_tests {
v19:Fixnum[0] = Const Value(0)
PatchPoint NoSingletonClass(Array@0x1008)
PatchPoint MethodRedefined(Array@0x1008, []@0x1010, cme:0x1018)
- v31:CInt64[0] = UnboxFixnum v19
+ v37:CInt64[0] = Const CInt64(0)
v32:CInt64 = ArrayLength v14
- v33:CInt64[0] = GuardLess v31, v32
+ v33:CInt64[0] = GuardLess v37, v32
v34:CInt64[0] = Const CInt64(0)
v35:CInt64[0] = GuardGreaterEq v33, v34
v36:BasicObject = ArrayAref v14, v35
@@ -8706,9 +8741,9 @@ mod hir_opt_tests {
v34:CUInt64 = LoadField v33, :_rbasic_flags@0x1040
v35:CUInt64 = GuardNoBitsSet v34, RUBY_FL_FREEZE=CUInt64(2048)
v37:CUInt64 = GuardNoBitsSet v34, RUBY_ELTS_SHARED=CUInt64(4096)
- v38:CInt64[1] = UnboxFixnum v17
+ v45:CInt64[1] = Const CInt64(1)
v39:CInt64 = ArrayLength v33
- v40:CInt64[1] = GuardLess v38, v39
+ v40:CInt64[1] = GuardLess v45, v39
v41:CInt64[0] = Const CInt64(0)
v42:CInt64[1] = GuardGreaterEq v40, v41
ArrayAset v33, v42, v19
diff --git a/zjit/src/options.rs b/zjit/src/options.rs
index acc965854b9b23..5da5fd2d706a5d 100644
--- a/zjit/src/options.rs
+++ b/zjit/src/options.rs
@@ -8,7 +8,7 @@ use std::collections::HashSet;
/// Default --zjit-num-profiles
const DEFAULT_NUM_PROFILES: NumProfiles = 5;
-pub type NumProfiles = u32;
+pub type NumProfiles = u16;
/// Default --zjit-call-threshold. This should be large enough to avoid compiling
/// warmup code, but small enough to perform well on micro-benchmarks.
diff --git a/zjit/src/payload.rs b/zjit/src/payload.rs
index 8540d5e35c498e..cb486975bd5d0b 100644
--- a/zjit/src/payload.rs
+++ b/zjit/src/payload.rs
@@ -14,9 +14,9 @@ pub struct IseqPayload {
}
impl IseqPayload {
- fn new(iseq_size: u32) -> Self {
+ fn new() -> Self {
Self {
- profile: IseqProfile::new(iseq_size),
+ profile: IseqProfile::new(),
versions: vec![],
}
}
@@ -87,8 +87,7 @@ pub fn get_or_create_iseq_payload_ptr(iseq: IseqPtr) -> *mut IseqPayload {
// We drop the payload with Box::from_raw when the GC frees the ISEQ and calls us.
// NOTE(alan): Sometimes we read from an ISEQ without ever writing to it.
// We allocate in those cases anyways.
- let iseq_size = get_iseq_encoded_size(iseq);
- let new_payload = IseqPayload::new(iseq_size);
+ let new_payload = IseqPayload::new();
let new_payload = Box::into_raw(Box::new(new_payload));
rb_iseq_set_zjit_payload(iseq, new_payload as VoidPtr);
diff --git a/zjit/src/profile.rs b/zjit/src/profile.rs
index 795aa6d60649e3..a4981156a6c756 100644
--- a/zjit/src/profile.rs
+++ b/zjit/src/profile.rs
@@ -104,8 +104,9 @@ fn profile_insn(bare_opcode: ruby_vminsn_type, ec: EcPtr) {
}
// Once we profile the instruction num_profiles times, we stop profiling it.
- profile.num_profiles[profiler.insn_idx] = profile.num_profiles[profiler.insn_idx].saturating_add(1);
- if profile.num_profiles[profiler.insn_idx] == get_option!(num_profiles) {
+ let entry = profile.entry_mut(profiler.insn_idx);
+ entry.num_profiles = entry.num_profiles.saturating_add(1);
+ if entry.num_profiles == get_option!(num_profiles) {
unsafe { rb_zjit_iseq_insn_set(profiler.iseq, profiler.insn_idx as u32, bare_opcode); }
}
}
@@ -118,12 +119,12 @@ pub type TypeDistributionSummary = DistributionSummary>,
+struct ProfileEntry {
+ /// YARV instruction index
+ insn_idx: u32,
+ /// Type information of YARV instruction operands
+ opnd_types: Vec,
+ /// Number of profiled executions for this YARV instruction
+ num_profiles: NumProfiles,
+}
- /// Number of profiled executions for each YARV instruction, indexed by the instruction index
- num_profiles: Vec,
+#[derive(Debug)]
+pub struct IseqProfile {
+ /// Sparse storage of per-instruction profile data, sorted by instruction index.
+ /// Only instructions that have actually been profiled have entries here.
+ entries: Vec,
/// Method entries for `super` calls (stored as VALUE to be GC-safe)
super_cme: HashMap
}
impl IseqProfile {
- pub fn new(iseq_size: u32) -> Self {
+ pub fn new() -> Self {
Self {
- opnd_types: vec![vec![]; iseq_size as usize],
- num_profiles: vec![0; iseq_size as usize],
+ entries: Vec::new(),
super_cme: HashMap::new(),
}
}
+ /// Get or create a mutable profile entry for the given instruction index.
+ fn entry_mut(&mut self, insn_idx: usize) -> &mut ProfileEntry {
+ let idx = insn_idx as u32;
+ match self.entries.binary_search_by_key(&idx, |e| e.insn_idx) {
+ Ok(i) => &mut self.entries[i],
+ Err(i) => {
+ self.entries.insert(i, ProfileEntry {
+ insn_idx: idx,
+ opnd_types: Vec::new(),
+ num_profiles: 0,
+ });
+ &mut self.entries[i]
+ }
+ }
+ }
+
+ /// Get a profile entry for the given instruction index (read-only).
+ fn entry(&self, insn_idx: usize) -> Option<&ProfileEntry> {
+ let idx = insn_idx as u32;
+ self.entries.binary_search_by_key(&idx, |e| e.insn_idx)
+ .ok().map(|i| &self.entries[i])
+ }
+
/// Get profiled operand types for a given instruction index
pub fn get_operand_types(&self, insn_idx: usize) -> Option<&[TypeDistribution]> {
- self.opnd_types.get(insn_idx).map(|v| &**v)
+ self.entry(insn_idx).map(|e| e.opnd_types.as_slice()).filter(|s| !s.is_empty())
}
pub fn get_super_method_entry(&self, insn_idx: usize) -> Option<*const rb_callable_method_entry_t> {
@@ -413,8 +445,8 @@ impl IseqProfile {
/// Run a given callback with every object in IseqProfile
pub fn each_object(&self, callback: impl Fn(VALUE)) {
- for operands in &self.opnd_types {
- for distribution in operands {
+ for entry in &self.entries {
+ for distribution in &entry.opnd_types {
for profiled_type in distribution.each_item() {
// If the type is a GC object, call the callback
callback(profiled_type.class);
@@ -431,8 +463,8 @@ impl IseqProfile {
/// Run a given callback with a mutable reference to every object in IseqProfile.
pub fn each_object_mut(&mut self, callback: impl Fn(&mut VALUE)) {
- for operands in &mut self.opnd_types {
- for distribution in operands {
+ for entry in &mut self.entries {
+ for distribution in &mut entry.opnd_types {
for ref mut profiled_type in distribution.each_item_mut() {
// If the type is a GC object, call the callback
callback(&mut profiled_type.class);