changeset 3:d0162d8ca0f2

Added support for function pointers in dstepgen
author Jacob Carlborg <doob@me.com>
date Sun, 05 Jul 2009 20:54:42 +0200
parents 9fd439a28ce3
children 5a1a6afbfe3a
files dstep/Cocoa/NSAutoreleasePool.d dstep/Cocoa/NSObject.d dstep/Cocoa/NSString.d scripts/dgen.rb scripts/dstepgen.rb scripts/gen.rb
diffstat 6 files changed, 287 insertions(+), 121 deletions(-) [+]
line wrap: on
line diff
--- a/dstep/Cocoa/NSAutoreleasePool.d	Sun Jul 05 17:16:19 2009 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,31 +0,0 @@
-/**
- * Copyright: Copyright (c) 2009 Jacob Carlborg.
- * Authors: Jacob Carlborg
- * Version: Initial created: Apr 19, 2009
- * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
- */
-module dstep.Cocoa.NSAutoreleasePool;
-
-import dstep.Cocoa.NSObject;
-import dstep.objc.objc;
-import dstep.objc.runtime;
-/*
-class NSAutoreleasePool : NSObject
-{
-	this (id object)
-	{
-		super(object);
-	}
-	
-	static NSAutoreleasePool alloc ()
-	{
-		id r = objc.getClass!("NSAutoreleasePool").msgSend(sel.registerName!("alloc"));
-		return r ? new NSAutoreleasePool(r) : null;
-	}
-	
-	NSAutoreleasePool init ()
-	{
-		return invokeObjcCall!(NSAutoreleasePool, "init");
-	}
-	
-}*/
\ No newline at end of file
--- a/dstep/Cocoa/NSObject.d	Sun Jul 05 17:16:19 2009 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-/**
- * Copyright: Copyright (c) 2009 Jacob Carlborg.
- * Authors: Jacob Carlborg
- * Version: Initial created: Mar 28, 2009
- * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
- */
-module dstep.Cocoa.NSObject;
-
-import mambo.io;
-
-import dstep.objc.bridge.Bridge;
-import dstep.objc.bridge.Wrapper;
-
-
-
-class NSObject : ObjcWrapper
-{
-	mixin ObjcWrap;
-	
-	int i = 34;
-	
-	NSObject foo (NSObject o)
-	{
-		println("foo in NSObject");
-		o.add(1, 2);
-		println(this is o);
-	    
-		this.add(3, 4);
-	
-		return this;
-	}
-	
-	mixin ObjcBindMethod!(foo);
-	
-	int add (int x, int y)
-	{
-		println(x + y);
-		return x + y;
-	}
-	
-	mixin ObjcBindMethod!(add);
-}
\ No newline at end of file
--- a/dstep/Cocoa/NSString.d	Sun Jul 05 17:16:19 2009 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-/**
- * Copyright: Copyright (c) 2009 Jacob Carlborg.
- * Authors: Jacob Carlborg
- * Version: Initial created: Apr 19, 2009
- * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
- */
-module dstep.Cocoa.NSString;
-
-import tango.stdc.stringz;
-
-import dstep.Cocoa.NSObject;
-import dstep.objc.bridge.Bridge;
-import dstep.objc.bridge.Wrapper;
-import dstep.internal.String;
-import dstep.objc.objc;
-
-import mambo.io;
-
-class NSString : NSObject
-{
-	mixin ObjcWrap;
-	
-	string UTF8String ()
-	{
-		char* s = invokeObjcSelf!(char*, "UTF8String");
-		return fromStringz(s);
-	}
-	
-	int add (int x, int y)
-	{
-		println("NSString");
-		return 0;
-	}
-	
-	mixin ObjcBindMethod!(add);
-}
\ No newline at end of file
--- a/scripts/dgen.rb	Sun Jul 05 17:16:19 2009 +0200
+++ b/scripts/dgen.rb	Sun Jul 05 20:54:42 2009 +0200
@@ -154,7 +154,7 @@
 		self.class.instance_eval do
 			define_method(method) do |*args|
 				if args.length > 0
