mirror of
https://github.com/ThrowTheSwitch/CMock.git
synced 2026-10-04 16:07:25 +00:00
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:
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user