diff scripts/dstepgen.rb @ 2:9fd439a28ce3

Adapted the scripts for the new bridge + a lot more
author Jacob Carlborg <doob@me.com>
date Sun, 05 Jul 2009 17:16:19 +0200
parents 033d260cfc9b
children d0162d8ca0f2
line wrap: on
line diff
--- a/scripts/dstepgen.rb	Thu Jun 18 22:00:13 2009 +0200
+++ b/scripts/dstepgen.rb	Sun Jul 05 17:16:19 2009 +0200
@@ -121,6 +121,13 @@
 	end	
 end
 
+Category = Struct.new(:name, :class) do
+	def initialize
+		self.name = ""
+		self.class = ""
+	end
+end
+
 # This class scans the headers
 class HeaderScaner
 	CPP = ['/usr/bin/cpp-4.0', '/usr/bin/cpp-3.3', '/usr/bin/cpp3'].find { |x| File.exist?(x) }
@@ -136,19 +143,29 @@
 		@file_content = nil
 		@headers = []
 		@classes = {}
-		@informal_protocols = {}
+		@protocols = {}
+		@categories = {}
+		#@informal_protocols = {}
 		@function_pointer_types = {}
 		@do_64bit = false
 	end
 	
-	def classes
+	def get_classes
 		@classes
 	end
 	
-	def protocols
-		@informal_protocols
+	def get_protocols
+		@protocols
 	end
 	
+	def get_categories
+		@categories
+	end		
+	
+	# def get_informal_protocols
+	# 	@informal_protocols
+	# end
+	
 	def cftypes (header)
 		re = /typedef\s+(const\s+)?(struct\s*\w+\s*\*\s*)([^\s]+Ref)\s*;/
 		@cpp_result.scan(re).each do |m|
@@ -262,12 +279,24 @@
 		header.imports = tmp.compact.uniq
 	end
 	
-	def informal_protocols (header)
-		self.methods(header)
+	# def informal_protocols (header)
+	# 	methods(header, /^@(interface)\s+(\w+)\s*:?\s*(\w*)\s*(\([^)]+\))?/, @protocols, false)
+	# end
+	
+	def classes (header)
+		methods(header, /^@(interface)\s+(\w+)\s*:?\s*(\w*)\s*(\<([\w,\s]+)>)?$/, @classes, false)
 	end	
 	
-	def methods (header)
-		interface_re = /^@(interface|protocol)\s+(\w+)\s*:?\s*(\w*)\s*(\([^)]+\))?/
+	def protocols (header)
+		methods(header, /^@(protocol)\s+(\w+)\s*:?\s*(\w*)\s*(\<([\w,\s]+)>)?(\([^)]+\))?/, @protocols, true)
+	end	
+
+	def categories (header)
+		methods(header, /^@(interface)\s+(\w+)\s*:?\s*(\w*)\s*(\<([\w,\s]+)>)?(\([^)]+\))/, @categories, false, true)
+	end	
+	
+	def methods (header, regex, array, protocol, category = false)
+		interface_re = regex
 		
 		end_re = /^@end/
 		body_re = /^[-+]\s*(\([^)]+\))?\s*([^:\s;]+)/
@@ -275,17 +304,28 @@
 		prop_re = /^@property\s*(\([^)]+\))?\s*([^;]+);$/
 		current_interface = current_category = nil
 		i = 0
-		parent = nil	
+		parent = nil
+		protocols = nil
+		cat = nil	
 		
-		@cpp_result.each_line do |line|
+		@cpp_result.each_line do |line|			
 			size = line.size
 			line.strip!
 			
 			if md = interface_re.match(line)
 				parent = nil
-				current_interface = md[1] == "protocol" ? "NSObject" : md[2]
-				current_category = md[4].delete("()").strip if md[4]
+				protocols = nil
+				current_category = md[6].delete("()").strip if md[6]
+				current_interface = md[2] unless category
+				current_interface = current_category if category	
 				parent = md[3] unless md[3] == ""
+				protocols = md[5] if md[5]
+				
+				if category
+					cat = Category.new if category
+					cat.name = current_category
+					cat.class = md[2]
+				end
 				
 			elsif end_re.match(line)
 				current_interface = current_category = nil
@@ -310,8 +350,10 @@
 					
 					typeinfo = VarInfo.new(type, "", "")
 					
-					@classes[current_interface] ||= {}					
-					methods = (@classes[current_interface].methods ||= [])
+					array[current_interface] ||= {} unless category
+					array[cat] ||= {} if category
+					methods = (array[current_interface].methods ||= []) unless category
+					methods = (array[cat].methods ||= []) if category
 					methods << MethodInfo.new(typeinfo, getter, false, [], line)
 					
 					unless readonly
