Skip to content

Commit

Permalink
Item patchers refactoring: merge execution paths by parsing inserted …
Browse files Browse the repository at this point in the history
…lines
  • Loading branch information
andreyvit committed Sep 5, 2010
1 parent 3d85186 commit cdc4583
Show file tree
Hide file tree
Showing 10 changed files with 217 additions and 70 deletions.
2 changes: 1 addition & 1 deletion lib/xdry.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ module XDry
parsing/scopes_support parsing/scopes
parsing/scope_stack parsing/driver

patching/emitter patching/patcher
patching/emitter patching/patcher patching/insertion_points patching/item_patchers

boxing generators_support run
}.each { |name| require File.join(File.dirname(__FILE__), 'xdry', name) }
Expand Down
52 changes: 13 additions & 39 deletions lib/xdry/generators/dealloc.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,24 @@
module XDry
module Generators

class MethodPatcher

attr_reader :oclass
attr_reader :omethod

def initialize oclass
@oclass = oclass
find!
end

def found?
not omethod.nil?
end

protected
class DeallocMethodPatcher < MethodPatcher

def find
find_method_impl_by_selector('dealloc')
end

def find_method_impl_by_selector selector
m = oclass.find_method(selector)
m && (m.has_impl? ? m : nil)
def empty_implementation
[
"",
"- (void)dealloc {",
"\t[super dealloc];",
"}",
"",
]
end

private

def find!
@omethod = find
end

end

class DeallocMethodPatcher < MethodPatcher

def find
find_method_impl_by_selector('dealloc')
def insertion_point
ImplementationStartIP.new(oclass)
end

end
Expand All @@ -47,7 +29,7 @@ class Dealloc < Generator

def process_class oclass

dealloc_method_area = DeallocMethodPatcher.new(oclass)
dealloc_method_area = DeallocMethodPatcher.new(oclass, patcher)
if dealloc_method_area.found?
dealloc_method = dealloc_method_area.omethod
impl = dealloc_method.impl
Expand All @@ -66,14 +48,6 @@ def process_class oclass
lines = lines.collect { |l| indent + l }

@patcher.insert_before ending_node.pos, lines unless lines.empty?
else
lines = generate_release_calls_if(oclass) { true }
unless lines.empty?
lines = ["", "- (void)dealloc {"] + lines.collect { |l| INDENT_STEP+l } +
[INDENT_STEP + "[super dealloc];", "}", ""]
node = oclass.main_implementation.start_node
@patcher.insert_after node.pos, lines
end
end
end

Expand Down
75 changes: 52 additions & 23 deletions lib/xdry/parsing/driver.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,62 +11,91 @@ def initialize oglobal
@verbose = false
end

def new_lines_generator g, file_ref, io
line_no = 0
io.each_line do |line|
line_no += 1
orig_line = line.dup
line.strip!

# strip end-of-line comments, but keep comment lines
eol_comments = ''
line_without_comments = line.sub(%r`//.*$`) { eol_comments = $&; '' }
unless line_without_comments.empty?
line = line_without_comments
end

indent = if orig_line =~ /^(\s+)/ then $1 else '' end
g.yield [orig_line, line, Pos.new(file_ref, line_no), eol_comments, indent]
end
end

def parse_file file_name
gen = Generator.new { |g|
file_ref = FileRef.new(file_name)
File.open(file_name) do |file|
new_lines_generator g, file_ref, file
end
}
parse_data gen
parse_data_in_file_scope gen
end

def parse_string file_name, source
gen = Generator.new { |g|
file_ref = TestFileRef.new(file_name, source)
new_lines_generator g, file_ref, StringIO.new(source)
}
parse_data gen
parse_data_in_file_scope gen
end

def parse_fragment file_ref, lines, start_lineno, start_scope
gen = Generator.new { |g|
new_lines_from_array_generator g, file_ref, start_lineno, lines
}
parse_data_in_scopes gen, start_scope.all_scopes
end

private

def parse_data gen
scope_stack = ScopeStack.new(@oglobal.new_file_scope)
def parse_data_in_file_scope gen
parse_data_in_scopes gen, [@oglobal.new_file_scope]
end

