added handling for array index operators in argument lists

git-svn-id: http://cmock.svn.sourceforge.net/svnroot/cmock/trunk@105 bf332499-1b4d-0410-844d-d2d48d5cc64c
This commit is contained in:
mkarlesky
2009-05-25 23:28:46 +00:00
parent 9d608d61d3
commit 268ba11d49
7 changed files with 369 additions and 13 deletions
+53 -4
View File
@@ -2,6 +2,7 @@
module CMockFunctionPrototype
module FunctionPrototypeUtils
# handles '*' and '[]' (they're both pointers after all)
def normalize_ptr(ptr_string)
ptr_string.gsub!(/\s+\*/, '*')
ptr_string.gsub!(/\*(\w)/, '* \1')
@@ -210,7 +211,7 @@ module CMockFunctionPrototype
end
def typedef(arg_list_index, function_name)
typename= make_function_pointer_param_typedef_name(arg_list_index, function_name)
typename = make_function_pointer_param_typedef_name(arg_list_index, function_name)
# don't place 'const' in typedef no matter if it exists or not;
# data types that comprise mock queues can't be const
@@ -229,6 +230,9 @@ module CMockFunctionPrototype
def type_and_smart_name_string(arg_list_index)
if (name.text_value.blank?)
if (type.brackets?)
return "#{type.replace_brackets} #{make_cmock_arg_name(arg_list_index)}#{type.get_brackets}"
end
return "#{type.text_value} #{make_cmock_arg_name(arg_list_index)}"
end
@@ -237,10 +241,36 @@ module CMockFunctionPrototype
def type_and_smart_name_token_hash(arg_list_index)
if (name.text_value.blank?)
return { :type => type.text_value, :name => make_cmock_arg_name(arg_list_index)}
if (type.brackets?)
return { :type => type.replace_brackets('*'), :name => make_cmock_arg_name(arg_list_index) }
end
return { :type => type.text_value, :name => make_cmock_arg_name(arg_list_index) }
end
return { :type => type.text_value, :name => name.text_value}
if (name.brackets?)
return { :type => "#{type.text_value}*", :name => name.replace_brackets }
end
return { :type => type.text_value, :name => name.text_value }
end
end
class NameWithBracketsNode < Treetop::Runtime::SyntaxNode
def text_value
return super.gsub(/\s+/, '')
end
def brackets?
return !brackets.text_value.blank?
end
def get_brackets
return brackets.text_value
end
def replace_brackets(replace='')
return text_value.gsub(/(\s*\[\s*[0-9]*\])+/, replace)
end
end
@@ -258,9 +288,28 @@ module CMockFunctionPrototype
def text_value
return normalize_ptr(super.gsub(/\s+/, ' ')).strip
end
def brackets?
return !brackets.text_value.blank?
end
def get_brackets
return brackets.text_value
end
def replace_brackets(replace='')
return text_value.gsub(/(\s*\[\s*[0-9]*\])+/, replace)
end
end
class ArrayBracketsNode < Treetop::Runtime::SyntaxNode
def text_value
return super.gsub(/\s+/, '')
end
end
class VoidNode < Treetop::Runtime::SyntaxNode
def text_value
return super.strip
+258 -1
View File
@@ -451,7 +451,7 @@ module CMockFunctionPrototype
r1 = _nt_type
s0 << r1
if r1
r3 = _nt_name
r3 = _nt_name_with_brackets
if r3
r2 = r3
else
@@ -501,6 +501,9 @@ module CMockFunctionPrototype
end
module Type0
def brackets
elements[2]
end
end
def _nt_type
@@ -554,6 +557,15 @@ module CMockFunctionPrototype
end
end
s0 << r3
if r3
r11 = _nt_array_brackets
if r11
r10 = r11
else
r10 = instantiate_node(SyntaxNode,input, index...index)
end
s0 << r10
end
end
if s0.last
r0 = instantiate_node(TypeNode,input, i0...index, s0)
@@ -1247,6 +1259,49 @@ module CMockFunctionPrototype
return r0
end
module NameWithBrackets0
def name
elements[0]
end
def brackets
elements[1]
end
end
def _nt_name_with_brackets
start_index = index
if node_cache[:name_with_brackets].has_key?(index)
cached = node_cache[:name_with_brackets][index]
@index = cached.interval.end if cached
return cached
end
i0, s0 = index, []
r1 = _nt_name
s0 << r1
if r1
r3 = _nt_array_brackets
if r3
r2 = r3
else
r2 = instantiate_node(SyntaxNode,input, index...index)
end
s0 << r2
end
if s0.last
r0 = instantiate_node(NameWithBracketsNode,input, i0...index, s0)
r0.extend(NameWithBrackets0)
else
self.index = i0
r0 = nil
end
node_cache[:name_with_brackets][start_index] = r0
return r0
end
module Void0
def space
elements[1]
@@ -1299,6 +1354,89 @@ module CMockFunctionPrototype
return r0
end
module ArrayBrackets0
def left_bracket
elements[0]
end
def number
elements[1]
end
def right_bracket
elements[2]
end
end
module ArrayBrackets1
def left_bracket
elements[0]
end
def right_bracket
elements[1]
end
end
def _nt_array_brackets
start_index = index
if node_cache[:array_brackets].has_key?(index)
cached = node_cache[:array_brackets][index]
@index = cached.interval.end if cached
return cached
end
i0, s0 = index, []
r1 = _nt_left_bracket
s0 << r1
if r1
r2 = _nt_right_bracket
s0 << r2
if r2
s3, i3 = [], index
loop do
i4, s4 = index, []
r5 = _nt_left_bracket
s4 << r5
if r5
r6 = _nt_number
s4 << r6
if r6
r7 = _nt_right_bracket
s4 << r7
end
end
if s4.last
r4 = instantiate_node(SyntaxNode,input, i4...index, s4)
r4.extend(ArrayBrackets0)
else
self.index = i4
r4 = nil
end
if r4
s3 << r4
else
break
end
end
r3 = instantiate_node(SyntaxNode,input, i3...index, s3)
s0 << r3
end
end
if s0.last
r0 = instantiate_node(ArrayBracketsNode,input, i0...index, s0)
r0.extend(ArrayBrackets1)
else
self.index = i0
r0 = nil
end
node_cache[:array_brackets][start_index] = r0
return r0
end
module Const0
def space
elements[1]
@@ -1459,6 +1597,86 @@ module CMockFunctionPrototype
return r0
end
module LeftBracket0
def space
elements[1]
end
end
def _nt_left_bracket
start_index = index
if node_cache[:left_bracket].has_key?(index)
cached = node_cache[:left_bracket][index]
@index = cached.interval.end if cached
return cached
end
i0, s0 = index, []
if input.index('[', index) == index
r1 = instantiate_node(SyntaxNode,input, index...(index + 1))
@index += 1
else
terminal_parse_failure('[')
r1 = nil
end
s0 << r1
if r1
r2 = _nt_space
s0 << r2
end
if s0.last
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
r0.extend(LeftBracket0)
else
self.index = i0
r0 = nil
end
node_cache[:left_bracket][start_index] = r0
return r0
end
module RightBracket0
def space
elements[1]
end
end
def _nt_right_bracket
start_index = index
if node_cache[:right_bracket].has_key?(index)
cached = node_cache[:right_bracket][index]
@index = cached.interval.end if cached
return cached
end
i0, s0 = index, []
if input.index(']', index) == index
r1 = instantiate_node(SyntaxNode,input, index...(index + 1))
@index += 1
else
terminal_parse_failure(']')
r1 = nil
end
s0 << r1
if r1
r2 = _nt_space
s0 << r2
end
if s0.last
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
r0.extend(RightBracket0)
else
self.index = i0
r0 = nil
end
node_cache[:right_bracket][start_index] = r0
return r0
end
module Comma0
def space
elements[1]
@@ -1499,6 +1717,45 @@ module CMockFunctionPrototype
return r0
end
module Number0
def space
elements[1]
end
end
def _nt_number
start_index = index
if node_cache[:number].has_key?(index)
cached = node_cache[:number][index]
@index = cached.interval.end if cached
return cached
end
i0, s0 = index, []
if input.index(Regexp.new('[0-9]'), index) == index
r1 = instantiate_node(SyntaxNode,input, index...(index + 1))
@index += 1
else
r1 = nil
end
s0 << r1
if r1
r2 = _nt_space
s0 << r2
end
if s0.last
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
r0.extend(Number0)
else
self.index = i0
r0 = nil
end
node_cache[:number][start_index] = r0
return r0
end
def _nt_space
start_index = index
if node_cache[:space].has_key?(index)
+24 -3
View File
@@ -45,7 +45,7 @@ grammar CMockFunctionPrototype
# add name: tag to name? so we can always access it in programming even if blank.
# tell parser that type and optional name will always be followed by ',' '(' or ')' but don't consume them;
# this helps enforce the limits on what can be parsed in argument lists
type name:name? &( comma / left_paren / right_paren ) <TypeWithNameNode>
type name:name_with_brackets? &( comma / left_paren / right_paren ) <TypeWithNameNode>
end
rule type
@@ -55,7 +55,8 @@ grammar CMockFunctionPrototype
type_enum /
type_void_ptr /
type_primitive /
type_custom ) <TypeNode>
type_custom )
brackets:array_brackets? <TypeNode>
end
rule type_struct
@@ -87,7 +88,7 @@ grammar CMockFunctionPrototype
end
rule type_const_and_ptr_suffix
# "const *" or "* const" or "*" (asterisks can be multiples)
# "const *" or "* const" or "*" (more than one asterisk possible)
((const space asterisk+) / (asterisk+ (const space)?))
end
@@ -95,11 +96,19 @@ grammar CMockFunctionPrototype
[a-zA-Z0-9_]+ space <NameNode>
end
rule name_with_brackets
name brackets:array_brackets? <NameWithBracketsNode>
end
rule void
# in reality, 'void' is something different than the 'void*' type so limit to 'void' here and handle 'void*' in type rule;
# recognizing the VoidNode uniquely in programming is helpful
'void' space !asterisk <VoidNode>
end
rule array_brackets
left_bracket right_bracket (left_bracket number right_bracket)* <ArrayBracketsNode>
end
rule const
'const' space
@@ -117,10 +126,22 @@ grammar CMockFunctionPrototype
')' space
end
rule left_bracket
'[' space
end
rule right_bracket
']' space
end
rule comma
',' space
end
rule number
[0-9] space
end
rule space
' '*
end
+1 -1
View File
@@ -6,7 +6,7 @@ class CMockHeaderParser
def initialize(parser, source, cfg, name)
@src_lines = []
@prototypes = []
@prototype_parse_matcher = /([\d\w\s\*\(\),]+??)\(([\d\w\s\*\(\),\.]*)\)$/m
@prototype_parse_matcher = /([\d\w\s\*\(\),\[\]]+??)\(([\d\w\s\*\(\),\.\[\]]*)\)$/m
@c_attributes = cfg.attributes
@parser = parser
@@ -13,12 +13,14 @@
UINT32 foo(custom_type a);
UINT32 bar(custom_type b);
UINT32 foo_varargs(custom_type a, ...);
char* foo_char_strings(char a[], char* b);
:source:
:header: |
UINT32 function_a(int a, int b);
void function_b(void);
UINT32 function_c(int a);
char* function_d(char a[], char* b);
:code: |
UINT32 function_a(int a, int b)
@@ -33,6 +35,11 @@
return foo_varargs((custom_type)a, "ignored", 5);
}
char* function_d(char a[], char* b)
{
return foo_char_strings(a, b);
}
:tests:
:common: |
void setUp(void) {}
@@ -76,4 +83,13 @@
TEST_ASSERT_EQUAL(10, function_c(3));
}
- :pass: TRUE
:should: 'handle char strings'
:code: |
test()
{
foo_char_strings_ExpectAndReturn("larry", "curly", "moe");
TEST_ASSERT_EQUAL("moe", function_d("larry", "curly"));
}
...
@@ -146,6 +146,15 @@ class CMockFunctionPrototypeParserTest < Test::Unit::TestCase
{:type => 'CUSTOM_TYPE*', :name => 'xyz_123'}],
parsed.get_arguments)
assert_nil(parsed.get_var_arg)
parsed = @parser.parse("void foo_bar(CUSTOM_TYPE thing1[], int thing2 [ ], char thing3 [][2 ][ 3])")
assert_equal('CUSTOM_TYPE thing1[], int thing2[], char thing3[][2][3]', parsed.get_argument_list)
assert_equal([
{:type => 'CUSTOM_TYPE*', :name => 'thing1'},
{:type => 'int*', :name => 'thing2'},
{:type => 'char*', :name => 'thing3'}],
parsed.get_arguments)
assert_nil(parsed.get_var_arg)
end
@@ -298,14 +307,18 @@ class CMockFunctionPrototypeParserTest < Test::Unit::TestCase
should "insert unique names for top-level nameless arguments" do
parsed = @parser.parse("void foo_bar(int (*)(int, int), char* const, unsigned int c, CUSTOM_THING)")
parsed = @parser.parse("void foo_bar(int (*)(int, int), char* const, unsigned int c, CUSTOM_THING, int[], char[][2])")
assert_equal('int (*cmock_arg1)( int, int ), char* const cmock_arg2, unsigned int c, CUSTOM_THING cmock_arg4', parsed.get_argument_list)
assert_equal(
'int (*cmock_arg1)( int, int ), char* const cmock_arg2, unsigned int c, CUSTOM_THING cmock_arg4, int cmock_arg5[], char cmock_arg6[][2]',
parsed.get_argument_list)
assert_equal(
[{:type => 'FUNC_PTR_FOO_BAR_PARAM_1_T', :name => 'cmock_arg1'},
{:type => 'char* const', :name => 'cmock_arg2'},
{:type => 'unsigned int', :name => 'c'},
{:type => 'CUSTOM_THING', :name => 'cmock_arg4'}],
{:type => 'CUSTOM_THING', :name => 'cmock_arg4'},
{:type => 'int*', :name => 'cmock_arg5'},
{:type => 'char*', :name => 'cmock_arg6'}],
parsed.get_arguments)
assert_nil(parsed.get_var_arg)
end
+1 -1
View File
@@ -204,7 +204,7 @@ class CMockHeaderParserTest < Test::Unit::TestCase
end
should "raise upon prototype parsing failure" do
should "raise upon prototype parsing failure" do
source =
"int Foo(int a, unsigned int b);\n" +
"void bar \n(uint la, int de, bool da) ; \n"