objc2swift_assistant 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.idea/.name +1 -0
  4. data/.idea/.rakeTasks +7 -0
  5. data/.idea/compiler.xml +22 -0
  6. data/.idea/copyright/profiles_settings.xml +3 -0
  7. data/.idea/dictionaries/ckornher.xml +7 -0
  8. data/.idea/encodings.xml +4 -0
  9. data/.idea/misc.xml +4 -0
  10. data/.idea/modules.xml +8 -0
  11. data/.idea/objc2swift_assistant.iml +103 -0
  12. data/.idea/runConfigurations/Console.xml +26 -0
  13. data/.idea/runConfigurations/assistant.xml +28 -0
  14. data/.idea/runConfigurations/help_text.xml +28 -0
  15. data/.idea/scopes/scope_settings.xml +5 -0
  16. data/.idea/uiDesigner.xml +124 -0
  17. data/.idea/vcs.xml +6 -0
  18. data/.idea/workspace.xml +1484 -0
  19. data/.rspec +2 -0
  20. data/.travis.yml +3 -0
  21. data/CODE_OF_CONDUCT.md +13 -0
  22. data/Gemfile +8 -0
  23. data/LICENSE.txt +21 -0
  24. data/README.md +83 -0
  25. data/Rakefile +1 -0
  26. data/bin/console +14 -0
  27. data/bin/objc2swift_assistant +50 -0
  28. data/bin/setup +7 -0
  29. data/lib/assistant.rb +110 -0
  30. data/lib/objc2swift_assistant/code_recognizer.rb +220 -0
  31. data/lib/objc2swift_assistant/file_hierarchical_config.rb +168 -0
  32. data/lib/objc2swift_assistant/file_sets.rb +577 -0
  33. data/lib/objc2swift_assistant/logging.rb +19 -0
  34. data/lib/objc2swift_assistant/objc_2_swift.rb +734 -0
  35. data/lib/objc2swift_assistant/objc_2_swift_block_conversion.rb +106 -0
  36. data/lib/objc2swift_assistant/objc_2_swift_configuration.rb +108 -0
  37. data/lib/objc2swift_assistant/objc_2_swift_type_mapping.rb +64 -0
  38. data/lib/objc2swift_assistant/objc_variable_types.rb +76 -0
  39. data/lib/objc2swift_assistant/processing_element.rb +32 -0
  40. data/lib/objc2swift_assistant/recognizers/at_sign_directives_recognizer.rb +41 -0
  41. data/lib/objc2swift_assistant/recognizers/category_recognizer.rb +72 -0
  42. data/lib/objc2swift_assistant/recognizers/enum_recognizer.rb +0 -0
  43. data/lib/objc2swift_assistant/recognizers/implementation_recognizer.rb +31 -0
  44. data/lib/objc2swift_assistant/recognizers/interface_recognizer.rb +37 -0
  45. data/lib/objc2swift_assistant/recognizers/method_recognizer.rb +190 -0
  46. data/lib/objc2swift_assistant/recognizers/pragma_mark_recognizer.rb +41 -0
  47. data/lib/objc2swift_assistant/recognizers/property_declaration_recognizer.rb +78 -0
  48. data/lib/objc2swift_assistant/recognizers/protocol_recognizer.rb +40 -0
  49. data/lib/objc2swift_assistant/recognizers/recognizer_keys.rb +26 -0
  50. data/lib/objc2swift_assistant/settings_file.rb +23 -0
  51. data/lib/objc2swift_assistant/swift_file_generator.rb +27 -0
  52. data/lib/objc2swift_assistant/version.rb +3 -0
  53. data/objc2swift_assistant.gemspec +31 -0
  54. metadata +128 -0
@@ -0,0 +1,168 @@
1
+ require_relative "version"
2
+
3
+ module Objc2swiftAssistant
4
+
5
+ SUBDIR_KEY = 'subdirs'
6
+ PATH_KEY = 'path'
7
+
8
+
9
+ class FileHierarchicalConfig
10
+ attr_accessor :node_class
11
+ attr_accessor :config_hash
12
+ attr_accessor :configs_by_path
13
+ attr_accessor :failure_reason
14
+ attr_accessor :all_valid_keys
15
+ attr_accessor :failure_reason
16
+
17
+
18
+ def initialize( config_hash, config_keys )
19
+ @node_class = FileHierarchicalConfigNode
20
+ @all_valid_keys = config_keys + [ SUBDIR_KEY, PATH_KEY ]
21
+ @config_hash = config_hash
22
+ @configs_by_path = {}
23
+ end
24
+
25
+ def load_configuration
26
+ # path test
27
+ # p = Pathname.new( "/a/b/c/d")
28
+ # done = false
29
+ # until done
30
+ # puts( "path= #{p.to_s}")
31
+ # p = p.parent
32
+ # end
33
+
34
+ # @failure_reason = 'No Root configuration specified' unless root_hash.path.to_s == '' TODO: Fail is path specified
35
+ root_node = node_class.new( self, @config_hash, '.' )
36
+ add_config_node( root_node )
37
+
38
+ # root_node.apply_wildcards
39
+ end
40
+
41
+ def add_config_node( config_node )
42
+ if @configs_by_path.has_key?( config_node.path_from_root.to_s )
43
+ return false, "A configuration node already exists for #{config_node.path_from_root.to_s}"
44
+ end
45
+
46
+ @configs_by_path[ config_node.path_from_root.to_s ] = config_node
47
+ return true, nil
48
+ end
49
+
50
+ def config_value( path_str, key )
51
+ pathname = Pathname.new( path_str )
52
+ value = nil
53
+ config = nil
54
+ while config.nil?
55
+ config = @configs_by_path[ pathname.to_s ]
56
+ break if pathname.to_s == "." && config.nil? # This should not happen, but just in case
57
+ pathname = pathname.parent
58
+ end
59
+
60
+ value = config.config_value_for_key( key, path_str ) unless config.nil?
61
+ value
62
+ end
63
+
64
+ def config_value_defaulted( path_str, key, default )
65
+ value = config_value( path_str, key )
66
+ value.nil? ? default : value
67
+ end
68
+ end
69
+
70
+ class FileHierarchicalConfigNode
71
+ attr_accessor :configuration
72
+ attr_accessor :path_from_parent
73
+ attr_accessor :path_from_root
74
+ attr_accessor :parent_node
75
+ attr_accessor :child_nodes
76
+ attr_accessor :wildcard_nodes
77
+ attr_accessor :configuration_hash
78
+
79
+
80
+ def initialize( configuration, node_hash, relative_path, parent:nil, is_wildcard:false )
81
+ @configuration = configuration
82
+ @configuration_hash = node_hash || {}
83
+ @path_from_parent = Pathname.new( relative_path ) #'.' is the "root" of relative Pathname. i.e. Pathname.parent.parent...
84
+ @child_nodes = []
85
+
86
+ if( parent.nil? )
87
+ @path_from_root = Pathname.new( relative_path ) unless is_wildcard # Parents set on clones of this object
88
+ @parent_node = nil
89
+ else
90
+ add_to_parent( parent )
91
+ end
92
+
93
+ @wildcard_nodes = []
94
+
95
+ child_hashes = @configuration_hash[ "subdirs" ] || nil
96
+ unless child_hashes.nil?
97
+ child_hashes.each do |child_hash|
98
+ path_str = child_hash['path']
99
+ make_child_node( path_str, child_hash )
100
+ end
101
+ end
102
+
103
+ post_process_config
104
+ end
105
+
106
+ def make_child_node( path_str, child_hash )
107
+ m = path_str.match(/\*\*\/(?<path>.*)/)
108
+ if m.nil?
109
+ child = @configuration.node_class.new( @configuration, child_hash, path_str, parent: self )
110
+ success, failure_reason = configuration.add_config_node(child)
111
+ @configuration.log_error("Could not add child configuration for path:#{child.path} to parent node with path:#{@path} - #{failure_reason})") unless success
112
+ else
113
+ path_str = m[ 'path' ]
114
+ wild_child = @configuration.node_class.new(@configuration, child_hash, path_str, is_wildcard:true)
115
+ @wildcard_nodes << wild_child
116
+ end
117
+ end
118
+
119
+
120
+ def add_to_parent( parent )
121
+ @parent_node = parent
122
+ @parent_node.child_nodes << self
123
+ @path_from_root = parent.path_from_root.join( @path_from_parent )
124
+ end
125
+
126
+ def post_process_config()
127
+ # Hook for subclasses
128
+ end
129
+
130
+ # def apply_wildcards( parent_wildcards=[] )
131
+ # all_wildcards = @wildcard_nodes + parent_wildcards
132
+ # @child_nodes.clone.each { |node| node.apply_wildcards( all_wildcards ) }
133
+ #
134
+ # all_wildcards.each do |wildcard_node|
135
+ # new_child = wildcard_node.clone
136
+ # new_child.add_to_parent( self )
137
+ # success, failure_reason = configuration.add_config_node( new_child ) #todo look for errors
138
+ # end
139
+ # end
140
+
141
+ def config_value_for_key( key, path_str )
142
+ value = nil
143
+ unless path_str.nil? || @wildcard_nodes.length == 0
144
+ catch :wildcard_value_found do
145
+ @wildcard_nodes.each do |wildcard_node|
146
+ pathname = Pathname.new( path_str )
147
+ until pathname.to_s == @path_from_root.to_s
148
+ if pathname.to_s.end_with?( wildcard_node.path_from_parent.to_s )
149
+ value = wildcard_node.config_value_for_key( key, nil )
150
+ throw :wildcard_value_found
151
+ end
152
+ pathname = pathname.parent
153
+ end
154
+ end
155
+ end
156
+ end
157
+
158
+ if value.nil?
159
+ value = @configuration_hash[ key ]
160
+ value ||= parent_node.config_value_for_key( key, path_str ) unless parent_node.nil?
161
+ end
162
+
163
+ value
164
+ end
165
+
166
+ end
167
+
168
+ end
@@ -0,0 +1,577 @@
1
+ require_relative "version"
2
+
3
+ require "fiber"
4
+
5
+ require_relative "code_recognizer"
6
+ require_relative "objc_2_swift"
7
+ require_relative "objc_2_swift_configuration"
8
+ require_relative "processing_element"
9
+
10
+ require "swift_generator/code_generation/swift_class_generation"
11
+ require "swift_generator/code_generation/swift_file_template"
12
+ require "swift_generator/code_generation/swift_class_generation"
13
+
14
+ module Objc2swiftAssistant
15
+
16
+ class FileSet < FailableProcessingElement
17
+ attr_accessor :root
18
+ attr_accessor :root_dir_node
19
+ attr_accessor :directory_nodes_by_path
20
+ attr_accessor :configuration
21
+
22
+ def initialize( root, configuration )
23
+ super()
24
+ @configuration = configuration
25
+ @root = Pathname.new( root )
26
+ @directory_nodes_by_path = {}
27
+ end
28
+
29
+ def directory_node_for_path( path )
30
+ node = @directory_nodes_by_path[ path.to_s ]
31
+
32
+ if node.nil?
33
+ node = make_directory_node( path )
34
+ @directory_nodes_by_path[ path.to_s ] = node
35
+ end
36
+
37
+ return node
38
+ end
39
+
40
+ def make_directory_node( path )
41
+ node = DirectoryNode.new( path, self )
42
+ node
43
+ end
44
+
45
+ def dump( indent, tab, errors_only )
46
+ if errors_only
47
+ puts( "\nWARNING: You specified '--structure errors'")
48
+ puts( " This option (Logging only only the file structure that caused errors) is not yet supported. The full source file structure will be logged.\n\n" )
49
+ end
50
+
51
+ @configuration.log_verbose( indent + "File Set")
52
+ @root_dir_node.dump( indent+tab, tab, errors_only )
53
+ end
54
+
55
+ # Create nodes for all directories and files of interest
56
+ # Use find() to limit stack depth
57
+ def scan()
58
+ @root.find() do |path|
59
+ if path.directory?
60
+ process_directory( path )
61
+ else
62
+ process_file( path )
63
+ end
64
+ end
65
+
66
+ @configuration.log_verbose( "Processed #{@directory_nodes_by_path.size} directories.")
67
+
68
+ collect_active_file_nodes()
69
+ end
70
+ end
71
+
72
+ class ScannedFileSet < FileSet
73
+ attr_accessor :active_file_nodes
74
+
75
+ def initialize( root, configuration )
76
+ super( root, configuration )
77
+ end
78
+
79
+ def process_directory(path)
80
+ directory_node = directory_node_for_path( path )
81
+ if directory_node.relative_path.to_s == '.'
82
+ @root_dir_node = directory_node
83
+ end
84
+ @configuration.log_verbose( "Processing Directory: #{path.to_s}")
85
+ end
86
+
87
+ def process_file(path)
88
+ @configuration.log_verbose( "Processing File: #{path.to_s}")
89
+ dir_node = directory_node_for_path( path.parent )
90
+ dir_node.process_file( path )
91
+ end
92
+
93
+
94
+ def collect_active_file_nodes
95
+ @active_file_nodes = []
96
+
97
+ @directory_nodes_by_path.each do |_, directory_node |
98
+ @configuration.log_verbose( "Collecting file nodes for directory:#{directory_node.full_path}")
99
+ directory_node.file_nodes_by_name.each do |_, file_node |
100
+ file_node.prepare_for_use()
101
+ if file_node.should_be_used
102
+ @active_file_nodes << file_node
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
108
+
109
+
110
+ class DirectoryNode
111
+ attr_accessor :file_set
112
+ attr_accessor :file_nodes_by_name
113
+ attr_accessor :full_path
114
+ attr_accessor :relative_path
115
+ attr_accessor :child_directories
116
+ attr_accessor :parent_node
117
+ attr_accessor :pruned
118
+
119
+ def initialize(path, file_set)
120
+ @full_path = path
121
+ @file_set = file_set
122
+
123
+ if file_set.root == @full_path
124
+ @parent_node = nil
125
+ else
126
+ @parent_node = file_set.directory_node_for_path( path.parent )
127
+ end
128
+
129
+ @relative_path = @full_path.relative_path_from( file_set.root )
130
+
131
+ @child_directories = {}
132
+ @file_nodes = {}
133
+ @pruned = false
134
+ @file_nodes_by_name = {}
135
+
136
+ #todo: Apply settings
137
+
138
+ unless @parent_node.nil?
139
+ @parent_node.add_child_directory( self )
140
+ end
141
+ end
142
+
143
+ # Add a child directory. Mark the child as pruned if this node is pruned. Note that this keeps
144
+ # pruned nodes around which is desirable for reporting the effects of code generation
145
+ def add_child_directory( child_node )
146
+ @child_directories[ child_node.relative_path.basename().to_s ] = child_node
147
+ child_node.pruned = @pruned
148
+ end
149
+
150
+ def dump( indent, tab, errors_only )
151
+ puts( indent + "Path: #{@relative_path.to_s}")
152
+ puts( indent + "Files:") unless @file_nodes_by_name.length == 0
153
+ @file_nodes_by_name.each_value { |file| file.dump( indent+tab, tab, errors_only ) }
154
+ puts( "\n" + indent + "Child Directories:") unless @child_directories.length == 0
155
+ @child_directories.each_value { |dir| dir.dump( indent+tab, tab, errors_only ) }
156
+ end
157
+
158
+ end
159
+
160
+ class ObjCDirectoryNode < DirectoryNode
161
+ attr_accessor :associated_generated_directory
162
+
163
+ def initialize(path, file_set)
164
+ super(path, file_set)
165
+ end
166
+
167
+ def process_file( path )
168
+ basename = path.basename
169
+
170
+ without_extension = path.basename(".h") || path.basename(".hh")
171
+ if without_extension != basename
172
+ file_node = file_node_for_file( without_extension.to_s )
173
+ file_node.header_file_path = path
174
+ return
175
+ end
176
+
177
+ without_extension = path.basename(".m") || path.basename(".mm")
178
+ if without_extension != basename
179
+ file_node = file_node_for_file( without_extension.to_s )
180
+ file_node.implementation_file_path = path
181
+ return
182
+ end
183
+
184
+ @file_set.configuration.log_verbose( "File not captured:#{path.to_s}")
185
+ end
186
+
187
+ def file_node_for_file( without_extension_string )
188
+ file_node = @file_nodes_by_name[ without_extension_string ]
189
+
190
+ if file_node.nil?
191
+ file_node = ObjCFileNode.new( self, without_extension_string )
192
+ @file_nodes_by_name[ without_extension_string ] = file_node
193
+ end
194
+
195
+ return file_node
196
+ end
197
+
198
+ def create_associated_generated_nodes( generated_file_set )
199
+ # puts( "generaating file node: #{@relative_path}")
200
+ #TODO: Break this out into Swift generation-specific ruby file
201
+ return if @pruned
202
+
203
+ # #TODO: allow mapping to new directory scruture for this file
204
+ generated_relative_path = generated_file_set.root + @relative_path
205
+ @associated_generated_directory = generated_file_set.directory_node_for_path( generated_relative_path )
206
+ @file_nodes_by_name.each_value do |file_node|
207
+ # puts( "generaating file node: #{file_node.}")
208
+ file_node.create_generated_file_nodes( generated_file_set, @associated_generated_directory )
209
+ end
210
+ end
211
+ end
212
+
213
+
214
+ class SourceFileNode
215
+ attr_accessor :directory_node
216
+ attr_accessor :should_be_used
217
+ attr_accessor :file_set
218
+
219
+ def initialize( directory_node )
220
+ @directory_node = directory_node
221
+ @file_set = directory_node.file_set
222
+ @should_be_used = true
223
+ end
224
+
225
+ end
226
+
227
+
228
+ class ObjCFileNode < SourceFileNode
229
+
230
+ attr_accessor :name_root
231
+ attr_accessor :header_file_path
232
+ attr_accessor :implementation_file_path
233
+
234
+ attr_accessor :processed_header_file
235
+ attr_accessor :processed_implementation_file
236
+ attr_accessor :recognized_code
237
+ attr_accessor :objc_2_swift_converter
238
+
239
+ def initialize(directory_node, name_root )
240
+ super( directory_node )
241
+ @name_root = name_root
242
+ end
243
+
244
+ def prepare_for_use
245
+ # puts( "prepare_for_use() header: #{@header_file_path}, implementation: #{@implementation_file_path}")
246
+ @recognized_code = []
247
+ @processed_header_file = ProcessedSourceFile.new( @header_file_path, :header, @file_set.configuration ) unless @header_file_path.nil? || @file_set.omit_file( relative_header_path )
248
+ @processed_implementation_file = ProcessedSourceFile.new( @implementation_file_path, :implementation, @file_set.configuration ) unless @implementation_file_path.nil? || @file_set.omit_file( relative_impl_path )
249
+ end
250
+
251
+ def recognize_code_fragments( recognizers )
252
+ @file_set.configuration.log_verbose( "Recognizing code fragments in #{@header_file_path}, #{@implementation_file_path}")
253
+ @processed_header_file.recognize_code_fragments( recognizers ) unless @processed_header_file.nil?
254
+ @processed_implementation_file.recognize_code_fragments( recognizers ) unless @processed_implementation_file.nil?
255
+ end
256
+
257
+ def prepare_conversion( configuration )
258
+ @objc_2_swift_converter = ObjC2SwiftFileConverter.new( self, configuration )
259
+ @objc_2_swift_converter.prepare
260
+ end
261
+
262
+ def root_matches
263
+ root_matches = []
264
+ root_matches.concat( @processed_header_file.root_matches ) unless @processed_header_file.nil?
265
+ root_matches.concat( @processed_implementation_file.root_matches ) unless @processed_implementation_file.nil?
266
+ return root_matches
267
+ end
268
+
269
+ def create_generated_file_nodes( generated_file_set, generated_directory )
270
+ swift_file_name = @name_root + '.swift'
271
+ generated_file_node = generated_directory.file_nodes_by_name[ swift_file_name ]
272
+
273
+ if generated_file_node.nil?
274
+ generated_file_node = GeneratedSwiftFileNode.new( generated_directory, swift_file_name )
275
+ generated_directory.file_nodes_by_name[ swift_file_name ] = generated_file_node
276
+ end
277
+
278
+ @objc_2_swift_converter.swift_file_node = generated_file_node
279
+ end
280
+
281
+ def dump( indent, tab, errors_only )
282
+ # puts( indent + "NameRoot: #{@name_root}")
283
+ puts( indent + "#{@name_root} :")
284
+
285
+ unless @processed_header_file.nil?
286
+ puts( indent+tab + "Header:")
287
+ @processed_header_file.dump( indent+tab+tab, tab, errors_only )
288
+ end
289
+
290
+ unless @processed_implementation_file.nil?
291
+ puts( indent+tab + "Implementation:")
292
+ @processed_implementation_file.dump( indent+tab+tab, tab, errors_only )
293
+ end
294
+
295
+ unless @objc_2_swift_converter.nil?
296
+ puts( indent+tab + "Swift File Generation:")
297
+ @objc_2_swift_converter.dump( indent+tab+tab, tab, errors_only )
298
+ end
299
+ end
300
+
301
+ def relative_header_path
302
+ if @header_file_path.nil?
303
+ return nil
304
+ else
305
+ return @directory_node.relative_path.join( @header_file_path.basename )
306
+ end
307
+
308
+ end
309
+
310
+ def relative_impl_path
311
+ if @implementation_file_path.nil?
312
+ return nil
313
+ else
314
+ return @directory_node.relative_path.join( @implementation_file_path.basename )
315
+ end
316
+ end
317
+
318
+ # Utility
319
+ def cannonical_source_file_path
320
+ source_path = relative_impl_path
321
+ source_path ||= relative_header_path
322
+ source_path
323
+ end
324
+ end
325
+
326
+
327
+ class ProcessedSourceFile
328
+ attr_accessor :file_path
329
+ attr_accessor :file_type
330
+ attr_accessor :root_matches
331
+ attr_accessor :inner_matches
332
+ attr_accessor :configuration
333
+
334
+ def initialize( file_path, file_type, configuration )
335
+ @file_path = file_path
336
+ @file_type = file_type
337
+ @configuration = configuration
338
+ @root_matches = []
339
+ @inner_matches = []
340
+ end
341
+
342
+ def recognize_code_fragments( recognizers )
343
+ file_lines = Objc2swiftAssistant::de_comment_lines( @file_path.readlines )
344
+
345
+ @configuration.log_verbose( "\nRecognizing code fragments in #{@file_path.to_s}" )
346
+
347
+ recognizers.each do |recognizer|
348
+ if recognizer.should_scan_file( @file_type )
349
+ matches = recognizer.matches( file_lines )
350
+ matches.each do |match|
351
+ unless match_already_found( match )
352
+ if match.is_root_entity
353
+ @root_matches << match
354
+ else
355
+ @inner_matches << match unless match_already_found( match )
356
+ end
357
+ end
358
+ end
359
+ end
360
+ end
361
+
362
+ # Sort both sets of matches by the starting line number
363
+ @root_matches.sort_by!{ |m| m.starting_line_number }
364
+ @inner_matches.sort_by!{ |m| m.starting_line_number }
365
+
366
+ # Delimit the root matches in the file
367
+ previous_match = nil
368
+ @root_matches.each do |match|
369
+ previous_match.ending_line_number = match.starting_line_number - 1 unless previous_match.nil?
370
+ previous_match = match
371
+ end
372
+
373
+ previous_match.ending_line_number = file_lines.count - 1 unless previous_match.nil?
374
+
375
+ # Associate the inner_matches with the root matches that they belong to
376
+ root_match_fiber = Fiber.new do
377
+ if @root_matches
378
+ @root_matches.each do |match|
379
+ Fiber.yield match
380
+ end
381
+ end
382
+ Fiber.yield nil
383
+ end
384
+
385
+ # puts( root_match_fiber.resume.region_type_name ) if root_match_fiber.alive?
386
+ # puts( root_match_fiber.resume.region_type_name ) if root_match_fiber.alive?
387
+ # puts( root_match_fiber.resume.region_type_name ) if root_match_fiber.alive?
388
+
389
+ # Add inner matches to the containing root match, if possible
390
+
391
+ if @root_matches.length > 0
392
+ current_root_match = nil
393
+ @inner_matches.each do |inner_match|
394
+ while( current_root_match.nil? || ! current_root_match.contains_line( inner_match.starting_line_number ) )
395
+
396
+ if root_match_fiber.alive?
397
+ current_root_match = root_match_fiber.resume
398
+ # puts(current_root_match)
399
+ if current_root_match.nil?
400
+ configuration.log_verbose( "Uncontained inner match: #{inner_match}")
401
+ end
402
+ else
403
+ configuration.log_verbose( "Uncontained inner match: #{inner_match}")
404
+ current_root_match = nil
405
+ break
406
+ end
407
+ end
408
+
409
+ current_root_match.add_sub_region( inner_match ) unless current_root_match.nil?
410
+ end
411
+ end
412
+
413
+ @root_matches.each do |root_match|
414
+ root_match.complete( file_lines )
415
+ configuration.log_verbose( " added match: #{root_match.description} in file: #{@file_path.to_s}")
416
+ end
417
+ end
418
+
419
+ def match_already_found( new_match )
420
+ return match_already_exists( new_match, @root_matches ) || match_already_exists( new_match, @inner_matches )
421
+ end
422
+
423
+ def match_already_exists( new_match, existing_matches )
424
+ existing_matches.each do | existing_match |
425
+ if new_match.starting_line_number == existing_match.starting_line_number
426
+ @configuration.log_verbose( "match : #{new_match.brief_description} found at existing match: #{existing_match.brief_description}")
427
+ return true
428
+ end
429
+ end
430
+ return false
431
+ end
432
+
433
+ def organize_matches
434
+ @raw_matches.each do |match|
435
+
436
+ end
437
+ end
438
+
439
+ def dump( indent, tab, errors_only )
440
+ puts( indent + "Path: #{@file_path.to_s}")
441
+ puts( indent + "Type: #{@file_type.to_s}")
442
+ puts( indent + 'Matches:')
443
+
444
+ @root_matches.each do |region|
445
+ region.dump( indent + tab, tab, errors_only )
446
+ end
447
+ end
448
+ end
449
+
450
+
451
+ class ObjCFileSet < ScannedFileSet
452
+ attr_accessor :code_recognizers
453
+ attr_accessor :header_file_extensions
454
+ attr_accessor :implmentation_file_extensions
455
+ attr_accessor :generated_swift_file_set
456
+
457
+ def initialize( root, code_recognizers, configuration:nil )
458
+ super( root, configuration )
459
+ @code_recognizers = code_recognizers
460
+ @header_file_extensions=[ '.h', '.hh' ]
461
+ @implmentation_file_extensions=[ '.m', '.mm' ]
462
+ end
463
+
464
+ #Factory Methods
465
+ def make_directory_node( path )
466
+ ObjCDirectoryNode.new( path, self )
467
+ end
468
+
469
+ def recognize_code_fragments()
470
+ @active_file_nodes.each do |file_node|
471
+ file_node.prepare_for_use
472
+ file_node.recognize_code_fragments( @code_recognizers )
473
+ end
474
+ end
475
+
476
+ def prepare_conversion()
477
+ # TODO: Error handling
478
+
479
+ # puts( "1: #{@configuration.config_value( "Test", "company_name")}" )
480
+ # puts( "2: #{@configuration.config_value( "SomePathTest", "company_name")}" )
481
+ # puts( "3: #{@configuration.config_value( ".", "company_name")}" )
482
+ # puts( "4: #{@configuration.config_value( "Runtime/Channel", "company_name")}" )
483
+
484
+ @active_file_nodes.each do |file_node|
485
+ file_node.prepare_conversion( @configuration )
486
+ end
487
+ end
488
+
489
+ def generate_swift_file_set(root, dry_run)
490
+ @generated_swift_file_set = GeneratedSwiftFileSet.new( root, @configuration )
491
+
492
+ # Map the original source files to the new generated source files
493
+ @directory_nodes_by_path.each_value do |node |
494
+ node.create_associated_generated_nodes( @generated_swift_file_set )
495
+ end
496
+
497
+ # Create the Swift code generator
498
+ generator_definitions = SwiftGenerator::SwiftDefinitionSet.new( generated_root:@generated_swift_file_set.root.to_s )
499
+ generator_definitions.make_unknown_types = true
500
+
501
+ @active_file_nodes.each do |file_node|
502
+ file_node.objc_2_swift_converter.generate( generator_definitions, @configuration, dry_run )
503
+ end
504
+
505
+ generator_definitions.run_generation_sequence()
506
+ SwiftGenerator::write_files_for_definition_set( generator_definitions )
507
+ end
508
+
509
+ def omit_file( path )
510
+ return @configuration.omit_file( path )
511
+ end
512
+ end
513
+
514
+ #
515
+ # Generated Swift File Sets
516
+ #
517
+
518
+ # Swift file sets simplify mapping to a new directory structure and the application on customization that
519
+ # will be associated with nodes in the original directory structure
520
+ class GeneratedSwiftFileSet < FileSet
521
+ def initialize( root, configuration )
522
+ super( root, configuration )
523
+ end
524
+ end
525
+
526
+
527
+ class GeneratedSwiftFileNode < SourceFileNode
528
+ attr_accessor :full_path
529
+ attr_accessor :relative_path
530
+
531
+ def initialize( directory_node, file_name )
532
+ super( directory_node )
533
+ @full_path = directory_node.full_path + file_name
534
+ @relative_path = directory_node.relative_path + file_name
535
+ end
536
+
537
+ end
538
+
539
+
540
+ # class SwiftDirectoryNode < DirectoryNode
541
+ #
542
+ # def initialize(objc_node, parent_node, file_set)
543
+ # #todo: Apply settings
544
+ #
545
+ # @parent_node = parent_node
546
+ # @relative_path = objc_node.relative_path
547
+ # @full_path = file_set.root + @relative_path
548
+ #
549
+ # @child_directories = {}
550
+ # @file_nodes = {}
551
+ #
552
+ # unless @parent_node.nil?
553
+ # @parent_node.add_child_directory( self )
554
+ # end
555
+ #
556
+ # @pruned = false
557
+ # end
558
+ #
559
+ # def generate_files()
560
+ # @full_path.mkpath
561
+ # @file_nodes.each { |node| node.generate_files }
562
+ # @child_directories.each { |node| node.generate_files }
563
+ # end
564
+ #
565
+ # end
566
+ # class SwiftFileSet < FileSet
567
+ #
568
+ # def initialize(root)
569
+ # super(root)
570
+ # end
571
+ #
572
+ # def make_directory_node( path )
573
+ # SwiftDirectoryNode.new( path, self )
574
+ # end
575
+ # end
576
+
577
+ end