-					self[method[0 ... -1]] = args[0]
+					#self[method[0 ... -1]] = args[0]
 					self[eval(":#{method}"[0 ... -1])] = args[0]
 				else
 					result = self[method]
--- a/scripts/dstepgen.rb	Sun Jul 05 17:16:19 2009 +0200
+++ b/scripts/dstepgen.rb	Sun Jul 05 20:54:42 2009 +0200
@@ -73,7 +73,7 @@
 		self.class.instance_eval do
 			define_method(method) do |*args|
 				if args.length > 0
-					self[method[0 ... -1]] = args[0]
+					#self[method[0 ... -1]] = args[0]
 					self[eval(":#{method}"[0 ... -1])] = args[0]
 				else
 					result = self[method]
@@ -101,7 +101,7 @@
 end
 
 # This Struct represents a C/Objective-C header
-HeaderFile = Struct.new(:name, :framework, :cftypes, :constants, :defines, :enums, :externs, :functions,
+HeaderFile = Struct.new(:name, :framework, :cftypes, :constants, :defines, :enums, :externs, :functions, :function_pointers,
 			  			:imports, :inline_functions, :opaques, :path, :structs, :typedefs) do
 	def initialize
 		self.name = ""
@@ -112,6 +112,7 @@
 		self.externs = []
 		self.framework = ""
 		self.functions = []
+		self.function_pointers = {}
 		self.imports = []
 		self.inline_functions = []
 		self.opaques = []
@@ -146,7 +147,7 @@
 		@protocols = {}
 		@categories = {}
 		#@informal_protocols = {}
-		@function_pointer_types = {}
+		#@function_pointers = {}
 		@do_64bit = false
 	end
 	
@@ -206,7 +207,7 @@
 		end
 	end
 	
-	def function_pointer_types (header)
+	def function_pointers (header)
 		re = /typedef\s+([\w\s]+)\s*\(\s*\*\s*(\w+)\s*\)\s*\(([^)]*)\)\s*;/
 		data = @cpp_result.scan(re)
 		re = /typedef\s+([\w\s]+)\s*\(([^)]+)\)\s*;/
@@ -230,10 +231,37 @@
 			end
 			
 			type = "#{m[0]}(*)(#{args.join(', ')})"
-			@function_pointer_types[name] = type
+			header.function_pointers[name] = get_function_pointer(type)
 		end
 	end
 	
+	def get_function_pointer (fp)
+		type = {}
+		re = /(.+)\(\*\)\((.+)\)/
+
+		if fp =~ /(.+)\(\*\)\((.+)\)/
+			m1 = $1
+			m2 = $2
+
+			type.const = m1 =~ /const/ ? true : false	
+			m1.gsub!(/const/, "")
+			type.return_type = m1.strip
+			type.args = []
+
+			args = m2.split(",")		
+
+			args.each do |arg|
+				const = arg =~ /const/ ? true : false			
+				arg.gsub!(/const/, "")
+				arg.strip!
+				arg.gsub!(/\s*\*/, "*")				
+				type.args << {:type => arg, :const => const}
+			end
+		end
+
+		type
+	end
+	
 	def typedefs (header)
 		re = /^\s*typedef\s+(.+)\s+([\w\*]+)\s*;$/
 		data = @cpp_result
@@ -574,7 +602,7 @@
 				protocols(header)
 				#informal_protocols(header)
 				categories(header)
-				function_pointer_types(header)
+				function_pointers(header)
 			end
 		end
 		
@@ -595,7 +623,7 @@
 			protocols(header)
 			#informal_protocols(header)
 			categories(header)
-			function_pointer_types(header)
+			function_pointers(header)
 		end
 	end
 	
@@ -735,10 +763,10 @@
 			@stripped_return_type = t
 		end
 		
