class Polyphony::DebugController

Constants

POLYPHONY_LIB_DIR

Public Class Methods

new(server) click to toggle source
# File lib/polyphony/debugger.rb, line 28
def initialize(server)
  @server = server
  @server.wait_for_client
  @state = { fibers: {} }
  @control_fiber = Fiber.new { |f| control_loop(f) }
  @control_fiber.transfer Fiber.current
end

Public Instance Methods

cmd_help(cmd) click to toggle source
# File lib/polyphony/debugger.rb, line 143
def cmd_help(cmd)
  get_next_command(kind: :help)
end
cmd_initial(cmd) click to toggle source
# File lib/polyphony/debugger.rb, line 99
def cmd_initial(cmd)
  get_next_command(nil)
end
cmd_list(cmd) click to toggle source
# File lib/polyphony/debugger.rb, line 147
def cmd_list(cmd)
  get_next_command(info_listing(@state))
end
cmd_state(cmd) click to toggle source
# File lib/polyphony/debugger.rb, line 151
def cmd_state(cmd)
  get_next_command(info_state(@state))
end
cmd_step(cmd) click to toggle source
# File lib/polyphony/debugger.rb, line 128
def cmd_step(cmd)
  tp = nil
  fiber = nil
  while true
    event = get_next_trace_event
    @peer = event[:fiber]
    if event[:kind] == :line && event[:path] !~ /#{POLYPHONY_LIB_DIR}/
      return get_next_command(info_listing(@state))
    end
  end
rescue => e
  trace "Uncaught error: #{e.inspect}"
  @trace&.disable
end
control_loop(source_fiber) click to toggle source
# File lib/polyphony/debugger.rb, line 36
def control_loop(source_fiber)
  @peer = source_fiber
  cmd = { cmd: :initial }
  loop do
    cmd = send(:"cmd_#{cmd[:cmd]}", cmd)
  end
end
fiber_id(fiber) click to toggle source
# File lib/polyphony/debugger.rb, line 79
def fiber_id(fiber)
  {
    object_id: fiber.object_id,
    tag: fiber.tag
  }
end
fiber_representation(fiber) click to toggle source
# File lib/polyphony/debugger.rb, line 86
def fiber_representation(fiber)
  {
    object_id: fiber.object_id,
    tag: fiber.tag,
    parent: fiber.parent && fiber_id(fiber.parent),
    children: fiber.children.map { |c| fiber_id(c) }
  }
end
get_next_command(info) click to toggle source
# File lib/polyphony/debugger.rb, line 95
def get_next_command(info)
  @server.get_command(info)
end
get_next_trace_event() click to toggle source
# File lib/polyphony/debugger.rb, line 46
def get_next_trace_event
  @peer.transfer.tap { |e| update_state(e) }
end
handle_tp(trace, tp) click to toggle source
# File lib/polyphony/debugger.rb, line 155
def handle_tp(trace, tp)
  return if Thread.current == @server.thread
  return if Fiber.current == @control_fiber

  kind = tp.event
  event = {
    fiber: Fiber.current,
    kind: kind,
    path: tp.path,
    lineno: tp.lineno,
    binding: tp.binding
  }
  case kind
  when :call, :c_call, :b_call
    event[:method_id] = tp.method_id
    event[:parameters] = tp.parameters
  when :return, :c_return, :b_return
    event[:method_id] = tp.method_id
    event[:return_value] = tp.return_value
  end
  @control_fiber.transfer(event)
end
info_fiber_states(fiber_states) click to toggle source
# File lib/polyphony/debugger.rb, line 119
def info_fiber_states(fiber_states)
  fiber_states.inject({}) do |h, (f, s)|
    h[fiber_id(f)] = {
      stack: s[:stack].map { |e| { path: e[:path], lineno: e[:lineno] } }
    }
    h
  end
end
info_listing(state) click to toggle source
# File lib/polyphony/debugger.rb, line 103
def info_listing(state)
  {
    kind: :listing,
    fiber: fiber_id(state[:fiber]),
    path: state[:path],
    lineno: state[:lineno]
  }
end
info_state(state) click to toggle source
# File lib/polyphony/debugger.rb, line 112
def info_state(state)
  info_listing(state).merge(
    kind: :state,
    fibers: info_fiber_states(state[:fibers])
  )
end
state_presentation(state) click to toggle source
# File lib/polyphony/debugger.rb, line 71
def state_presentation(state)
  {
    fiber:  fiber_id(state[:fiber]),
    path:   state[:path],
    lineno: state[:lineno]
  }
end
update_fiber_state(event) click to toggle source
# File lib/polyphony/debugger.rb, line 58
def update_fiber_state(event)
  fiber_state = @state[:fibers][event[:fiber]] ||= { stack: [] }
  case event[:kind]
  when :call, :c_call, :b_call
    fiber_state[:stack] << event
  when :return, :c_return, :b_return
    fiber_state[:stack].pop
  end
  fiber_state[:binding] = event[:binding]
  fiber_state[:path] = event[:path]
  fiber_state[:lineno] = event[:lineno]
end
update_state(event) click to toggle source
# File lib/polyphony/debugger.rb, line 50
def update_state(event)
  trace update_state: event
  @state[:fiber] = event[:fiber]
  @state[:path] = event[:path]
  @state[:lineno] = event[:lineno]
  update_fiber_state(event)
end