@@ -377,23 +419,34 @@
 				args << VarInfo.new("...", "vararg", "") if variadic
 				method = MethodInfo.new(retval, selector, line[0] == ?+, args, data)
 				
-				if current_category && current_interface == "NSObject"
-					(@informal_protocols[current_category] ||= []) << method
-				end
+				# if protocol && current_category && current_interface == "NSObject"
+				# 	(@informal_protocols[current_category] ||= []) << method
+				# end
 				
-				@classes[current_interface] ||= {}
+				array[current_interface] ||= {} unless category
+				array[cat] ||= {} if category
 				
 				if header.name == current_interface				
-					@classes[current_interface].file = header.name
+					array[current_interface].file = header.name unless category
+					array[cat].file = header.name if category
 				else
-					@classes[current_interface].file ||= header.name
+					array[current_interface].file ||= header.name unless category
+					array[cat].file ||= header.name if category
 				end
 				
 				unless parent == current_interface || parent =~ /\s+/ || parent.nil?
-					@classes[current_interface].parent = parent
-				end				
+					array[current_interface].parent = parent unless category
+					array[cat].parent = parent if category
+				end
 				
-				(@classes[current_interface].methods ||= []) << method
+				unless protocols.nil?					
+					protocols.gsub!(/ /, "")										
+					array[current_interface].protocols = protocols unless category
+					array[cat].protocols = protocols if category
+				end
+				
+				(array[current_interface].methods ||= []) << method unless category
+				(array[cat].methods ||= []) << method if category
 			end
 			i += size
 		end
@@ -493,7 +546,7 @@
 		end
 	end
 	
