Repository: ruby/yarp (c)

Issue:
RegexpNode options for e, u, s, and n don't match MRI
We got `m`, `i`, and `x` working in #1437, but the other four require a bit more care. `e`. `u`, and `s` map to a single bit, and `n` is high enough that masking alone won't work.

What I'd like to see:

```ruby
irb(main):001:0> //e.options
=> 16
irb(main):002:0> //u.options
=> 16
irb(main):003:0> //s.options
=> 16
irb(main):004:0> Regexp::FIXEDENCODING
=> 16
irb(main):005:0> //n.options
=> 32
irb(main):006:0> Regexp::NOENCODING
=> 32
```

What YARP gives:

```ruby
irb(main):007:0> YARP.parse('//e').value.statements.body.first.options
=> 0
irb(main):008:0> YARP.parse('//u').value.statements.body.first.options
=> 0
irb(main):009:0> YARP.parse('//s').value.statements.body.first.options
=> 0
irb(main):010:0> YARP.parse('//n').value.statements.body.first.options
=> 0
```

Pull request description:
Return Regexp options that match MRI for e, u, s, and n
Fixes #1516

I'm trying to match the final `Regexp` constants with `RegularExpressionNode#options` and `InterpolatedRegularExpressionNode#options`.

I don't know if this is a good approach. If it's not, feel free to close unceremoniously! ❤️ 

Patch:
diff --git a/lib/yarp.rb b/lib/yarp.rb
index c1043c32..48b1f173 100644
--- a/lib/yarp.rb
+++ b/lib/yarp.rb
@@ -587,11 +587,12 @@ module YARP
 
   class InterpolatedRegularExpressionNode < Node
     # Returns a numeric value that represents the flags that were used to create
-    # the regular expression. This mirrors the Regexp#options method in Ruby.
-    # Note that this is effectively masking only the three common flags that are
-    # used in Ruby, and does not include the full set of flags like encoding.
+    # the regular expression.
     def options
-      flags & 0b111
+      o = flags & 0b111
+      o |= Regexp::FIXEDENCODING if flags.anybits?(RegularExpressionFlags::EUC_JP | RegularExpressionFlags::WINDOWS_31J | RegularExpressionFlags::UTF_8)
+      o |= Regexp::NOENCODING if flags.anybits?(RegularExpressionFlags::ASCII_8BIT)
+      o
     end
   end
 
@@ -604,11 +605,12 @@ module YARP
 
   class RegularExpressionNode < Node
     # Returns a numeric value that represents the flags that were used to create
-    # the regular expression. This mirrors the Regexp#options method in Ruby.
-    # Note that this is effectively masking only the three common flags that are
-    # used in Ruby, and does not include the full set of flags like encoding.
+    # the regular expression.
     def options
-      flags & 0b111
+      o = flags & 0b111
+      o |= Regexp::FIXEDENCODING if flags.anybits?(RegularExpressionFlags::EUC_JP | RegularExpressionFlags::WINDOWS_31J | RegularExpressionFlags::UTF_8)
+      o |= Regexp::NOENCODING if flags.anybits?(RegularExpressionFlags::ASCII_8BIT)
+      o
     end
   end
 end


Test patch:
diff --git a/test/yarp/regexp_test.rb b/test/yarp/regexp_test.rb
index c2f92e2b..865c70a2 100644
--- a/test/yarp/regexp_test.rb
+++ b/test/yarp/regexp_test.rb
@@ -208,6 +208,20 @@ module YARP
       assert_equal(Regexp::MULTILINE, options("m"))
     end
 
+    def test_flag_fixedencoding
+      assert_equal(Regexp::FIXEDENCODING, options("e"))
+      assert_equal(Regexp::FIXEDENCODING, options("u"))
+      assert_equal(Regexp::FIXEDENCODING, options("s"))
+    end
+
+    def test_flag_noencoding
+      assert_equal(Regexp::NOENCODING, options("n"))
+    end
+
+    def test_flag_once
+      assert_equal(0, options("o"))
+    end
+
     def test_flag_combined
       value = Regexp::IGNORECASE | Regexp::MULTILINE | Regexp::EXTENDED
       assert_equal(value, options("mix"))