def parse_data_in_scopes gen, scopes
scope_stack = ScopeStack.new(scopes)
scope_stack.verbose = @verbose
while gen.next?
orig_line, line, pos, eol_comments, indent = gen.next
puts " #{pos} #{orig_line}" if @verbose
pos.scope_before = scope_stack.current_scope
scope_stack.parse_line line, eol_comments do |scope, child|
# child is a Node or a Scope
if child.is_a? Node
child.pos = pos
child.indent = indent
end

puts "#{scope} << #{child}" if @verbose
scope << child
end
pos.scope_after = scope_stack.current_scope
end
end

def new_lines_generator g, file_ref, io
line_no = 0
io.each_line do |line|
line_no += 1
orig_line, line, eol_comments, indent = split_line(line)
g.yield [orig_line, line, Pos.new(file_ref, line_no), eol_comments, indent]
end
end

def new_lines_from_array_generator g, file_ref, start_lineno, lines
line_no = start_lineno - 1
lines.each do |line|
line_no += 1
orig_line, line, eol_comments, indent = split_line(line.dup)
g.yield [orig_line, line, Pos.new(file_ref, line_no), eol_comments, indent]
end
end

def split_line line
orig_line = line.dup
line.strip!

# strip end-of-line comments, but keep comment lines
eol_comments = ''
line_without_comments = line.sub(%r`//.*$`) { eol_comments = $&; '' }
unless line_without_comments.empty?
line = line_without_comments
end

indent = if orig_line =~ /^(\s+)/ then $1 else '' end
return [orig_line, line, eol_comments, indent]
end

end

end
1 change: 1 addition & 0 deletions lib/xdry/parsing/model.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def lookup_class name
end

class OClass
attr_reader :oglobal
attr_reader :name, :field_defs, :attributes, :methods
attr_reader :interfaces
attr_reader :implementations
Expand Down
1 change: 1 addition & 0 deletions lib/xdry/parsing/pos.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ def read

class Pos
attr_reader :file_ref, :line_no
attr_accessor :scope_before, :scope_after

def initialize file_ref, line_no
@file_ref = file_ref
Expand Down
8 changes: 6 additions & 2 deletions lib/xdry/parsing/scope_stack.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ class ScopeStack

attr_accessor :verbose

def initialize root_scope
def initialize root_scopes
@stack = []
push root_scope
root_scopes.each { |scope| push(scope) }
end

def parse_line line, eol_comments
Expand All @@ -30,6 +30,10 @@ def parse_line line, eol_comments
end
end

def current_scope
@current_scope
end

private

def push subscope
Expand Down
18 changes: 16 additions & 2 deletions lib/xdry/parsing/scopes_support.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def parser

def subscope_for node
if subscope_class = self.class.child_subscope_table[node.class]
subscope_class.new(node)
subscope_class.new(self, node)
else
nil
end
Expand All @@ -54,6 +54,14 @@ def to_s
"#{self.class.name}:#{@model}"
end

def parent_scopes
[]
end

def all_scopes
parent_scopes + [self]
end

protected

def create_parser
Expand Down Expand Up @@ -118,12 +126,18 @@ def child_collections
class ChildScope < Scope

attr_reader :start_node
attr_reader :parent_scope

def initialize start_node
def initialize parent_scope, start_node
super()
@parent_scope = parent_scope
@start_node = start_node
end

def parent_scopes
parent_scope.all_scopes
end

end

end
72 changes: 72 additions & 0 deletions lib/xdry/patching/insertion_points.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@

module XDry

class InsertionPoint

attr_reader :method, :node

def initialize
find!
end

def insert patcher, lines
raise StandardError, "#{self.class.name} has not been found but trying to insert" unless found?
patcher.send(@method, @node.pos, lines)
end

def found?
not @method.nil?
end

protected

def before node
@method = :insert_before
@node = node
end

def after node
@method = :insert_after
@node = node
end

def try insertion_point
if insertion_point.found?
@method, @node = insertion_point.method, insertion_point.node
true
else
false
end
end

def find!
end

end

class ImplementationStartIP < InsertionPoint

def initialize oclass
@oclass = oclass
super()
end

def find!
after @oclass.main_implementation.start_node
end

end

class MultiIP < InsertionPoint

def initialize *insertion_points
@insertion_points = insertion_points
end

def find!
@insertion_points.detect { |ip| try ip }
end

end

end
Loading

0 comments on commit cdc4583

Please sign in to comment.