Skip to content

Commit

Permalink
Compatibility with IRB
Browse files Browse the repository at this point in the history
Instead of accessing the struct as an array, access it via methods. There are other places inside of this file already using this API (for example https://github.com/ruby/ruby/blob/e0a5c3d2b71dfad038d7562fdd33f02ffd79232d/lib/irb/ruby-lex.rb#L829-L830).

This commit moves all struct array-ish calls to use their method calls instead. It is also ~1.23 faster accessing values via a method instead of as an array according to this microbenchmark:

```ruby
Elem = Struct.new(:pos, :event, :tok, :state, :message) do
  def initialize(pos, event, tok, state, message = nil)
    super(pos, event, tok, State.new(state), message)
  end

  # ...

  def to_a
    a = super
    a.pop unless a.empty?
    a
  end
end

class ElemClass
  attr_accessor :pos, :event, :tok, :state, :message

  def initialize(pos, event, tok, state, message = nil)
    @pos = pos
    @event = event
    @Tok = tok
    @State = State.new(state)
    @message = message
  end

  def to_a
    if @message
      [@pos, @event, @Tok, @State, @message]
    else
      [@pos, @event, @Tok, @State]
    end
  end
end

class State; def initialize(val); end; end
```

```ruby
Benchmark.ips do |x|
  x.report("struct") { struct[1] }
  x.report("class ") { from_class.event }
  x.compare!
end; nil
```

```
Warming up --------------------------------------
              struct     1.624M i/100ms
              class      1.958M i/100ms
Calculating -------------------------------------
              struct     17.139M (± 2.6%) i/s -     86.077M in   5.025801s
              class      21.104M (± 3.4%) i/s -    105.709M in   5.015193s

Comparison:
              class : 21103826.3 i/s
              struct: 17139201.5 i/s - 1.23x  (± 0.00) slower
```
  • Loading branch information
schneems authored and aycabta committed Dec 24, 2021
1 parent 02de8e5 commit 1b014ef
Showing 1 changed file with 8 additions and 0 deletions.
8 changes: 8 additions & 0 deletions lib/irb/ruby-lex.rb
Original file line number Diff line number Diff line change
Expand Up @@ -100,13 +100,15 @@ def set_input(io, p = nil, context: nil, &block)
code << t.tok
end
end

unless unprocessed_tokens.empty?
ltype, indent, continue, code_block_open = check_state(code, unprocessed_tokens, context: context)
result << @prompt.call(ltype, indent, continue || code_block_open, @line_no + line_num_offset)
end
result
end
end

if p.respond_to?(:call)
@input = p
elsif block_given?
Expand Down Expand Up @@ -570,6 +572,7 @@ def check_newline_depth_difference
when :on_sp
next
end

case t.event
when :on_lbracket, :on_lbrace, :on_lparen, :on_tlambeg
depth_difference += 1
Expand Down Expand Up @@ -658,6 +661,7 @@ def check_corresponding_token_depth(lines, line_index)
is_first_spaces_of_line = false
next
end

case t.event
when :on_lbracket, :on_lbrace, :on_lparen, :on_tlambeg
spaces_of_nest.push(spaces_at_line_head + open_brace_on_line * 2)
Expand Down Expand Up @@ -753,6 +757,8 @@ def check_string_literal(tokens)

def process_literal_type(tokens = @tokens)
start_token = check_string_literal(tokens)
return nil if start_token == ""

case start_token&.event
when :on_tstring_beg
case start_token&.tok
Expand Down Expand Up @@ -798,6 +804,7 @@ def check_termination_in_prev_line(code, context: nil)
false
end
end

if index
first_token = nil
last_line_tokens = tokens[(index + 1)..(tokens.size - 1)]
Expand All @@ -807,6 +814,7 @@ def check_termination_in_prev_line(code, context: nil)
break
end
end

if first_token.nil?
return false
elsif first_token && first_token.state == Ripper::EXPR_DOT
Expand Down

0 comments on commit 1b014ef

Please sign in to comment.