-		def function_pointer? (function_pointer_types)
-			type = @function_pointer_types[@stripped_return_type] || @stripped_return_type
-			@function_pointer_type ||= FunctionPointerInfo.new_from_type(type)
-		end
+		# def function_pointer? (function_pointers)
+		# 	type = @function_pointers[@stripped_return_type] || @stripped_return_type
+		# 	@function_pointer ||= FunctionPointerInfo.new_from_type(type)
+		# end
 		
 		def <=>(x)
 			self.name <=> x.name
@@ -1138,6 +1166,14 @@
 			end
 		end
 		
+		header.function_pointers.each do |fp, value|
+			types << value.return_type
+			
+			value.args.each do |arg|
+				types << arg.type
+			end
+		end
+		
 		types
 	end
 	
@@ -1247,6 +1283,18 @@
 			end
 		end
 		
+		header.function_pointers.each do |fp, value|
+			value.resolved_type = resolved_types[i] unless enable_64bit
+			value.resolved_type64 = resolved_types[i] if enable_64bit
+			i += 1
+			
+			value.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
+		
 		i
 	end
 	
@@ -1449,6 +1497,16 @@
 					xml.returnValue :declaredType => function.return_type, :type => function.resolved_type, :type64 => function.resolved_type64, :const => function.const, :typeModifier => function.type_modifier
 				end
 			end