-	def prepare (path)		
+	def prepare (path)
 		@file_content = File.read(path)
 		@file_content.gsub!(%r{(/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+/)|(//.*)}, "");
 		@complete_cpp_result, @cpp_result = do_cpp(path, false, true, "")
@@ -517,7 +570,10 @@
 				functions(header)
 				functions(header, true)
 				defines(header)
-				methods(header)
+				classes(header)
+				protocols(header)
+				#informal_protocols(header)
+				categories(header)
 				function_pointer_types(header)
 			end
 		end
@@ -535,7 +591,10 @@
 			functions(header)
 			functions(header, true)
 			defines(header)
-			methods(header)
+			classes(header)
+			protocols(header)
+			#informal_protocols(header)
+			categories(header)
 			function_pointer_types(header)
 		end
 	end
@@ -815,7 +874,7 @@
 	
 	VERSION = 1.0
 	
-	attr_accessor :out_file, :scaner, :code_to_inject
+	attr_accessor :out_file, :scaner, :code_to_inject, :dependencies_switch
 	
 	def initialize
 		@do_64bit = false
@@ -823,12 +882,15 @@
 		@framework_paths = []
 		@headers = []
 		@import_directives = "#import <Foundation/Foundation.h>\n"
-		@informal_protocols = []
+		#@informal_protocols = []
 		@classes = []
+		@protocols = []
+		@categories = []
 		@scaner = HeaderScaner.new
 		@scaner.do_64bit = @do_64bit
 		@umbrella_framework = nil
 		@handled_dependencies = []
+		@dependencies_switch = false
 		
 		# link to foundation framework by default
 		@compiler_flags = "-framework Foundation"
@@ -841,12 +903,14 @@
 	def do_64bit= (do_64bit)
 		@do_64bit = do_64bit
 		@scaner.do_64bit = do_64bit
-	end	
+	end
 	
 	def collect		
 		scaner.scan(@frameworks, @headers)
-		@classes = scaner.classes
-		@informal_protocols = scaner.protocols
+		@classes = scaner.get_classes
+		@protocols = scaner.get_protocols
+		@categories = scaner.get_categories
+		#@informal_protocols = scaner.get_informal_protocols
 	end
 	
 	def handle_framework (framework, sub_framework = false, parent_framework = nil)
@@ -981,7 +1045,7 @@
 	
 	def compile_and_execute (code, enable_64bit = false, clean_when_fail = false)
 		compiler_line = "gcc "				
-		src = File.new(unique_tmp_path("src", ".m", "/Users/doob/development/eclipse_workspace/dstep/bindings"), "w")
+		src = File.new(unique_tmp_path("src", ".m"), "w")
 		src << code
 		src.close
 		
@@ -993,8 +1057,8 @@
 		
 		compiler_line << arch_flag
 		
-		bin = unique_tmp_path "bin", "", "/Users/doob/development/eclipse_workspace/dstep/bindings"
-		log = unique_tmp_path "log", ".txt", "/Users/doob/development/eclipse_workspace/dstep/bindings"
+		bin = unique_tmp_path "bin", ""
+		log = unique_tmp_path "log", ".txt"
 		
 		line = "#{compiler_line} -o #{bin} #{src.path} #{@compiler_flags} 2>#{log}"
 		
@@ -1093,11 +1157,43 @@
 		types
 	end
 	
-	def collect_informal_protocols_types (enable_64bit)
+	def collect_protocols_types (enable_64bit)
 		types = []
 		
-		@informal_protocols.each do |name, methods|
-			methods.each do |method|				
+		@protocols.each do |protocol, value|
+			value.methods.each do |method|				
+				types << method.stripped_return_type
+				
+				method.args.each do |arg|					
+					types << arg.stripped_return_type
+				end
+			end
+		end
+		
+		types
+	end
+	
+	# def collect_informal_protocols_types (enable_64bit)
+	# 	types = []
+	# 	
+	# 	@informal_protocols.each do |name, methods|
+	# 		methods.each do |method|				
+	# 			types << method.stripped_return_type
+	# 			
+	# 			method.args.each do |arg|					
+	# 				types << arg.stripped_return_type
+	# 			end
+	# 		end
+	# 	end
+	# 	
+	# 	types
+	# end
+	
+	def collect_categories_types (enable_64bit)
+		types = []
+		
+		@categories.each do |category, value|
+			value.methods.each do |method|				
 				types << method.stripped_return_type
 				
 				method.args.each do |arg|					
@@ -1154,7 +1250,7 @@
 		i
 	end
 	
-	def resolve_methods_types (enable_64bit, resolved_types, x)
+	def resolve_classes_types (enable_64bit, resolved_types, x)
 		i = x
 		
 		@classes.each do |clazz, value|
@@ -1174,11 +1270,51 @@
 		i
 	end
 	
-	def resolve_informal_protocols_types (enable_64bit, resolved_types, x)
+	def resolve_protocols_types (enable_64bit, resolved_types, x)
 		i = x
 		
-		@informal_protocols.each do |name, methods|
-			methods.each do |method|
+		@protocols.each do |protocol, value|
+			value.methods.each do |method|
+				method.resolved_type = resolved_types[i] unless enable_64bit
+				method.resolved_type64 = resolved_types[i] if enable_64bit
+				i += 1
+				
+				method.args.each do |arg|
+					arg.resolved_type = resolved_types[i] unless enable_64bit
+					arg.resolved_type64 = resolved_types[i] if enable_64bit
+					i += 1
+				end
+			end
+		end
+		
+		i
+	end
+	
+	# def resolve_informal_protocols_types (enable_64bit, resolved_types, x)
+	# 	i = x
+	# 	
+	# 	@informal_protocols.each do |name, methods|
+	# 		methods.each do |method|
+	# 			method.resolved_type = resolved_types[i] unless enable_64bit
+	# 			method.resolved_type64 = resolved_types[i] if enable_64bit
+	# 			i += 1
+	# 			
+	# 			method.args.each do |arg|
+	# 				arg.resolved_type = resolved_types[i] unless enable_64bit
+	# 				arg.resolved_type64 = resolved_types[i] if enable_64bit
+	# 				i += 1
+	# 			end
+	# 		end
+	# 	end
+	# 	
+	# 	i
+	# end
+	
+	def resolve_categories_types (enable_64bit, resolved_types, x)
+		i = x
+		
+		@categories.each do |category, value|
+			value.methods.each do |method|
 				method.resolved_type = resolved_types[i] unless enable_64bit
 				method.resolved_type64 = resolved_types[i] if enable_64bit
 				i += 1
@@ -1211,7 +1347,7 @@
 		code << @import_directives
 		types = []
 		
-		code << @code_to_inject + ";\n" unless @code_to_inject.nil?
+		code << @code_to_inject + "\n" unless @code_to_inject.nil?
 		
 		@frameworks.each do |framework|
 			framework.headers.each do |header|
@@ -1229,7 +1365,9 @@
 		end
 		
 		types << collect_classes_types(enable_64bit)
-		types << collect_informal_protocols_types(enable_64bit)
+		types << collect_protocols_types(enable_64bit)
+		#types << collect_informal_protocols_types(enable_64bit)
+		types << collect_categories_types(enable_64bit)
 		
 		code << "int main ()\n{\n"
 		types.flatten!
@@ -1257,9 +1395,11 @@
 		@headers.each do |header|
 			i = resolve_header_types(header, enable_64bit, resolved_types, i)
 		end
-		
-		i = resolve_methods_types(enable_64bit, resolved_types, i)
-		i = resolve_informal_protocols_types(enable_64bit, resolved_types, i)
+				
+		i = resolve_classes_types(enable_64bit, resolved_types, i)
+		i = resolve_protocols_types(enable_64bit, resolved_types, i)
+		#i = resolve_informal_protocols_types(enable_64bit, resolved_types, i)
+		i = resolve_categories_types(enable_64bit, resolved_types, i)
 	end
 	
 	def generate_header (xml, header)
@@ -1314,7 +1454,7 @@
 	
 	def generate_classes (xml)
 		@classes.each do |clazz, value|
-			xml.class :name => clazz, :parent => value.parent, :file => value.file do
+			xml.class :name => clazz, :parent => value.parent, :protocols => value.protocols, :file => value.file do
 				value.methods.each do |method|
 					xml.method :selector => method.selector, :classMethod => method.class_method?, :variadic => method.variadic? do
 						method.args.each do |arg|
@@ -1328,10 +1468,42 @@
 		end
 	end
 	
-	def generate_informal_protocols (xml)
-		@informal_protocols.each do |name, methods|
-			xml.informalProtocol :name => name do
-				methods.each do |method|
+	def generate_protocols (xml)
+		@protocols.each do |protocol, value|
+			xml.protocol :name => protocol, :parent => value.parent, :protocols => value.protocols, :file => value.file do
+				value.methods.each do |method|
+					xml.method :selector => method.selector, :classMethod => method.class_method?, :variadic => method.variadic? do
+						method.args.each do |arg|
+							xml.arg :name => arg.name, :declaredType => arg.return_type, :type => arg.resolved_type, :type64 => arg.resolved_type64, :const => arg.const, :typeModifier => arg.type_modifier
+						end
+						
+						xml.returnValue :declaredType => method.return_type, :type => method.resolved_type, :type64 => method.resolved_type64, :const => method.const, :typeModifier => method.type_modifier
+					end
+				end
+			end
+		end
+	end
+	
+	# def generate_informal_protocols (xml)
+	# 	@informal_protocols.each do |name, methods|
+	# 		xml.informalProtocol :name => name do
+	# 			methods.each do |method|
+	# 				xml.method :selector => method.selector, :classMethod => method.class_method?, :variadic => method.variadic? do
+	# 					method.args.each do |arg|
+	# 						xml.arg :name => arg.name, :declaredType => arg.return_type, :type => arg.resolved_type, :type64 => arg.resolved_type64, :const => arg.const, :typeModifier => arg.type_modifier
+	# 					end
+	# 					
+	# 					xml.returnValue :declaredType => method.return_type, :type => method.resolved_type, :type64 => method.resolved_type64, :const => method.const, :typeModifier => method.type_modifier
+	# 				end
+	# 			end
+	# 		end
+	# 	end
+	# end
+	
+	def generate_categories (xml)
+		@categories.each do |category, value|			
+			xml.category :name => category.name, :class => category.class, :parent => value.parent, :protocols => value.protocols, :file => value.file do
+				value.methods.each do |method|
 					xml.method :selector => method.selector, :classMethod => method.class_method?, :variadic => method.variadic? do
 						method.args.each do |arg|
 							xml.arg :name => arg.name, :declaredType => arg.return_type, :type => arg.resolved_type, :type64 => arg.resolved_type64, :const => arg.const, :typeModifier => arg.type_modifier
@@ -1368,10 +1540,25 @@
 			end
 			
 			generate_classes(xml)
-			generate_informal_protocols(xml)
+			generate_protocols(xml)
+			#generate_informal_protocols(xml)
+			generate_categories(xml)
 		end
 		
 		file.close unless file == STDOUT
+	end
+	
+	def write_dependencies
+		file = STDOUT if @out_file == nil
+		file = File.open @out_file, "w" unless @out_file == nil
+		
+		@dependencies.each do |dep|
+			file << dep + "\n"
+		end
+		
+		file.close unless file == STDOUT
+		
+		exit 0
 	end	
 end
 
@@ -1410,10 +1597,14 @@
 		# 	dstep_gen.out_dir = opt
 		# end
 		
-		opts.on("-C", "--code CODE", "Add code") do |opt|
+		opts.on("-c", "--code CODE", "Add code") do |opt|
 			dstep_gen.code_to_inject = opt
 		end
 		
+		opts.on("-d", "--dependencies", "Write framework dependencies and exit") do |opt|
+			dstep_gen.dependencies_switch = true
+		end
+		
 		help_msg = "Use the `-h' flag or for help."	
 			
 		opts.on("-h", "--help", "Show this message.") do
@@ -1434,6 +1625,8 @@
 			#begin
 				opts.parse!(ARGV)
 				
+				dstep_gen.write_dependencies if dstep_gen.dependencies_switch
+				
 				ARGV.each do |header|
 					dstep_gen.add_header(header)
 				end
@@ -1448,4 +1641,4 @@
 			# end
 		end
 	end
-end
+end
\ No newline at end of file