From 153b8b90002a1781445a1cfd84d12cbdf62b291d Mon Sep 17 00:00:00 2001 From: mkarlesky Date: Fri, 15 May 2009 00:57:26 +0000 Subject: [PATCH] added support: 'struct' qualifiers for pointers in argument lists, const function pointers, added more type tests git-svn-id: http://cmock.svn.sourceforge.net/svnroot/cmock/trunk@97 bf332499-1b4d-0410-844d-d2d48d5cc64c --- config/production_environment.rb | 3 +- config/test_environment.rb | 3 +- lib/cmock_function_prototype_node_classes.rb | 36 +- lib/cmock_function_prototype_parser.rb | 460 +++++++++++------- lib/cmock_function_prototype_parser.treetop | 15 +- rakefile_helper.rb | 5 +- .../cmock_function_prototype_parser_test.rb | 53 +- 7 files changed, 380 insertions(+), 195 deletions(-) diff --git a/config/production_environment.rb b/config/production_environment.rb index 6f29057..71be056 100644 --- a/config/production_environment.rb +++ b/config/production_environment.rb @@ -1,4 +1,3 @@ -ROOT_PATH = File.expand_path(File.dirname(__FILE__) + "/../") # Setup our load path: [ @@ -6,7 +5,7 @@ ROOT_PATH = File.expand_path(File.dirname(__FILE__) + "/../") 'vendor/gems/polyglot-0.2.5/lib/', 'vendor/gems/treetop-1.2.5/lib/', ].each do |dir| - $LOAD_PATH.unshift(File.join(ROOT_PATH, dir)) + $LOAD_PATH.unshift( File.join( File.expand_path(File.dirname(__FILE__) + "/../"), dir) ) end require 'rubygems' diff --git a/config/test_environment.rb b/config/test_environment.rb index 220f685..3dacad8 100644 --- a/config/test_environment.rb +++ b/config/test_environment.rb @@ -1,4 +1,3 @@ -ROOT_PATH = File.expand_path(File.dirname(__FILE__) + "/../") # Setup our load path: [ @@ -10,5 +9,5 @@ ROOT_PATH = File.expand_path(File.dirname(__FILE__) + "/../") 'vendor/gems/treetop-1.2.5/lib/', 'test/system/' ].each do |dir| - $LOAD_PATH.unshift(File.join(ROOT_PATH, dir)) + $LOAD_PATH.unshift( File.join( File.expand_path(File.dirname(__FILE__) + "/../"), dir) ) end diff --git a/lib/cmock_function_prototype_node_classes.rb b/lib/cmock_function_prototype_node_classes.rb index efe8144..5724871 100644 --- a/lib/cmock_function_prototype_node_classes.rb +++ b/lib/cmock_function_prototype_node_classes.rb @@ -47,10 +47,12 @@ module CMockFunctionPrototype class FunctionPrototypeFunctionPointerReturnNode < Treetop::Runtime::SyntaxNode def get_declaration + return "#{return_type.text_value} (* const #{get_function_name}#{function_arglist.normalized_argument_list})#{function_return_arglist.normalized_argument_list}" if not (const.text_value.blank?) return "#{return_type.text_value} (*#{get_function_name}#{function_arglist.normalized_argument_list})#{function_return_arglist.normalized_argument_list}" end def get_return_type + return "#{return_type.text_value} (* const)#{function_return_arglist.normalized_argument_list}" if not (const.text_value.blank?) return "#{return_type.text_value} (*)#{function_return_arglist.normalized_argument_list}" end @@ -72,10 +74,18 @@ module CMockFunctionPrototype def get_typedefs type_name = "FUNC_PTR_#{get_function_name.upcase}_RETURN_T" + + if (const.text_value.blank?) + return [ + { :type => get_return_type, + :typename => type_name, + :typedef => "typedef #{return_type.text_value} (*#{type_name})#{function_return_arglist.normalized_argument_list};" }] + end + return [ { :type => get_return_type, :typename => type_name, - :typedef => "typedef #{return_type.text_value} (*#{type_name})#{function_return_arglist.normalized_argument_list};" }] + :typedef => "typedef #{return_type.text_value} (* const #{type_name})#{function_return_arglist.normalized_argument_list};" }] end end @@ -168,6 +178,7 @@ module CMockFunctionPrototype include FunctionPrototypeUtils def text_value + return "#{return_type.text_value} (* const #{name.text_value})#{argument_list.normalized_argument_list}" if not (const.text_value.blank?) return "#{return_type.text_value} (*#{name.text_value})#{argument_list.normalized_argument_list}" end @@ -178,11 +189,18 @@ module CMockFunctionPrototype func_ptr_name = make_cmock_arg_name(arg_list_index) end + return "#{return_type.text_value} (* const #{func_ptr_name})#{argument_list.normalized_argument_list}" if not (const.text_value.blank?) return "#{return_type.text_value} (*#{func_ptr_name})#{argument_list.normalized_argument_list}" end def type_and_name_token_hash(arg_list_index, function_name) - type = "#{return_type.text_value} (*)#{argument_list.normalized_argument_list}" + type = '' + + if (const.text_value.blank?) + type = "#{return_type.text_value} (*)#{argument_list.normalized_argument_list}" + else + type = "#{return_type.text_value} (* const)#{argument_list.normalized_argument_list}" + end return { :type => type, :name => make_cmock_arg_name(arg_list_index) } if (name.text_value.blank?) return { :type => type, :name => name.text_value } @@ -190,10 +208,18 @@ module CMockFunctionPrototype def typedef_hash(arg_list_index, function_name) typename = "FUNC_PTR_#{function_name.upcase}_PARAM_#{arg_list_index+1}_T" - type = "#{return_type.text_value} (*)#{argument_list.normalized_argument_list}" - typedef = "typedef #{return_type.text_value} (*#{typename})#{argument_list.normalized_argument_list};" - return { :type => type, :typename => typename, :typedef => typedef } + if (const.text_value.blank?) + type = "#{return_type.text_value} (*)#{argument_list.normalized_argument_list}" + typedef = "typedef #{return_type.text_value} (*#{typename})#{argument_list.normalized_argument_list};" + + return { :type => type, :typename => typename, :typedef => typedef } + end + + type = "#{return_type.text_value} (* const)#{argument_list.normalized_argument_list}" + typedef = "typedef #{return_type.text_value} (* const #{typename})#{argument_list.normalized_argument_list};" + + return { :type => type, :typename => typename, :typedef => typedef } end end diff --git a/lib/cmock_function_prototype_parser.rb b/lib/cmock_function_prototype_parser.rb index e2b2947..b92c92e 100644 --- a/lib/cmock_function_prototype_parser.rb +++ b/lib/cmock_function_prototype_parser.rb @@ -91,21 +91,25 @@ module CMockFunctionPrototype elements[2] end - def name + def const elements[3] end - def function_arglist + def name elements[4] end - def right_paren + def function_arglist elements[5] end - def function_return_arglist + def right_paren elements[6] end + + def function_return_arglist + elements[7] + end end def _nt_function_prototype_function_pointer_return @@ -126,17 +130,26 @@ module CMockFunctionPrototype r3 = _nt_asterisk s0 << r3 if r3 - r4 = _nt_name + r5 = _nt_const + if r5 + r4 = r5 + else + r4 = instantiate_node(SyntaxNode,input, index...index) + end s0 << r4 if r4 - r5 = _nt_argument_list - s0 << r5 - if r5 - r6 = _nt_right_paren - s0 << r6 - if r6 - r7 = _nt_argument_list - s0 << r7 + r6 = _nt_name + s0 << r6 + if r6 + r7 = _nt_argument_list + s0 << r7 + if r7 + r8 = _nt_right_paren + s0 << r8 + if r8 + r9 = _nt_argument_list + s0 << r9 + end end end end @@ -353,17 +366,21 @@ module CMockFunctionPrototype elements[2] end - def name + def const elements[3] end - def right_paren + def name elements[4] end - def argument_list + def right_paren elements[5] end + + def argument_list + elements[6] + end end def _nt_func_ptr_prototype @@ -384,7 +401,7 @@ module CMockFunctionPrototype r3 = _nt_asterisk s0 << r3 if r3 - r5 = _nt_name + r5 = _nt_const if r5 r4 = r5 else @@ -392,11 +409,20 @@ module CMockFunctionPrototype end s0 << r4 if r4 - r6 = _nt_right_paren + r7 = _nt_name + if r7 + r6 = r7 + else + r6 = instantiate_node(SyntaxNode,input, index...index) + end s0 << r6 if r6 - r7 = _nt_argument_list - s0 << r7 + r8 = _nt_right_paren + s0 << r8 + if r8 + r9 = _nt_argument_list + s0 << r9 + end end end end @@ -491,9 +517,30 @@ module CMockFunctionPrototype def space elements[1] end + + def name + elements[2] + end + end module Type1 + def space + elements[1] + end + end + + module Type2 + end + + module Type3 + def name + elements[0] + end + + end + + module Type4 end def _nt_type @@ -514,173 +561,250 @@ module CMockFunctionPrototype s0 << r1 if r1 i3 = index - s4, i4 = [], index - loop do - i5, s5 = index, [] - i6 = index - if input.index('void', index) == index - r7 = instantiate_node(SyntaxNode,input, index...(index + 4)) - @index += 4 - else - terminal_parse_failure('void') - r7 = nil - end - if r7 - r6 = r7 - else - if input.index('unsigned', index) == index - r8 = instantiate_node(SyntaxNode,input, index...(index + 8)) - @index += 8 - else - terminal_parse_failure('unsigned') - r8 = nil - end - if r8 - r6 = r8 - else - if input.index('signed', index) == index - r9 = instantiate_node(SyntaxNode,input, index...(index + 6)) - @index += 6 - else - terminal_parse_failure('signed') - r9 = nil - end - if r9 - r6 = r9 - else - if input.index('long', index) == index - r10 = instantiate_node(SyntaxNode,input, index...(index + 4)) - @index += 4 - else - terminal_parse_failure('long') - r10 = nil - end - if r10 - r6 = r10 - else - if input.index('int', index) == index - r11 = instantiate_node(SyntaxNode,input, index...(index + 3)) - @index += 3 - else - terminal_parse_failure('int') - r11 = nil - end - if r11 - r6 = r11 - else - if input.index('short', index) == index - r12 = instantiate_node(SyntaxNode,input, index...(index + 5)) - @index += 5 - else - terminal_parse_failure('short') - r12 = nil - end - if r12 - r6 = r12 - else - if input.index('char', index) == index - r13 = instantiate_node(SyntaxNode,input, index...(index + 4)) - @index += 4 - else - terminal_parse_failure('char') - r13 = nil - end - if r13 - r6 = r13 - else - if input.index('float', index) == index - r14 = instantiate_node(SyntaxNode,input, index...(index + 5)) - @index += 5 - else - terminal_parse_failure('float') - r14 = nil - end - if r14 - r6 = r14 - else - if input.index('double', index) == index - r15 = instantiate_node(SyntaxNode,input, index...(index + 6)) - @index += 6 - else - terminal_parse_failure('double') - r15 = nil - end - if r15 - r6 = r15 - else - self.index = i6 - r6 = nil - end - end - end - end - end - end - end - end - end - s5 << r6 + i4, s4 = index, [] + if input.index('struct', index) == index + r5 = instantiate_node(SyntaxNode,input, index...(index + 6)) + @index += 6 + else + terminal_parse_failure('struct') + r5 = nil + end + s4 << r5 + if r5 + r6 = _nt_space + s4 << r6 if r6 - r16 = _nt_space - s5 << r16 - end - if s5.last - r5 = instantiate_node(SyntaxNode,input, i5...index, s5) - r5.extend(Type0) - else - self.index = i5 - r5 = nil - end - if r5 - s4 << r5 - else - break + r7 = _nt_name + s4 << r7 + if r7 + s8, i8 = [], index + loop do + r9 = _nt_asterisk + if r9 + s8 << r9 + else + break + end + end + if s8.empty? + self.index = i8 + r8 = nil + else + r8 = instantiate_node(SyntaxNode,input, i8...index, s8) + end + s4 << r8 + end end end - if s4.empty? + if s4.last + r4 = instantiate_node(SyntaxNode,input, i4...index, s4) + r4.extend(Type0) + else self.index = i4 r4 = nil - else - r4 = instantiate_node(SyntaxNode,input, i4...index, s4) end if r4 r3 = r4 else - r17 = _nt_name - if r17 - r3 = r17 - else - self.index = i3 - r3 = nil - end - end - s0 << r3 - if r3 - s18, i18 = [], index + i10, s10 = index, [] + s11, i11 = [], index loop do - r19 = _nt_asterisk - if r19 - s18 << r19 + i12, s12 = index, [] + i13 = index + if input.index('void', index) == index + r14 = instantiate_node(SyntaxNode,input, index...(index + 4)) + @index += 4 + else + terminal_parse_failure('void') + r14 = nil + end + if r14 + r13 = r14 + else + if input.index('unsigned', index) == index + r15 = instantiate_node(SyntaxNode,input, index...(index + 8)) + @index += 8 + else + terminal_parse_failure('unsigned') + r15 = nil + end + if r15 + r13 = r15 + else + if input.index('signed', index) == index + r16 = instantiate_node(SyntaxNode,input, index...(index + 6)) + @index += 6 + else + terminal_parse_failure('signed') + r16 = nil + end + if r16 + r13 = r16 + else + if input.index('long', index) == index + r17 = instantiate_node(SyntaxNode,input, index...(index + 4)) + @index += 4 + else + terminal_parse_failure('long') + r17 = nil + end + if r17 + r13 = r17 + else + if input.index('int', index) == index + r18 = instantiate_node(SyntaxNode,input, index...(index + 3)) + @index += 3 + else + terminal_parse_failure('int') + r18 = nil + end + if r18 + r13 = r18 + else + if input.index('short', index) == index + r19 = instantiate_node(SyntaxNode,input, index...(index + 5)) + @index += 5 + else + terminal_parse_failure('short') + r19 = nil + end + if r19 + r13 = r19 + else + if input.index('char', index) == index + r20 = instantiate_node(SyntaxNode,input, index...(index + 4)) + @index += 4 + else + terminal_parse_failure('char') + r20 = nil + end + if r20 + r13 = r20 + else + if input.index('float', index) == index + r21 = instantiate_node(SyntaxNode,input, index...(index + 5)) + @index += 5 + else + terminal_parse_failure('float') + r21 = nil + end + if r21 + r13 = r21 + else + if input.index('double', index) == index + r22 = instantiate_node(SyntaxNode,input, index...(index + 6)) + @index += 6 + else + terminal_parse_failure('double') + r22 = nil + end + if r22 + r13 = r22 + else + self.index = i13 + r13 = nil + end + end + end + end + end + end + end + end + end + s12 << r13 + if r13 + r23 = _nt_space + s12 << r23 + end + if s12.last + r12 = instantiate_node(SyntaxNode,input, i12...index, s12) + r12.extend(Type1) + else + self.index = i12 + r12 = nil + end + if r12 + s11 << r12 else break end end - r18 = instantiate_node(SyntaxNode,input, i18...index, s18) - s0 << r18 - if r18 - r21 = _nt_const - if r21 - r20 = r21 - else - r20 = instantiate_node(SyntaxNode,input, index...index) - end - s0 << r20 + if s11.empty? + self.index = i11 + r11 = nil + else + r11 = instantiate_node(SyntaxNode,input, i11...index, s11) end + s10 << r11 + if r11 + s24, i24 = [], index + loop do + r25 = _nt_asterisk + if r25 + s24 << r25 + else + break + end + end + r24 = instantiate_node(SyntaxNode,input, i24...index, s24) + s10 << r24 + end + if s10.last + r10 = instantiate_node(SyntaxNode,input, i10...index, s10) + r10.extend(Type2) + else + self.index = i10 + r10 = nil + end + if r10 + r3 = r10 + else + i26, s26 = index, [] + r27 = _nt_name + s26 << r27 + if r27 + s28, i28 = [], index + loop do + r29 = _nt_asterisk + if r29 + s28 << r29 + else + break + end + end + r28 = instantiate_node(SyntaxNode,input, i28...index, s28) + s26 << r28 + end + if s26.last + r26 = instantiate_node(SyntaxNode,input, i26...index, s26) + r26.extend(Type3) + else + self.index = i26 + r26 = nil + end + if r26 + r3 = r26 + else + self.index = i3 + r3 = nil + end + end + end + s0 << r3 + if r3 + r31 = _nt_const + if r31 + r30 = r31 + else + r30 = instantiate_node(SyntaxNode,input, index...index) + end + s0 << r30 end end if s0.last r0 = instantiate_node(TypeNode,input, i0...index, s0) - r0.extend(Type1) + r0.extend(Type4) else self.index = i0 r0 = nil diff --git a/lib/cmock_function_prototype_parser.treetop b/lib/cmock_function_prototype_parser.treetop index e5c03d3..ffcf8b5 100644 --- a/lib/cmock_function_prototype_parser.treetop +++ b/lib/cmock_function_prototype_parser.treetop @@ -10,10 +10,12 @@ grammar CMockFunctionPrototype rule function_prototype_function_pointer_return # ex. float (*GetPtr(const char opCode))(float, float) - return_type left_paren asterisk name function_arglist:argument_list right_paren function_return_arglist:argument_list + # const: tag so we can always access its nodes in programming even if blank. + return_type left_paren asterisk const:const? name function_arglist:argument_list right_paren function_return_arglist:argument_list end rule return_type + # void is different than the type possibility 'void*' void / type end @@ -35,8 +37,8 @@ grammar CMockFunctionPrototype rule func_ptr_prototype # ex. int (*funcPtr)(float, char, char) - # add name: tag to name? so we can always access it in programming even if blank. - return_type left_paren asterisk name:name? right_paren argument_list + # const: & name: tags so we can always access their nodes in programming even if blank. + return_type left_paren asterisk const:const? name:name? right_paren argument_list end rule type_and_name @@ -47,7 +49,12 @@ grammar CMockFunctionPrototype end rule type - const? ((('void' / 'unsigned' / 'signed' / 'long' / 'int' / 'short' / 'char' / 'float' / 'double') space)+ / name) (asterisk)* const? + # be careful in here with parens; placement and grouping is important + const? + (('struct' space name asterisk+) / + ((('void' / 'unsigned' / 'signed' / 'long' / 'int' / 'short' / 'char' / 'float' / 'double') space)+ asterisk*) / + (name asterisk*)) + const? end rule name diff --git a/rakefile_helper.rb b/rakefile_helper.rb index f8af082..c474b1f 100644 --- a/rakefile_helper.rb +++ b/rakefile_helper.rb @@ -1,6 +1,5 @@ require 'yaml' require 'fileutils' -require 'cmock' require 'generate_test_runner' require 'unity_test_summary' require 'systest_generator' @@ -164,7 +163,9 @@ module RakefileHelpers summary.run end - def run_systests(test_case_files) + def run_systests(test_case_files) + require 'cmock' + SystemTestGenerator.new.generate_files(test_case_files) test_files = FileList.new(SYSTEST_GENERATED_FILES_PATH + 'test*.c') diff --git a/test/unit/cmock_function_prototype_parser_test.rb b/test/unit/cmock_function_prototype_parser_test.rb index 20ac930..ce01214 100644 --- a/test/unit/cmock_function_prototype_parser_test.rb +++ b/test/unit/cmock_function_prototype_parser_test.rb @@ -78,7 +78,7 @@ class CMockFunctionPrototypeParserTest < Test::Unit::TestCase end - should "parse out simple arguments from an argument list into an array of hashes" do + should "parse out arguments from an argument list into an array of hashes" do # function pointers & var args tested elsewhere # void is a special argument that yields no params to mock @@ -101,7 +101,23 @@ class CMockFunctionPrototypeParserTest < Test::Unit::TestCase {:type => 'unsigned int', :name => 'b'}], parsed.get_arguments) assert_nil(parsed.get_var_arg) + + parsed = @parser.parse("void foo_bar(double a, float b, unsigned short c)") + assert_equal('double a, float b, unsigned short c', parsed.get_argument_list) + assert_equal([ + {:type => 'double', :name => 'a'}, + {:type => 'float', :name => 'b'}, + {:type => 'unsigned short', :name => 'c'}], + parsed.get_arguments) + assert_nil(parsed.get_var_arg) + parsed = @parser.parse("void foo_bar(struct THINGER * a)") + assert_equal('struct THINGER* a', parsed.get_argument_list) + assert_equal([ + {:type => 'struct THINGER*', :name => 'a'}], + parsed.get_arguments) + assert_nil(parsed.get_var_arg) + parsed = @parser.parse("void foo_bar(unsigned char * abc, const unsigned long int xyz_123)") assert_equal('unsigned char* abc, const unsigned long int xyz_123', parsed.get_argument_list) assert_equal([ @@ -194,43 +210,56 @@ class CMockFunctionPrototypeParserTest < Test::Unit::TestCase # handle this? --> "int slinkydog(bool thing, int (* const)(void));\n" + parsed = @parser.parse("void thing(int (*func_ptr)(int, int))") + assert_equal('void thing( int (*func_ptr)( int, int ) )', parsed.get_declaration) assert_equal('int (*func_ptr)( int, int )', parsed.get_argument_list) assert_equal( [{:type => 'int (*)( int, int )', :name => 'func_ptr'}], parsed.get_arguments) + parsed = @parser.parse("void foo(int (* const func_ptr)(int, int))") + assert_equal('void foo( int (* const func_ptr)( int, int ) )', parsed.get_declaration) + assert_equal('int (* const func_ptr)( int, int )', parsed.get_argument_list) + assert_equal( + [{:type => 'int (* const)( int, int )', :name => 'func_ptr'}], + parsed.get_arguments) + parsed = @parser.parse("void foo_bar(void * (*func)(int *, unsigned long int, ...))") + assert_equal('void foo_bar( void* (*func)( int*, unsigned long int, ... ) )', parsed.get_declaration) assert_equal('void* (*func)( int*, unsigned long int, ... )', parsed.get_argument_list) assert_equal( [{:type => 'void* (*)( int*, unsigned long int, ... )', :name => 'func'}], parsed.get_arguments) - parsed = @parser.parse("void foo_bar(int (* func1)(int a, char b), void (*func2)(void))") - assert_equal('int (*func1)( int a, char b ), void (*func2)(void)', parsed.get_argument_list) + parsed = @parser.parse("void foo_bar(int (* func1)(int, char), void (*func2)(void))") + assert_equal('void foo_bar( int (*func1)( int, char ), void (*func2)(void) )', parsed.get_declaration) + assert_equal('int (*func1)( int, char ), void (*func2)(void)', parsed.get_argument_list) assert_equal( - [{:type => 'int (*)( int a, char b )', :name => 'func1'}, + [{:type => 'int (*)( int, char )', :name => 'func1'}, {:type => 'void (*)(void)', :name => 'func2'}], parsed.get_arguments) # directly returning function pointers (i.e. no typedef) parsed = @parser.parse("float (*func(const char opCode))(float, float)") + assert_equal('float (*func( const char opCode ))( float, float )', parsed.get_declaration) assert_equal('float (*)( float, float )', parsed.get_return_type) - parsed = @parser.parse("void (*func (void))(void)") - assert_equal('void (*)(void)', parsed.get_return_type) + parsed = @parser.parse("void (* const func (void))(void)") + assert_equal('void (* const func(void))(void)', parsed.get_declaration) + assert_equal('void (* const)(void)', parsed.get_return_type) parsed = @parser.parse("unsigned int * (* func(double foo, THING bar))(unsigned int a)") + assert_equal('unsigned int* (*func( double foo, THING bar ))( unsigned int a )', parsed.get_declaration) assert_equal('unsigned int* (*)( unsigned int a )', parsed.get_return_type) end should "create unique typedefs for function pointer prototypes in argument lists and return types" do # function prototype argument list handling - parsed = @parser.parse("void foo_bar(unsigned int a, void (*func)(int *, unsigned long int, ...))") + parsed = @parser.parse("void foo_bar(unsigned int a, void (* const func)(int *, unsigned long int, ...))") assert_equal( - [{:type => 'void (*)( int*, unsigned long int, ... )', + [{:type => 'void (* const)( int*, unsigned long int, ... )', :typename => 'FUNC_PTR_FOO_BAR_PARAM_2_T', - :typedef => 'typedef void (*FUNC_PTR_FOO_BAR_PARAM_2_T)( int*, unsigned long int, ... );'}], + :typedef => 'typedef void (* const FUNC_PTR_FOO_BAR_PARAM_2_T)( int*, unsigned long int, ... );'}], parsed.get_typedefs) parsed = @parser.parse("void test_func(void (*)(int, char), unsigned int (*)(void))") @@ -244,11 +273,11 @@ class CMockFunctionPrototypeParserTest < Test::Unit::TestCase parsed.get_typedefs) # function prototype return type handling - parsed = @parser.parse("void (*func (void))(void)") + parsed = @parser.parse("void (* const func (void))(void)") assert_equal( - [{:type => 'void (*)(void)', + [{:type => 'void (* const)(void)', :typename => 'FUNC_PTR_FUNC_RETURN_T', - :typedef => 'typedef void (*FUNC_PTR_FUNC_RETURN_T)(void);'}], + :typedef => 'typedef void (* const FUNC_PTR_FUNC_RETURN_T)(void);'}], parsed.get_typedefs) parsed = @parser.parse("unsigned int * (* func(double foo, THING bar))(unsigned int, ...)")