+			
+			header.function_pointers.each do |fp, value|
+				xml.functionPointer :name => fp do
+					value.args.each do |arg|
+						xml.arg :declaredType => arg.type, :type => arg.resolved_type, :type64 => arg.resolved_type64, :const => arg.const
+					end
+					
+					xml.returnValue :declaredType => value.return_type, :type => value.resolved_type, :type64 => value.resolved_type64, :const => value.const
+				end
+			end
 		end
 	end
 	
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/gen.rb	Sun Jul 05 20:54:42 2009 +0200
@@ -0,0 +1,217 @@
+#!/usr/bin/env ruby
+
+##
+# Copyright:: Copyright (c) 2009 Jacob Carlborg.
+# Author:: Jacob Carlborg
+# Version:: Initial created: 2009
+# License:: [Boost Software License 1.0]http://www.boost.org/LICENSE_1_0.txt
+#
+
+require "rubygems"
+gem "xml-simple"
+require "xmlsimple"
+require "optparse"
+require "date"
+
+# Extensions to String
+class String
+	
+	# Returns the index of the given character or length of the string if not found
+	# char:: the character to look for
+	# start:: the index where to start the search
+	# 
+	# === Example:
+	# "012345789".index_of("1")		#=> 1
+	# "0123 0123".index_of("3", 6)	#=> 8
+	# 
+	def index_of (char, start = 0)
+		return self.length if start >= self.length
+		
+		i = 0
+		
+		if start == 0
+			self.each_char do |c|
+				return i if char == c
+				i += 1			
+			end
+		else
+			self[start + 1 .. -1].each_char do |c|
+				return i + start + 1 if char == c
+				i += 1			
+			end
+		end
+		
+		return self.length
+	end
+end
+
+class Generator
+	VERSION = 1.0
+	
+	attr_accessor :dependencies_switch, :out_dir, :private
+	
+	def initialize
+		@frameworks = []
+		@do_64bit = false
+		@dependencies_switch = false
+		@dependencies = {}
+		@private = false
+	end
+	
+	def framework_path (val)
+		return val if File.exist?(val)
+		
+		val += ".framework" unless /\.framework$/.match(val)
+		paths = ["/System/Library/Frameworks", "/Library/Frameworks", "#{ENV['HOME']}/Library/Frameworks"]
+		paths << "/System/Library/PrivateFrameworks" if @private
+		
+		paths.each do |dir|
+			path = File.join(dir, val)
+			return path if File.exist?(path)
+		end
+		
+		return nil
+	end
+	
+ 	def add_framework (framework)
+ 		@frameworks << framework_path(framework)
+ 	end
+	 
+	def collect_dependencies (framework)
+		result = `./dstepgen.rb -f #{framework} -d`
+		@dependencies[framework] = {}
+		
+		result.each_line do |path|
+			path = path[0 .. -2] # remove the newline
+			@dependencies[framework][path] = true
+			collect_dependencies(path) unless @dependencies.key?(path)
+		end
+	end
+	
+	def write_dependencies
+		@frameworks.each do |framework|
+			collect_dependencies(framework) 
+		end		
+		
+		file = STDOUT
+		
+		@dependencies.each do |key, value|
+			file << "#{key}\n"
+		end
+		
+		exit
+	end
+	
+	def generate
+		dstep_file = "Frameworks.dstep"
+		
+		@frameworks.each do |framework|
+			collect_dependencies(framework)
+		end
+		
+		str = StringIO.new
+		
+		frameworks = []
+		
+		@dependencies.each do |framework, value|
+			frameworks << get_umbrella_framework(framework)
+		end
+		
+		frameworks.uniq!
+		
+		frameworks.each do |framework|
+			str << " -f "
+			str << framework
+		end
+		
+		`./dstepgen.rb -o #{@out_dir}/#{dstep_file} #{str.string}`
+		`./dgen.rb -o #{@out_dir} #{@out_dir}/#{dstep_file}`
+	end
+	
+	def get_framework_name (framework)
+		i = framework.rindex(".framework")
+		return framework if i.nil?
+		x = framework.rindex("/", i)
+		framework[x + 1 ... i]
+	end
+	
+	def get_umbrella_framework (framework)
+		str = ".framework"
+		i = framework.index(str)
+		return framework[0 ... i + str.length] unless i.nil?
+		framework
+	end
+end
+
+if __FILE__ == $0
+	gen = Generator.new
+	
+	OptionParser.new do |opts|
+		opts.banner = "Usage: #{File.basename(__FILE__)} [options] <frameworks...>"
+		opts.separator ""
+		opts.separator "Options:"
+		
+		opts.on("-u", "--umbrella FRAMEWORK", "Link againts the given umbrella framework.") do |opt|
+			gen.umbrella_framework(opt)
+		end
+		
+		opts.on(nil, "--64-bit", "Write 64-bit annotations.") do
+			gen.do_64bit = true
+		end
+		
+		opts.on("-p", "--private", "Include private frameworks.") do |opt|
+			gen.private = true
+		end
+		
+		opts.on("-o", "--output DIRECTORY", "Place the output file(s) in this directory.") do |opt|
+			die "The specified directory \"#{opt}\" does not exists" if File.exist?(opt) == false
+			die "Output directory cannot be specified more than once" if gen.out_dir
+			gen.out_dir = opt
+		end
+		
+		opts.on("-c", "--code CODE", "Inject CODE in the type file.") do |opt|
+			gen.code_to_inject = opt
+		end
+		
+		opts.on("-d", "--dependencies", "Write dependencies to stdout and exit.") do |opt|
+			gen.dependencies_switch = true
+		end
+		
+		help_msg = "Use the `-h' flag or for help."	
+			
+		opts.on("-h", "--help", "Show this message and exit.") do
+			puts opts, help_msg
+			exit
+		end
+		
+		opts.on('-v', '--version', 'Show version and exit.') do
+			puts Generator::VERSION
+			exit
+		end
+		
+		opts.separator ""
+		
+		if ARGV.empty?			
+			die opts.banner
+		else
+			#begin
+				opts.parse!(ARGV)
+				
+				ARGV.each do |framework|
+					gen.add_framework(framework)
+				end
+				
+				gen.write_dependencies if gen.dependencies_switch
+				
+				die "No output directory given" if gen.out_dir.nil?
+				
+				gen.generate
+			# rescue => e
+			# 	msg = e.message
+			# 	msg = "Internal error" if msg.empty?
+			# 	
+			# 	die msg, opts.banner, help_msg
+			# end
+		end
+	end
+end
\ No newline at end of file