prism 1.1.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +39 -1
- data/Makefile +1 -1
- data/config.yml +422 -3
- data/docs/build_system.md +8 -11
- data/docs/relocation.md +34 -0
- data/ext/prism/api_node.c +18 -10
- data/ext/prism/extconf.rb +13 -36
- data/ext/prism/extension.c +68 -0
- data/ext/prism/extension.h +1 -1
- data/include/prism/ast.h +427 -3
- data/include/prism/defines.h +22 -7
- data/include/prism/diagnostic.h +1 -0
- data/include/prism/parser.h +25 -12
- data/include/prism/version.h +2 -2
- data/include/prism.h +47 -0
- data/lib/prism/dot_visitor.rb +10 -0
- data/lib/prism/dsl.rb +4 -4
- data/lib/prism/ffi.rb +49 -2
- data/lib/prism/inspect_visitor.rb +2 -0
- data/lib/prism/node.rb +1839 -96
- data/lib/prism/parse_result/errors.rb +1 -1
- data/lib/prism/parse_result.rb +140 -3
- data/lib/prism/reflection.rb +2 -2
- data/lib/prism/relocation.rb +504 -0
- data/lib/prism/serialize.rb +17 -5
- data/lib/prism/string_query.rb +30 -0
- data/lib/prism/translation/parser/compiler.rb +36 -26
- data/lib/prism/translation/parser.rb +3 -3
- data/lib/prism/translation/ripper.rb +1 -5
- data/lib/prism/translation/ruby_parser.rb +14 -5
- data/lib/prism.rb +6 -4
- data/prism.gemspec +7 -1
- data/rbi/prism/dsl.rbi +4 -4
- data/rbi/prism/node.rbi +5118 -1030
- data/rbi/prism/parse_result.rbi +29 -0
- data/rbi/prism/string_query.rbi +12 -0
- data/rbi/prism.rbi +34 -34
- data/sig/prism/dsl.rbs +2 -2
- data/sig/prism/node.rbs +13 -98
- data/sig/prism/parse_result.rbs +20 -0
- data/sig/prism/relocation.rbs +185 -0
- data/sig/prism/string_query.rbs +11 -0
- data/src/diagnostic.c +3 -1
- data/src/node.c +18 -0
- data/src/prettyprint.c +32 -0
- data/src/prism.c +586 -195
- data/src/regexp.c +7 -3
- data/src/serialize.c +12 -0
- data/src/static_literals.c +1 -1
- data/src/util/pm_char.c +1 -1
- data/src/util/pm_string.c +1 -0
- metadata +9 -3
    
        data/include/prism/defines.h
    CHANGED
    
    | @@ -137,14 +137,15 @@ | |
| 137 137 | 
             
            #endif
         | 
| 138 138 |  | 
| 139 139 | 
             
            /**
         | 
| 140 | 
            -
             * isinf on  | 
| 141 | 
            -
             *  | 
| 142 | 
            -
             *  | 
| 140 | 
            +
             * isinf on POSIX systems it accepts a float, a double, or a long double.
         | 
| 141 | 
            +
             * But mingw didn't provide an isinf macro, only an isinf function that only
         | 
| 142 | 
            +
             * accepts floats, so we need to use _finite instead.
         | 
| 143 143 | 
             
             */
         | 
| 144 | 
            -
            #ifdef  | 
| 145 | 
            -
            # | 
| 146 | 
            -
            # | 
| 147 | 
            -
            # | 
| 144 | 
            +
            #ifdef __MINGW64__
         | 
| 145 | 
            +
                #include <float.h>
         | 
| 146 | 
            +
                #define PRISM_ISINF(x) (!_finite(x))
         | 
| 147 | 
            +
            #else
         | 
| 148 | 
            +
                #define PRISM_ISINF(x) isinf(x)
         | 
| 148 149 | 
             
            #endif
         | 
