summaryrefslogtreecommitdiff
path: root/ext/fiddle
diff options
context:
space:
mode:
authorhsbt <hsbt@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2015-01-03 00:54:37 +0000
committerhsbt <hsbt@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2015-01-03 00:54:37 +0000
commit3afd0f9a914e4a7c733523ee657e238861dd8b38 (patch)
treebc52bbfab87ceeda97a5a967bf00d147a43aeeec /ext/fiddle
parent4690241f012af796315013189ee5b98a3cf88f05 (diff)
* ext/fiddle/lib/fiddle/cparser.rb: Support for Fiddle::CParser
to handle rich signatures including parameter names and function pointer types. Patch by @theryan [fix GH-590] * test/fiddle/test_cparser.rb: ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@49110 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'ext/fiddle')
-rw-r--r--ext/fiddle/lib/fiddle/cparser.rb156
1 files changed, 86 insertions, 70 deletions
diff --git a/ext/fiddle/lib/fiddle/cparser.rb b/ext/fiddle/lib/fiddle/cparser.rb
index 43fb184..18c9908 100644
--- a/ext/fiddle/lib/fiddle/cparser.rb
+++ b/ext/fiddle/lib/fiddle/cparser.rb
@@ -7,8 +7,14 @@ module Fiddle
# include Fiddle::CParser
# #=> Object
#
- # parse_ctype('int increment(int)')
- # #=> ["increment", Fiddle::TYPE_INT, [Fiddle::TYPE_INT]]
+ # parse_ctype('int')
+ # #=> Fiddle::TYPE_INT
+ #
+ # parse_struct_signature(['int i', 'char c'])
+ # #=> [[Fiddle::TYPE_INT, Fiddle::TYPE_CHAR], ["i", "c"]]
+ #
+ # parse_signature('double sum(double, double)')
+ # #=> ["sum", Fiddle::TYPE_DOUBLE, [Fiddle::TYPE_DOUBLE, Fiddle::TYPE_DOUBLE]]
#
module CParser
# Parses a C struct's members
@@ -21,37 +27,33 @@ module Fiddle
# parse_struct_signature(['int i', 'char c'])
# #=> [[Fiddle::TYPE_INT, Fiddle::TYPE_CHAR], ["i", "c"]]
#
+ # parse_struct_signature(['char buffer[80]'])
+ # #=> [[[Fiddle::TYPE_CHAR, 80]], ["buffer"]]
+ #
def parse_struct_signature(signature, tymap=nil)
- if( signature.is_a?(String) )
- signature = signature.split(/\s*,\s*/)
+ if signature.is_a?(String)
+ signature = split_arguments(signature, /[,;]/)
end
mems = []
tys = []
signature.each{|msig|
- tks = msig.split(/\s+(\*)?/)
- ty = tks[0..-2].join(" ")
- member = tks[-1]
-
- case ty
- when /\[(\d+)\]/
- n = $1.to_i
- ty.gsub!(/\s*\[\d+\]/,"")
- ty = [ty, n]
- when /\[\]/
- ty.gsub!(/\s*\[\]/, "*")
- end
-
- case member
- when /\[(\d+)\]/
- ty = [ty, $1.to_i]
- member.gsub!(/\s*\[\d+\]/,"")
- when /\[\]/
- ty = ty + "*"
- member.gsub!(/\s*\[\]/, "")
+ msig = compact(msig)
+ case msig
+ when /^[\w\*\s]+[\*\s](\w+)$/
+ mems.push($1)
+ tys.push(parse_ctype(msig, tymap))
+ when /^[\w\*\s]+\(\*(\w+)\)\(.*?\)$/
+ mems.push($1)
+ tys.push(parse_ctype(msig, tymap))
+ when /^([\w\*\s]+[\*\s])(\w+)\[(\d+)\]$/
+ mems.push($2)
+ tys.push([parse_ctype($1.strip, tymap), $3.to_i])
+ when /^([\w\*\s]+)\[(\d+)\](\w+)$/
+ mems.push($3)
+ tys.push([parse_ctype($1.strip, tymap), $2.to_i])
+ else
+ raise(RuntimeError,"can't parse the struct member: #{msig}")
end
-
- mems.push(member)
- tys.push(parse_ctype(ty,tymap))
}
return tys, mems
end
@@ -70,22 +72,21 @@ module Fiddle
# parse_signature('double sum(double, double)')
# #=> ["sum", Fiddle::TYPE_DOUBLE, [Fiddle::TYPE_DOUBLE, Fiddle::TYPE_DOUBLE]]
#
+ # parse_signature('void update(void (*cb)(int code))')
+ # #=> ["update", Fiddle::TYPE_VOID, [Fiddle::TYPE_VOIDP]]
+ #
+ # parse_signature('char (*getbuffer(void))[80]')
+ # #=> ["getbuffer", Fiddle::TYPE_VOIDP, []]
+ #
def parse_signature(signature, tymap=nil)
tymap ||= {}
- signature = signature.gsub(/\s+/, " ").strip
- case signature
- when /^([\w@\*\s]+)\(([\w\*\s\,\[\]]*)\)$/
- ret = $1
- (args = $2).strip!
- ret = ret.split(/\s+/)
- args = args.split(/\s*,\s*/)
- func = ret.pop
- if( func =~ /^\*/ )
- func.gsub!(/^\*+/,"")
- ret.push("*")
- end
- ret = ret.join(" ")
- return [func, parse_ctype(ret, tymap), args.collect{|arg| parse_ctype(arg, tymap)}]
+ case compact(signature)
+ when /^(?:[\w\*\s]+)\(\*(\w+)\((.*?)\)\)(?:\[\w*\]|\(.*?\));?$/
+ func, args = $1, $2
+ return [func, TYPE_VOIDP, split_arguments(args).collect {|arg| parse_ctype(arg, tymap)}]
+ when /^([\w\*\s]+[\*\s])(\w+)\((.*?)\);?$/
+ ret, func, args = $1.strip, $2, $3
+ return [func, parse_ctype(ret, tymap), split_arguments(args).collect {|arg| parse_ctype(arg, tymap)}]
else
raise(RuntimeError,"can't parse the function prototype: #{signature}")
end
@@ -107,62 +108,65 @@ module Fiddle
# parse_ctype('int')
# #=> Fiddle::TYPE_INT
#
- # parse_ctype('double')
+ # parse_ctype('double diff')
# #=> Fiddle::TYPE_DOUBLE
#
- # parse_ctype('unsigned char')
+ # parse_ctype('unsigned char byte')
# #=> -Fiddle::TYPE_CHAR
#
+ # parse_ctype('const char* const argv[]')
+ # #=> -Fiddle::TYPE_VOIDP
+ #
def parse_ctype(ty, tymap=nil)
tymap ||= {}
case ty
when Array
return [parse_ctype(ty[0], tymap), ty[1]]
- when "void"
+ when 'void'
return TYPE_VOID
- when "char"
- return TYPE_CHAR
- when "unsigned char"
- return -TYPE_CHAR
- when "short"
- return TYPE_SHORT
- when "unsigned short"
- return -TYPE_SHORT
- when "int"
- return TYPE_INT
- when "unsigned int", 'uint'
- return -TYPE_INT
- when "long"
- return TYPE_LONG
- when "unsigned long"
- return -TYPE_LONG
- when "long long"
+ when /^(?:(?:signed\s+)?long\s+long(?:\s+int\s+)?|int64_t)(?:\s+\w+)?$/
if( defined?(TYPE_LONG_LONG) )
return TYPE_LONG_LONG
else
raise(RuntimeError, "unsupported type: #{ty}")
end
- when "unsigned long long"
+ when /^(?:unsigned\s+long\s+long(?:\s+int\s+)?|uint64_t)(?:\s+\w+)?$/
if( defined?(TYPE_LONG_LONG) )
return -TYPE_LONG_LONG
else
raise(RuntimeError, "unsupported type: #{ty}")
end
- when "float"
+ when /^(?:signed\s+)?long(?:\s+int\s+)?(?:\s+\w+)?$/
+ return TYPE_LONG
+ when /^unsigned\s+long(?:\s+int\s+)?(?:\s+\w+)?$/
+ return -TYPE_LONG
+ when /^(?:signed\s+)?int(?:\s+\w+)?$/
+ return TYPE_INT
+ when /^(?:unsigned\s+int|uint)(?:\s+\w+)?$/
+ return -TYPE_INT
+ when /^(?:signed\s+)?short(?:\s+int\s+)?(?:\s+\w+)?$/
+ return TYPE_SHORT
+ when /^unsigned\s+short(?:\s+int\s+)?(?:\s+\w+)?$/
+ return -TYPE_SHORT
+ when /^(?:signed\s+)?char(?:\s+\w+)?$/
+ return TYPE_CHAR
+ when /^unsigned\s+char(?:\s+\w+)?$/
+ return -TYPE_CHAR
+ when /^float(?:\s+\w+)?$/
return TYPE_FLOAT
- when "double"
+ when /^double(?:\s+\w+)?$/
return TYPE_DOUBLE
- when "size_t"
+ when /^size_t(?:\s+\w+)?$/
return TYPE_SIZE_T
- when "ssize_t"
+ when /^ssize_t(?:\s+\w+)?$/
return TYPE_SSIZE_T
- when "ptrdiff_t"
+ when /^ptrdiff_t(?:\s+\w+)?$/
return TYPE_PTRDIFF_T
- when "intptr_t"
+ when /^intptr_t(?:\s+\w+)?$/
return TYPE_INTPTR_T
- when "uintptr_t"
+ when /^uintptr_t(?:\s+\w+)?$/
return TYPE_UINTPTR_T
- when /\*/, /\[\s*\]/
+ when /\*/, /\[[\s\d]*\]/
return TYPE_VOIDP
else
if( tymap[ty] )
@@ -172,5 +176,17 @@ module Fiddle
end
end
end
+
+ private
+
+ def split_arguments(arguments, sep=',')
+ return [] if arguments.strip == 'void'
+ arguments.scan(/([\w\*\s]+\(\*\w*\)\(.*?\)|[\w\*\s\[\]]+)(?:#{sep}\s*|$)/).collect {|m| m[0]}
+ end
+
+ def compact(signature)
+ signature.gsub(/\s+/, ' ').gsub(/\s*([\(\)\[\]\*,;])\s*/, '\1').strip
+ end
+
end
end