class Parser::Source::Rewriter


@api public
@return [Diagnostic::Engine]
@!attribute [r] diagnostics
@return [Source::Buffer]
@!attribute [r] source_buffer
The default diagnostic engine consumer simply prints the diagnostics to ‘stderr`.
the diagnostic engine. After that, an exception is raised.
a `:note` diagnostics describing both updates are generated and passed to
If it is detected that one update clobbers another one, an `:error` and
modify the same part of code.
verifies that no two updates clobber each other, that is, attempt to
It schedules code updates to be performed in the correct order and
{Rewriter} performs the heavy lifting in the source rewriting process.
#

def append(action)

def append(action)
  if (clobber_action = clobbered?(action.range))
    # cannot replace 3 characters with "foobar"
    diagnostic = Diagnostic.new(:error,
                                :invalid_action,
                                { :action => action },
                                action.range)
    @diagnostics.process(diagnostic)
    # clobbered by: remove 3 characters
    diagnostic = Diagnostic.new(:note,
                                :clobbered,
                                { :action => clobber_action },
                                clobber_action.range)
    @diagnostics.process(diagnostic)
    raise RuntimeError, "Parser::Source::Rewriter detected clobbering"
  else
    clobber(action.range)
    @queue << action
  end
  self
end

def clobber(range)

def clobber(range)
  @clobber |= (2 ** range.size - 1) << range.begin_pos
end

def clobbered?(range)

def clobbered?(range)
  if @clobber & ((2 ** range.size - 1) << range.begin_pos) != 0
    @queue.find do |action|
      action.range.to_a & range.to_a
    end
  end
end

def initialize(source_buffer)

Parameters:
  • source_buffer (Source::Buffer) --
def initialize(source_buffer)
  @diagnostics = Diagnostic::Engine.new
  @diagnostics.consumer = lambda do |diag|
    $stderr.puts diag.render
  end
  @source_buffer = source_buffer
  @queue         = []
  @clobber       = 0
end

def insert_after(range, content)

Raises:
  • (RuntimeError) - when clobbering is detected

Returns:
  • (Rewriter) - self

Parameters:
  • content (String) --
  • range (Range) --
def insert_after(range, content)
  append Rewriter::Action.new(range.end, content)
end

def insert_before(range, content)

Raises:
  • (RuntimeError) - when clobbering is detected

Returns:
  • (Rewriter) - self

Parameters:
  • content (String) --
  • range (Range) --
def insert_before(range, content)
  append Rewriter::Action.new(range.begin, content)
end

def process

Returns:
  • (String) -
def process
  adjustment = 0
  source     = @source_buffer.source.dup
  sorted_queue = @queue.sort_by.with_index do |action, index|
    [action.range.begin_pos, index]
  end
  sorted_queue.each do |action|
    begin_pos = action.range.begin_pos + adjustment
    end_pos   = begin_pos + action.range.length
    source[begin_pos...end_pos] = action.replacement
    adjustment += (action.replacement.length - action.range.length)
  end
  source
end

def remove(range)

Raises:
  • (RuntimeError) - when clobbering is detected

Returns:
  • (Rewriter) - self

Parameters:
  • range (Range) --
def remove(range)
  append Rewriter::Action.new(range, '')
end

def replace(range, content)

Raises:
  • (RuntimeError) - when clobbering is detected

Returns:
  • (Rewriter) - self

Parameters:
  • content (String) --
  • range (Range) --
def replace(range, content)
  append Rewriter::Action.new(range, content)
end