From 8385e6fd11c3942ca800e5a65c1c435381188790 Mon Sep 17 00:00:00 2001 From: Cameron Dutro Date: Thu, 17 Jun 2021 16:05:44 -0700 Subject: [PATCH] WIP attempting to track output locations --- lib/unparser.rb | 5 +++-- lib/unparser/buffer.rb | 9 ++++++--- lib/unparser/concord.rb | 2 +- lib/unparser/emitter.rb | 7 ++++--- lib/unparser/emitter/argument.rb | 2 +- lib/unparser/emitter/class.rb | 3 ++- lib/unparser/emitter/def.rb | 8 +++++--- lib/unparser/emitter/module.rb | 3 ++- lib/unparser/emitter/primitive.rb | 25 ++++++++++++++++++++----- lib/unparser/emitter/root.rb | 2 +- lib/unparser/emitter/variable.rb | 9 ++++----- lib/unparser/generation.rb | 16 +++++++++++++--- lib/unparser/writer.rb | 2 +- lib/unparser/writer/send.rb | 4 ++-- 14 files changed, 65 insertions(+), 32 deletions(-) diff --git a/lib/unparser.rb b/lib/unparser.rb index ba22cef6..97fa260c 100644 --- a/lib/unparser.rb +++ b/lib/unparser.rb @@ -57,14 +57,15 @@ def initialize(message, node) # if the node passed is invalid # # @api public - def self.unparse(node, comment_array = []) + def self.unparse(node, comment_array = [], &callback) return '' if node.nil? Buffer.new.tap do |buffer| Emitter::Root.new( buffer, node, - Comments.new(comment_array) + Comments.new(comment_array), + callback ).write_to_buffer end.content end diff --git a/lib/unparser/buffer.rb b/lib/unparser/buffer.rb index 19674f15..b7037b34 100644 --- a/lib/unparser/buffer.rb +++ b/lib/unparser/buffer.rb @@ -31,7 +31,6 @@ def append(string) prefix end write(string) - self end # Append a string without an indentation prefix @@ -44,7 +43,6 @@ def append(string) # def append_without_prefix(string) write(string) - self end # Increase indent @@ -127,8 +125,13 @@ def capture_content # # @return [self] def write(fragment) + start_pos = @content.length @content << fragment - self + start_pos...@content.length + end + + def length + @content.length end private diff --git a/lib/unparser/concord.rb b/lib/unparser/concord.rb index f43227dc..c67ef207 100644 --- a/lib/unparser/concord.rb +++ b/lib/unparser/concord.rb @@ -8,7 +8,7 @@ class Concord < Module include Adamantium, Equalizer.new(:names) # The maximum number of objects the hosting class is composed of - MAX_NR_OF_OBJECTS = 3 + MAX_NR_OF_OBJECTS = 4 # Return names # diff --git a/lib/unparser/emitter.rb b/lib/unparser/emitter.rb index aedc5171..5f19457a 100644 --- a/lib/unparser/emitter.rb +++ b/lib/unparser/emitter.rb @@ -6,7 +6,7 @@ module Unparser # Emitter base class class Emitter include Adamantium, AbstractType, Constants, Generation, NodeHelpers - include Anima.new(:buffer, :comments, :node, :local_variable_scope) + include Anima.new(:buffer, :comments, :node, :local_variable_scope, :callback) public :node @@ -67,7 +67,7 @@ def emit_mlhs # @api private # # rubocop:disable Metrics/ParameterLists - def self.emitter(buffer:, comments:, node:, local_variable_scope:) + def self.emitter(buffer:, comments:, node:, local_variable_scope:, callback:) type = node.type klass = REGISTRY.fetch(type) do @@ -78,7 +78,8 @@ def self.emitter(buffer:, comments:, node:, local_variable_scope:) buffer: buffer, comments: comments, local_variable_scope: local_variable_scope, - node: node + node: node, + callback: callback ) end # rubocop:enable Metrics/ParameterLists diff --git a/lib/unparser/emitter/argument.rb b/lib/unparser/emitter/argument.rb index 93d44320..777e0707 100644 --- a/lib/unparser/emitter/argument.rb +++ b/lib/unparser/emitter/argument.rb @@ -87,7 +87,7 @@ class Argument < self private def dispatch - write(name.to_s) + write_loc(name.to_s, node.location.name.to_range) end end # Argument diff --git a/lib/unparser/emitter/class.rb b/lib/unparser/emitter/class.rb index ccdd26bf..fed60299 100644 --- a/lib/unparser/emitter/class.rb +++ b/lib/unparser/emitter/class.rb @@ -13,7 +13,8 @@ class Class < self private def dispatch - write('class ') + write_loc('class', node.location.keyword.to_range) + write(' ') visit(name) emit_superclass emit_optional_body(body) diff --git a/lib/unparser/emitter/def.rb b/lib/unparser/emitter/def.rb index 7d75ee1c..2a5b8f20 100644 --- a/lib/unparser/emitter/def.rb +++ b/lib/unparser/emitter/def.rb @@ -15,7 +15,8 @@ class Def < self private :body def dispatch - write('def ') + write_loc('def', node.location.keyword.to_range) + write(' ') emit_name emit_arguments emit_optional_body_ensure_rescue(body) @@ -39,7 +40,7 @@ class Instance < self private def emit_name - write(name.to_s) + write_loc(name.to_s, node.location.name.to_range) end end # Instance @@ -57,7 +58,8 @@ def emit_name conditional_parentheses(!subject_without_parens?) do visit(subject) end - write('.', name.to_s) + write_loc('.', node.location.operator.to_range) + write_loc(name.to_s, node.location.name.to_range) end def subject_without_parens? diff --git a/lib/unparser/emitter/module.rb b/lib/unparser/emitter/module.rb index 06b3d9b3..70bebb0b 100644 --- a/lib/unparser/emitter/module.rb +++ b/lib/unparser/emitter/module.rb @@ -13,7 +13,8 @@ class Module < self private def dispatch - write('module ') + write_loc('module', node.location.keyword.to_range) + write(' ') visit(name) emit_optional_body(body) k_end diff --git a/lib/unparser/emitter/primitive.rb b/lib/unparser/emitter/primitive.rb index e173704d..58e2fa52 100644 --- a/lib/unparser/emitter/primitive.rb +++ b/lib/unparser/emitter/primitive.rb @@ -7,18 +7,33 @@ class Primitive < self children :value - # Emitter for primitives based on Object#inspect - class Inspect < self + class Str < self - handle :sym, :str + handle :str private def dispatch - write(value.inspect) + new_loc = buffer.append(value.inspect) + return unless callback + + new_loc_adjusted = (new_loc.first + 1)...(new_loc.last - 1) + callback.call(buffer, node.location.expression.to_range, new_loc_adjusted) + end + + end # Str + + class Sym < self + + handle :sym + + private + + def dispatch + write_loc(value.inspect, node.location.expression.to_range) end - end # Inspect + end # Sym # Emitter for complex literals class Complex < self diff --git a/lib/unparser/emitter/root.rb b/lib/unparser/emitter/root.rb index e335f446..43d6df4e 100644 --- a/lib/unparser/emitter/root.rb +++ b/lib/unparser/emitter/root.rb @@ -4,7 +4,7 @@ module Unparser class Emitter # Root emitter a special case class Root < self - include Concord::Public.new(:buffer, :node, :comments) + include Concord::Public.new(:buffer, :node, :comments, :callback) include LocalVariableRoot END_NL = %i[class sclass module begin].freeze diff --git a/lib/unparser/emitter/variable.rb b/lib/unparser/emitter/variable.rb index e4915bac..5454fe76 100644 --- a/lib/unparser/emitter/variable.rb +++ b/lib/unparser/emitter/variable.rb @@ -12,7 +12,7 @@ class Variable < self private def dispatch - write(name.to_s) + write_loc(name.to_s, node.location.name.to_range) end end # Access @@ -27,14 +27,14 @@ class Const < self def dispatch emit_scope - write(name.to_s) + write_loc(name.to_s, node.location.name.to_range) end def emit_scope return unless scope visit(scope) - write('::') unless n_cbase?(scope) + write_loc('::', node.location.double_colon.to_range) unless n_cbase?(scope) end end @@ -48,8 +48,7 @@ class NthRef < self private def dispatch - write(PREFIX) - write(name.to_s) + write_loc([PREFIX, name.to_s], node.location.expression.to_range) end end # NthRef diff --git a/lib/unparser/generation.rb b/lib/unparser/generation.rb index e553c58d..67db645b 100644 --- a/lib/unparser/generation.rb +++ b/lib/unparser/generation.rb @@ -90,17 +90,27 @@ def write(*strings) strings.each(&buffer.method(:append)) end + def write_loc(strings, old_location, new_location = nil) + locs = Array(strings).map(&buffer.method(:append)) + return unless callback + + if old_location + new_location ||= locs.first.first...locs.last.last + callback.call(buffer, old_location, new_location) + end + end + def k_end buffer.indent emit_comments_before(:end) buffer.unindent - write('end') + write_loc('end', node.location.end.to_range) end def parentheses(open = '(', close = ')') - write(open) + write_loc(open, node.location.begin.to_range) if node.location.respond_to?(:begin) yield - write(close) + write_loc(close, node.location.end.to_range) if node.location.respond_to?(:begin) end def indented diff --git a/lib/unparser/writer.rb b/lib/unparser/writer.rb index 94b95bfd..ff344197 100644 --- a/lib/unparser/writer.rb +++ b/lib/unparser/writer.rb @@ -6,7 +6,7 @@ module Writer def self.included(descendant) descendant.class_eval do - include Anima.new(:buffer, :comments, :node, :local_variable_scope) + include Anima.new(:buffer, :comments, :node, :local_variable_scope, :callback) extend DSL end diff --git a/lib/unparser/writer/send.rb b/lib/unparser/writer/send.rb index 413bdc4f..155f0d95 100644 --- a/lib/unparser/writer/send.rb +++ b/lib/unparser/writer/send.rb @@ -27,7 +27,7 @@ def emit_mlhs end def emit_selector - write(details.string_selector) + write_loc(details.string_selector, node.location.selector.to_range) end def emit_heredoc_reminders @@ -59,7 +59,7 @@ def write_as_attribute_assignment? end def emit_operator - write(OPERATORS.fetch(node.type)) + write_loc(OPERATORS.fetch(node.type), node.location.dot.to_range) end def emit_arguments