| 149 150 |  | 
| 150 151 | 
             
            /**
         | 
| @@ -239,4 +240,18 @@ | |
| 239 240 | 
             
                #define PRISM_UNLIKELY(x) (x)
         | 
| 240 241 | 
             
            #endif
         | 
| 241 242 |  | 
| 243 | 
            +
            /**
         | 
| 244 | 
            +
             * We use -Wimplicit-fallthrough to guard potentially unintended fall-through between cases of a switch.
         | 
| 245 | 
            +
             * Use PRISM_FALLTHROUGH to explicitly annotate cases where the fallthrough is intentional.
         | 
| 246 | 
            +
             */
         | 
| 247 | 
            +
            #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L // C23 or later
         | 
| 248 | 
            +
                #define PRISM_FALLTHROUGH [[fallthrough]];
         | 
| 249 | 
            +
            #elif defined(__GNUC__) || defined(__clang__)
         | 
| 250 | 
            +
                #define PRISM_FALLTHROUGH __attribute__((fallthrough));
         | 
| 251 | 
            +
            #elif defined(_MSC_VER)
         | 
| 252 | 
            +
                #define PRISM_FALLTHROUGH __fallthrough;
         | 
| 253 | 
            +
            #else
         | 
| 254 | 
            +
                #define PRISM_FALLTHROUGH
         | 
| 255 | 
            +
            #endif
         | 
| 256 | 
            +
             | 
| 242 257 | 
             
            #endif
         | 
    
        data/include/prism/diagnostic.h
    CHANGED
    
    
    
        data/include/prism/parser.h
    CHANGED
    
    | @@ -82,6 +82,23 @@ typedef enum { | |
| 82 82 | 
             
                PM_HEREDOC_INDENT_TILDE,
         | 
| 83 83 | 
             
            } pm_heredoc_indent_t;
         | 
| 84 84 |  | 
| 85 | 
            +
            /**
         | 
| 86 | 
            +
             * All of the information necessary to store to lexing a heredoc.
         | 
| 87 | 
            +
             */
         | 
| 88 | 
            +
            typedef struct {
         | 
| 89 | 
            +
                /** A pointer to the start of the heredoc identifier. */
         | 
| 90 | 
            +
                const uint8_t *ident_start;
         | 
| 91 | 
            +
             | 
| 92 | 
            +
                /** The length of the heredoc identifier. */
         | 
| 93 | 
            +
                size_t ident_length;
         | 
| 94 | 
            +
             | 
| 95 | 
            +
                /** The type of quote that the heredoc uses. */
         | 
| 96 | 
            +
                pm_heredoc_quote_t quote;
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                /** The type of indentation that the heredoc uses. */
         | 
| 99 | 
            +
                pm_heredoc_indent_t indent;
         | 
| 100 | 
            +
            } pm_heredoc_lex_mode_t;
         | 
| 101 | 
            +
             | 
| 85 102 | 
             
            /**
         | 
| 86 103 | 
             
             * When lexing Ruby source, the lexer has a small amount of state to tell which
         | 
| 87 104 | 
             
             * kind of token it is currently lexing. For example, when we find the start of
         | 
| @@ -210,17 +227,10 @@ typedef struct pm_lex_mode { | |
| 210 227 | 
             
                    } string;
         | 
| 211 228 |  | 
| 212 229 | 
             
                    struct {
         | 
| 213 | 
            -
                        /** | 
| 214 | 
            -
             | 
| 215 | 
            -
             | 
| 216 | 
            -
                         | 
| 217 | 
            -
                        size_t ident_length;
         | 
| 218 | 
            -
             | 
| 219 | 
            -
                        /** The type of quote that the heredoc uses. */
         | 
| 220 | 
            -
                        pm_heredoc_quote_t quote;
         | 
| 221 | 
            -
             | 
| 222 | 
            -
                        /** The type of indentation that the heredoc uses. */
         | 
