ripper-docs

Lists

Often your Ruby code will contain a variable-length list of items, like parameters to a method call, items in an array, or statements inside a block. Ripper doesn’t use variable-length events. Instead, every event has a fixed number of items.

In order to keep the number of parameters fixed for each event, Ripper often creates an empty item and then adds to it. For instance, here is how array literals are parsed by Ripper::SexpBuilder:

2.7.1 :001 > pp Ripper.sexp_raw("[1, 2, 3, 4, 5]")
[:program,
 [:stmts_add,
  [:stmts_new],
  [:array,
   [:args_add,
    [:args_add,
     [:args_add,
      [:args_add,
       [:args_add, [:args_new], [:@int, "1", [1, 1]]],
       [:@int, "2", [1, 4]]],
      [:@int, "3", [1, 7]]],
     [:@int, "4", [1, 10]]],
    [:@int, "5", [1, 13]]]]]]

Notice that args_new has no additional parameters, and the other array elements are added one at a time using args_add.

Other events, such as qsymbols_new/qsymbols_add work very much like args_new/args_add. Here’s what qsymbols_new/qsymbols_add looks like in Ripper::SexpBuilder:

2.7.1 :001 > pp Ripper.sexp_raw("%i[one two three]")
[:program,
 [:stmts_add,
  [:stmts_new],
  [:array,
   [:qsymbols_add,
    [:qsymbols_add,
     [:qsymbols_add, [:qsymbols_new], [:@tstring_content, "one", [1, 3]]],
     [:@tstring_content, "two", [1, 7]]],
    [:@tstring_content, "three", [1, 11]]]]]]

One of the differences between the Ripper::SexpBuilder and Ripper::SexpBuilderPP classes is that it replaces *_new/*_add chains with a Ruby array, such as stmts_new/stmts_add being replaced here:

2.7.1 :001 > pp Ripper.sexp("[1, 2, 3, 4, 5]")
[:program,
 [[:array,
   [[:@int, "1", [1, 1]],
    [:@int, "2", [1, 4]],
    [:@int, "3", [1, 7]],
    [:@int, "4", [1, 10]],
    [:@int, "5", [1, 13]]]]]]

The accomplish this same behavior in your own Ripper parser, you can duplicate the approach that Ripper::SexpBuilderPP takes by handling *_new events with a new array and *_add methods by adding onto that array, like here.

The convention to use *_new/*_add events to build lists is used in many places in the Ripper parser. The complete list is given below: