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.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.idea/.name +1 -0
- data/.idea/.rakeTasks +7 -0
- data/.idea/compiler.xml +22 -0
- data/.idea/copyright/profiles_settings.xml +3 -0
- data/.idea/dictionaries/ckornher.xml +7 -0
- data/.idea/encodings.xml +4 -0
- data/.idea/misc.xml +4 -0
- data/.idea/modules.xml +8 -0
- data/.idea/objc2swift_assistant.iml +103 -0
- data/.idea/runConfigurations/Console.xml +26 -0
- data/.idea/runConfigurations/assistant.xml +28 -0
- data/.idea/runConfigurations/help_text.xml +28 -0
- data/.idea/scopes/scope_settings.xml +5 -0
- data/.idea/uiDesigner.xml +124 -0
- data/.idea/vcs.xml +6 -0
- data/.idea/workspace.xml +1484 -0
- data/.rspec +2 -0
- data/.travis.yml +3 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +8 -0
- data/LICENSE.txt +21 -0
- data/README.md +83 -0
- data/Rakefile +1 -0
- data/bin/console +14 -0
- data/bin/objc2swift_assistant +50 -0
- data/bin/setup +7 -0
- data/lib/assistant.rb +110 -0
- data/lib/objc2swift_assistant/code_recognizer.rb +220 -0
- data/lib/objc2swift_assistant/file_hierarchical_config.rb +168 -0
- data/lib/objc2swift_assistant/file_sets.rb +577 -0
- data/lib/objc2swift_assistant/logging.rb +19 -0
- data/lib/objc2swift_assistant/objc_2_swift.rb +734 -0
- data/lib/objc2swift_assistant/objc_2_swift_block_conversion.rb +106 -0
- data/lib/objc2swift_assistant/objc_2_swift_configuration.rb +108 -0
- data/lib/objc2swift_assistant/objc_2_swift_type_mapping.rb +64 -0
- data/lib/objc2swift_assistant/objc_variable_types.rb +76 -0
- data/lib/objc2swift_assistant/processing_element.rb +32 -0
- data/lib/objc2swift_assistant/recognizers/at_sign_directives_recognizer.rb +41 -0
- data/lib/objc2swift_assistant/recognizers/category_recognizer.rb +72 -0
- data/lib/objc2swift_assistant/recognizers/enum_recognizer.rb +0 -0
- data/lib/objc2swift_assistant/recognizers/implementation_recognizer.rb +31 -0
- data/lib/objc2swift_assistant/recognizers/interface_recognizer.rb +37 -0
- data/lib/objc2swift_assistant/recognizers/method_recognizer.rb +190 -0
- data/lib/objc2swift_assistant/recognizers/pragma_mark_recognizer.rb +41 -0
- data/lib/objc2swift_assistant/recognizers/property_declaration_recognizer.rb +78 -0
- data/lib/objc2swift_assistant/recognizers/protocol_recognizer.rb +40 -0
- data/lib/objc2swift_assistant/recognizers/recognizer_keys.rb +26 -0
- data/lib/objc2swift_assistant/settings_file.rb +23 -0
- data/lib/objc2swift_assistant/swift_file_generator.rb +27 -0
- data/lib/objc2swift_assistant/version.rb +3 -0
- data/objc2swift_assistant.gemspec +31 -0
- 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
|