| 223 | 
            -
                        pm_heredoc_indent_t indent;
         | 
| 230 | 
            +
                        /**
         | 
| 231 | 
            +
                         * All of the data necessary to lex a heredoc.
         | 
| 232 | 
            +
                         */
         | 
| 233 | 
            +
                        pm_heredoc_lex_mode_t base;
         | 
| 224 234 |  | 
| 225 235 | 
             
                        /**
         | 
| 226 236 | 
             
                         * This is the pointer to the character where lexing should resume
         | 
| @@ -233,7 +243,7 @@ typedef struct pm_lex_mode { | |
| 233 243 | 
             
                         * line so that we know how much to dedent each line in the case of
         | 
| 234 244 | 
             
                         * a tilde heredoc.
         | 
| 235 245 | 
             
                         */
         | 
| 236 | 
            -
                        size_t common_whitespace;
         | 
| 246 | 
            +
                        size_t *common_whitespace;
         | 
| 237 247 |  | 
| 238 248 | 
             
                        /** True if the previous token ended with a line continuation. */
         | 
| 239 249 | 
             
                        bool line_continuation;
         | 
| @@ -382,6 +392,9 @@ typedef enum { | |
| 382 392 | 
             
                /** a rescue statement within a module statement */
         | 
| 383 393 | 
             
                PM_CONTEXT_MODULE_RESCUE,
         | 
| 384 394 |  | 
| 395 | 
            +
                /** a multiple target expression */
         | 
| 396 | 
            +
                PM_CONTEXT_MULTI_TARGET,
         | 
| 397 | 
            +
             | 
| 385 398 | 
             
                /** a parenthesized expression */
         | 
| 386 399 | 
             
                PM_CONTEXT_PARENS,
         | 
| 387 400 |  | 
    
        data/include/prism/version.h
    CHANGED
    
    | @@ -14,7 +14,7 @@ | |
| 14 14 | 
             
            /**
         | 
| 15 15 | 
             
             * The minor version of the Prism library as an int.
         | 
| 16 16 | 
             
             */
         | 
| 17 | 
            -
            #define PRISM_VERSION_MINOR  | 
| 17 | 
            +
            #define PRISM_VERSION_MINOR 3
         | 
| 18 18 |  | 
| 19 19 | 
             
            /**
         | 
| 20 20 | 
             
             * The patch version of the Prism library as an int.
         | 
| @@ -24,6 +24,6 @@ | |
| 24 24 | 
             
            /**
         | 
| 25 25 | 
             
             * The version of the Prism library as a constant string.
         | 
| 26 26 | 
             
             */
         | 
| 27 | 
            -
            #define PRISM_VERSION "1. | 
| 27 | 
            +
            #define PRISM_VERSION "1.3.0"
         | 
| 28 28 |  | 
| 29 29 | 
             
            #endif
         | 
    
        data/include/prism.h
    CHANGED
    
    | @@ -234,6 +234,53 @@ PRISM_EXPORTED_FUNCTION void pm_dump_json(pm_buffer_t *buffer, const pm_parser_t | |
| 234 234 |  | 
| 235 235 | 
             
            #endif
         | 
| 236 236 |  | 
| 237 | 
            +
            /**
         | 
| 238 | 
            +
             * Represents the results of a slice query.
         | 
| 239 | 
            +
             */
         | 
| 240 | 
            +
            typedef enum {
         | 
| 241 | 
            +
                /** Returned if the encoding given to a slice query was invalid. */
         | 
| 242 | 
            +
                PM_STRING_QUERY_ERROR = -1,
         | 
| 243 | 
            +
             | 
| 244 | 
            +
                /** Returned if the result of the slice query is false. */
         | 
| 245 | 
            +
                PM_STRING_QUERY_FALSE,
         | 
| 246 | 
            +
             | 
| 247 | 
            +
                /** Returned if the result of the slice query is true. */
         | 
| 248 | 
            +
                PM_STRING_QUERY_TRUE
         | 
| 249 | 
            +
            } pm_string_query_t;
         | 
| 250 | 
            +
             | 
| 251 | 
            +
            /**
         | 
| 252 | 
            +
             * Check that the slice is a valid local variable name.
         | 
| 253 | 
            +
             *
         | 
| 254 | 
            +
             * @param source The source to check.
         | 
| 255 | 
            +
             * @param length The length of the source.
         | 
| 256 | 
            +
             * @param encoding_name The name of the encoding of the source.
         | 
| 257 | 
            +
             * @return PM_STRING_QUERY_TRUE if the query is true, PM_STRING_QUERY_FALSE if
         | 
| 258 | 
            +
             *   the query is false, and PM_STRING_QUERY_ERROR if the encoding was invalid.
         | 
| 259 | 
            +
             */
         | 
| 260 | 
            +
            PRISM_EXPORTED_FUNCTION pm_string_query_t pm_string_query_local(const uint8_t *source, size_t length, const char *encoding_name);
         | 
| 261 | 
            +
             | 
| 262 | 
            +
            /**
         | 
| 263 | 
            +
             * Check that the slice is a valid constant name.
         | 
| 264 | 
            +
             *
         | 
| 265 | 
            +
             * @param source The source to check.
         | 
| 266 | 
            +
             * @param length The length of the source.
         | 
| 267 | 
            +
             * @param encoding_name The name of the encoding of the source.
         | 
| 268 | 
            +
             * @return PM_STRING_QUERY_TRUE if the query is true, PM_STRING_QUERY_FALSE if
         | 
| 269 | 
            +
             *   the query is false, and PM_STRING_QUERY_ERROR if the encoding was invalid.
         | 
| 270 | 
            +
             */
         | 
| 271 | 
            +
            PRISM_EXPORTED_FUNCTION pm_string_query_t pm_string_query_constant(const uint8_t *source, size_t length, const char *encoding_name);
         | 
| 272 | 
            +
             | 
| 273 | 
            +
            /**
         | 
| 274 | 
            +
             * Check that the slice is a valid method name.
         | 
| 275 | 
            +
             *
         | 
| 276 | 
            +
             * @param source The source to check.
         | 
| 277 | 
            +
             * @param length The length of the source.
         | 
| 278 | 
            +
             * @param encoding_name The name of the encoding of the source.
         | 
| 279 | 
            +
             * @return PM_STRING_QUERY_TRUE if the query is true, PM_STRING_QUERY_FALSE if
         | 
| 280 | 
            +
             *   the query is false, and PM_STRING_QUERY_ERROR if the encoding was invalid.
         | 
| 281 | 
            +
             */
         | 
| 282 | 
            +
            PRISM_EXPORTED_FUNCTION pm_string_query_t pm_string_query_method_name(const uint8_t *source, size_t length, const char *encoding_name);
         | 
| 283 | 
            +
             | 
| 237 284 | 
             
            /**
         | 
| 238 285 | 
             
             * @mainpage
         | 
| 239 286 | 
             
             *
         | 
    
        data/lib/prism/dot_visitor.rb
    CHANGED
    
    | @@ -4414,6 +4414,11 @@ module Prism | |
| 4414 4414 | 
             
                  # keyword_loc
         | 
| 4415 4415 | 
             
                  table.field("keyword_loc", location_inspect(node.keyword_loc))
         | 
| 4416 4416 |  | 
| 4417 | 
            +
                  # do_keyword_loc
         | 
| 4418 | 
            +
                  unless (do_keyword_loc = node.do_keyword_loc).nil?
         | 
| 4419 | 
            +
                    table.field("do_keyword_loc", location_inspect(do_keyword_loc))
         | 
| 4420 | 
            +
                  end
         | 
| 4421 | 
            +
             | 
| 4417 4422 | 
             
                  # closing_loc
         | 
| 4418 4423 | 
             
                  unless (closing_loc = node.closing_loc).nil?
         | 
| 4419 4424 | 
             
                    table.field("closing_loc", location_inspect(closing_loc))
         | 
| @@ -4490,6 +4495,11 @@ module Prism | |
| 4490 4495 | 
             
                  # keyword_loc
         | 
| 4491 4496 | 
             
                  table.field("keyword_loc", location_inspect(node.keyword_loc))
         | 
| 4492 4497 |  | 
| 4498 | 
            +
                  # do_keyword_loc
         | 
| 4499 | 
            +
                  unless (do_keyword_loc = node.do_keyword_loc).nil?
         | 
| 4500 | 
            +
                    table.field("do_keyword_loc", location_inspect(do_keyword_loc))
         | 
| 4501 | 
            +
                  end
         | 
| 4502 | 
            +
             | 
| 4493 4503 | 
             
                  # closing_loc
         | 
| 4494 4504 | 
             
                  unless (closing_loc = node.closing_loc).nil?
         | 
| 4495 4505 | 
             
                    table.field("closing_loc", location_inspect(closing_loc))
         | 
    
        data/lib/prism/dsl.rb
    CHANGED
    
    | @@ -804,8 +804,8 @@ module Prism | |
| 804 804 | 
             
                end
         | 
| 805 805 |  | 
| 806 806 | 
             
                # Create a new UntilNode node.
         | 
| 807 | 
            -
                def until_node(source: default_source, node_id: 0, location: default_location, flags: 0, keyword_loc: location, closing_loc: nil, predicate: default_node(source, location), statements: nil)
         | 
| 808 | 
            -
                  UntilNode.new(source, node_id, location, flags, keyword_loc, closing_loc, predicate, statements)
         | 
| 807 | 
            +
                def until_node(source: default_source, node_id: 0, location: default_location, flags: 0, keyword_loc: location, do_keyword_loc: nil, closing_loc: nil, predicate: default_node(source, location), statements: nil)
         | 
| 808 | 
            +
                  UntilNode.new(source, node_id, location, flags, keyword_loc, do_keyword_loc, closing_loc, predicate, statements)
         | 
| 809 809 | 
             
                end
         | 
| 810 810 |  | 
| 811 811 | 
             
                # Create a new WhenNode node.
         | 
| @@ -814,8 +814,8 @@ module Prism | |
| 814 814 | 
             
                end
         | 
| 815 815 |  | 
| 816 816 | 
             
                # Create a new WhileNode node.
         | 
| 817 | 
            -
                def while_node(source: default_source, node_id: 0, location: default_location, flags: 0, keyword_loc: location, closing_loc: nil, predicate: default_node(source, location), statements: nil)
         | 
| 818 | 
            -
                  WhileNode.new(source, node_id, location, flags, keyword_loc, closing_loc, predicate, statements)
         | 
| 817 | 
            +
                def while_node(source: default_source, node_id: 0, location: default_location, flags: 0, keyword_loc: location, do_keyword_loc: nil, closing_loc: nil, predicate: default_node(source, location), statements: nil)
         | 
| 818 | 
            +
                  WhileNode.new(source, node_id, location, flags, keyword_loc, do_keyword_loc, closing_loc, predicate, statements)
         | 
| 819 819 | 
             
                end
         | 
| 820 820 |  | 
| 821 821 | 
             
                # Create a new XStringNode node.
         | 
    
        data/lib/prism/ffi.rb
    CHANGED
    
    | @@ -13,7 +13,15 @@ module Prism | |
| 13 13 |  | 
| 14 14 | 
             
                # Define the library that we will be pulling functions from. Note that this
         | 
| 15 15 | 
             
                # must align with the build shared library from make/rake.
         | 
| 16 | 
            -
                 | 
| 16 | 
            +
                libprism_in_build = File.expand_path("../../build/libprism.#{RbConfig::CONFIG["SOEXT"]}", __dir__)
         | 
| 17 | 
            +
                libprism_in_libdir = "#{RbConfig::CONFIG["libdir"]}/prism/libprism.#{RbConfig::CONFIG["SOEXT"]}"
         | 
| 18 | 
            +
                if File.exist? libprism_in_build
         | 
| 19 | 
            +
                  INCLUDE_DIR = File.expand_path("../../include", __dir__)
         | 
| 20 | 
            +
                  ffi_lib libprism_in_build
         | 
| 21 | 
            +
                else
         | 
| 22 | 
            +
                  INCLUDE_DIR = "#{RbConfig::CONFIG["libdir"]}/prism/include"
         | 
| 23 | 
            +
                  ffi_lib libprism_in_libdir
         | 
| 24 | 
            +
                end
         | 
| 17 25 |  | 
| 18 26 | 
             
                # Convert a native C type declaration into a symbol that FFI understands.
         | 
| 19 27 | 
             
                # For example:
         | 
| @@ -38,7 +46,7 @@ module Prism | |
| 38 46 | 
             
                # given functions. For each one, define a function with the same name and
         | 
| 39 47 | 
             
                # signature as the C function.
         | 
| 40 48 | 
             
                def self.load_exported_functions_from(header, *functions, callbacks)
         | 
| 41 | 
            -
                  File.foreach( | 
| 49 | 
            +
                  File.foreach("#{INCLUDE_DIR}/#{header}") do |line|
         | 
| 42 50 | 
             
                    # We only want to attempt to load exported functions.
         | 
| 43 51 | 
             
                    next unless line.start_with?("PRISM_EXPORTED_FUNCTION ")
         | 
| 44 52 |  | 
| @@ -73,6 +81,7 @@ module Prism | |
| 73 81 |  | 
| 74 82 | 
             
                callback :pm_parse_stream_fgets_t, [:pointer, :int, :pointer], :pointer
         | 
| 75 83 | 
             
                enum :pm_string_init_result_t, %i[PM_STRING_INIT_SUCCESS PM_STRING_INIT_ERROR_GENERIC PM_STRING_INIT_ERROR_DIRECTORY]
         | 
| 84 | 
            +
                enum :pm_string_query_t, [:PM_STRING_QUERY_ERROR, -1, :PM_STRING_QUERY_FALSE, :PM_STRING_QUERY_TRUE]
         | 
| 76 85 |  | 
| 77 86 | 
             
                load_exported_functions_from(
         | 
| 78 87 | 
             
                  "prism.h",
         | 
| @@ -83,6 +92,9 @@ module Prism | |
| 83 92 | 
             
                  "pm_serialize_lex",
         | 
| 84 93 | 
             
                  "pm_serialize_parse_lex",
         | 
| 85 94 | 
             
                  "pm_parse_success_p",
         | 
| 95 | 
            +
                  "pm_string_query_local",
         | 
| 96 | 
            +
                  "pm_string_query_constant",
         | 
| 97 | 
            +
                  "pm_string_query_method_name",
         | 
| 86 98 | 
             
                  [:pm_parse_stream_fgets_t]
         | 
| 87 99 | 
             
                )
         | 
| 88 100 |  | 
| @@ -492,4 +504,39 @@ module Prism | |
| 492 504 | 
             
                  values.pack(template)
         | 
| 493 505 | 
             
                end
         | 
| 494 506 | 
             
              end
         | 
| 507 | 
            +
             | 
| 508 | 
            +
              # Here we are going to patch StringQuery to put in the class-level methods so
         | 
| 509 | 
            +
              # that it can maintain a consistent interface
         | 
| 510 | 
            +
              class StringQuery
         | 
| 511 | 
            +
                class << self
         | 
| 512 | 
            +
                  # Mirrors the C extension's StringQuery::local? method.
         | 
| 513 | 
            +
                  def local?(string)
         | 
| 514 | 
            +
                    query(LibRubyParser.pm_string_query_local(string, string.bytesize, string.encoding.name))
         | 
| 515 | 
            +
                  end
         | 
| 516 | 
            +
             | 
| 517 | 
            +
                  # Mirrors the C extension's StringQuery::constant? method.
         | 
| 518 | 
            +
                  def constant?(string)
         | 
| 519 | 
            +
                    query(LibRubyParser.pm_string_query_constant(string, string.bytesize, string.encoding.name))
         | 
| 520 | 
            +
                  end
         | 
| 521 | 
            +
             | 
| 522 | 
            +
                  # Mirrors the C extension's StringQuery::method_name? method.
         | 
| 523 | 
            +
                  def method_name?(string)
         | 
| 524 | 
            +
                    query(LibRubyParser.pm_string_query_method_name(string, string.bytesize, string.encoding.name))
         | 
| 525 | 
            +
                  end
         | 
| 526 | 
            +
             | 
| 527 | 
            +
                  private
         | 
| 528 | 
            +
             | 
| 529 | 
            +
                  # Parse the enum result and return an appropriate boolean.
         | 
| 530 | 
            +
                  def query(result)
         | 
| 531 | 
            +
                    case result
         | 
| 532 | 
            +
                    when :PM_STRING_QUERY_ERROR
         | 
| 533 | 
            +
                      raise ArgumentError, "Invalid or non ascii-compatible encoding"
         | 
| 534 | 
            +
                    when :PM_STRING_QUERY_FALSE
         | 
| 535 | 
            +
                      false
         | 
| 536 | 
            +
                    when :PM_STRING_QUERY_TRUE
         | 
| 537 | 
            +
                      true
         | 
| 538 | 
            +
                    end
         | 
| 539 | 
            +
                  end
         | 
| 540 | 
            +
                end
         | 
| 541 | 
            +
              end
         | 
| 495 542 | 
             
            end
         | 
| @@ -2287,6 +2287,7 @@ module Prism | |
| 2287 2287 | 
             
                  flags = [("newline" if node.newline?), ("static_literal" if node.static_literal?), ("begin_modifier" if node.begin_modifier?)].compact
         | 
| 2288 2288 | 
             
                  commands << ["├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n", indent]
         | 
| 2289 2289 | 
             
                  commands << ["├── keyword_loc: #{inspect_location(node.keyword_loc)}\n", indent]
         | 
| 2290 | 
            +
                  commands << ["├── do_keyword_loc: #{inspect_location(node.do_keyword_loc)}\n", indent]
         | 
| 2290 2291 | 
             
                  commands << ["├── closing_loc: #{inspect_location(node.closing_loc)}\n", indent]
         | 
| 2291 2292 | 
             
                  commands << ["├── predicate:\n", indent]
         | 
| 2292 2293 | 
             
                  commands << [node.predicate, "#{indent}│   "]
         | 
| @@ -2328,6 +2329,7 @@ module Prism | |
| 2328 2329 | 
             
                  flags = [("newline" if node.newline?), ("static_literal" if node.static_literal?), ("begin_modifier" if node.begin_modifier?)].compact
         | 
| 2329 2330 | 
             
                  commands << ["├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n", indent]
         | 
| 2330 2331 | 
             
                  commands << ["├── keyword_loc: #{inspect_location(node.keyword_loc)}\n", indent]
         | 
| 2332 | 
            +
                  commands << ["├── do_keyword_loc: #{inspect_location(node.do_keyword_loc)}\n", indent]
         | 
| 2331 2333 | 
             
                  commands << ["├── closing_loc: #{inspect_location(node.closing_loc)}\n", indent]
         | 
| 2332 2334 | 
             
                  commands << ["├── predicate:\n", indent]
         | 
| 2333 2335 | 
             
                  commands << [node.predicate, "#{indent}│   "]
         |