diff --git a/changelog.txt b/changelog.txt index 92f611934..90888d5b9 100644 --- a/changelog.txt +++ b/changelog.txt @@ -62,6 +62,7 @@ Version 1.20.0 - fbc: intrinsic define __FB_OPTION_PROFILE__ to indicate if profiling is currently enabled for code generation - rtlib: ./fbc-int/profile.bi - extra features for working with the built-in profiler; ProfileSetFileName(), ProfileGetOptions(), ProfileSetOptions(). ProfileIgnore() - '-earraydims' command line option to enable array dimensions checking. Enabled by default with '-exx' command line option. +- github #426: add __FB_ARG_LISTEXPAND__( macroname, macroargcount, args... ): expands to one or more 'macroname( .... )' depending on the value of macroargcount and number of arguments in the args... list (skyfish) [fixed] - github #410: give consistent floating point comparisons results involving NaNs. diff --git a/src/compiler/hlp-str.bas b/src/compiler/hlp-str.bas index cd48183d6..4e8a2d0d1 100644 --- a/src/compiler/hlp-str.bas +++ b/src/compiler/hlp-str.bas @@ -7,6 +7,14 @@ #include once "fbint.bi" #include once "dstr.bi" +#if sizeof(wstring) = 4 + type WSTRING_CHAR as ulong +#elseif sizeof(wstring) = 2 + type WSTRING_CHAR as ushort +#else + type WSTRING_CHAR as ubyte +#endif + ''::::: #macro ASSIGN_SETUP(dst, src, _type) dim as integer dst_len, src_len @@ -1321,6 +1329,45 @@ function hStr2long( byref txt as string, byref value as long ) as integer return (*s = CHAR_NULL) end function +function hWStr2long( byref txt as wstring, byref value as long ) as integer + '' could we not use VALINT() or some variation from rtlib? + + const CHAR_ZERO = asc("0") + + dim nvalue as long = 0 + dim nsign as long = 1 + + if( len( txt ) = 0 ) then + return FALSE + end if + + dim s as WSTRING_CHAR ptr = strptr(txt) + + if( s = NULL orelse *s = CHAR_NULL ) then + return FALSE + end if + + if( *s = CHAR_MINUS ) then + nsign = -1 + s += 1 + end if + + if( *s = CHAR_NULL ) then + return FALSE + end if + + while( hIsCharNumeric(*s) ) + nvalue *= 10 + nvalue += (*s - CHAR_ZERO) + s += 1 + wend + + value = nvalue * nsign + + '' return TRUE if we read the entire string + return (*s = CHAR_NULL) +end function + ''::::: sub hSplitStr(byref txt as string, byref del as string, res() as string) @@ -1424,7 +1471,7 @@ end function ''::::: function hStr2Args( byval txt as const zstring ptr, res() as string ) as integer - '' !!!TODO!!! add the wstring version + '' add the string version dim as integer t = 0 dim as const ubyte ptr s = cast(const ubyte ptr, txt) @@ -1585,3 +1632,167 @@ function hStr2Args( byval txt as const zstring ptr, res() as string ) as integer function = t end function + +''::::: +function hWStr2Args( byval txt as const wstring ptr, res() as DWSTRING ) as integer + + dim as integer t = 0 + dim as const WSTRING_CHAR ptr s = cast(const WSTRING_CHAR ptr, txt) + + dim as integer prntcnt = 0 + dim as uinteger c = CHAR_NULL + dim as integer max_t = 10 + + if( txt = NULl ) then + return 0 + end if + + #define PeekChar() cast( uinteger, s[0] ) + #define SkipChar() s += 1 + #define ReadChar(c) DWstrConcatAssign( res(t-1), wchr(c) ) : s += 1 + + redim res( 0 to max_t-1 ) as DWSTRING + + do + c = PeekChar() + if (c = CHAR_TAB) or (c = CHAR_SPACE) then + SkipChar() + else + exit do + end if + loop + + '' no arguments? + if( c = CHAR_NULL ) then + return 0 + end if + + '' ok, there's at least one argument + t += 1 + + '' scan for arguments + do + c = PeekChar() + select case c + case CHAR_NULL + exit do + + case CHAR_LPRNT + prntcnt += 1 + + case CHAR_RPRNT + if( prntcnt > 0 ) then + prntcnt -= 1 + end if + + case CHAR_COMMA + if( prntcnt = 0 ) then + t += 1 + if( t > max_t ) then + max_t += 10 + redim preserve res( 0 to max_t - 1 ) + end if + SkipChar() + continue do + end if + + case CHAR_QUOTE, CHAR_EXCL, CHAR_DOLAR + dim as integer escaped = env.opt.escapestr + if( c <> CHAR_QUOTE ) then + escaped = ( c = CHAR_EXCL ) + + '' '!' | '$' + ReadChar(c) + c = PeekChar() + if( c <> CHAR_QUOTE ) then + continue do + end if + + end if + + '' '"' + ReadChar(c) + + do + c = PeekChar() + if( c = CHAR_NULL ) then + exit do + end if + + '' '"' | '\\' | any other string char + ReadChar(c) + if( c = CHAR_QUOTE ) then + + c = PeekChar() + if( c <> CHAR_QUOTE ) then + exit do + end if + + '' '"' + ReadChar(c) + + elseif( c = CHAR_RSLASH ) then + + c = PeekChar() + select case c + case CHAR_QUOTE, CHAR_RSLASH + '' '"' | '\\' + ReadChar(c) + end select + + end if + loop + continue do + + case CHAR_SLASH + + '' '/' + ReadChar(c) + + c = PeekChar() + if( c <> CHAR_APOST ) then + continue do + end if + + '' ''' + ReadChar(c) + + do + c = PeekChar() + if( c = CHAR_NULL ) then + exit do + end if + + '' ''' | any other comment char + ReadChar(c) + + if( c = CHAR_APOST ) then + c = PeekChar() + if( c = CHAR_SLASH ) then + '' '/' + ReadChar(c) + exit do + end if + end if + + loop + continue do + + case CHAR_APOST + while( c <> CHAR_NULL ) + '' ''' or any comment char to end of line + ReadChar(c) + c = PeekChar() + wend + exit do + + end select + + '' any other char not handled above + ReadChar(c) + + loop + + function = t + +end function diff --git a/src/compiler/hlp-str.bi b/src/compiler/hlp-str.bi index 8ac75485d..afecad067 100644 --- a/src/compiler/hlp-str.bi +++ b/src/compiler/hlp-str.bi @@ -1,5 +1,6 @@ #ifndef __HELP_STR_BI__ #define __HELP_STR_BI__ +#include once "dstr.bi" declare sub ZstrAssign _ ( _ @@ -138,12 +139,16 @@ declare function hIsValidHexDigit( byval ch as integer ) as integer declare function hStr2long( byref txt as string, byref value as long ) as integer +declare function hWStr2long( byref txt as wstring, byref value as long ) as integer + declare sub hSplitStr(byref txt as string, byref del as string, res() as string) declare function hStr2Tok(byval txt as const zstring ptr, res() as string) as integer declare function hStr2Args(byval txt as const zstring ptr, res() as string) as integer +declare function hWStr2Args( byval txt as const wstring ptr, res() as DWSTRING ) as integer + ''::::: #define ZstrAllocate(chars) xallocate( chars + 1 ) diff --git a/src/compiler/symb-define.bas b/src/compiler/symb-define.bas index 792980b5e..a2c9a49de 100644 --- a/src/compiler/symb-define.bas +++ b/src/compiler/symb-define.bas @@ -687,7 +687,181 @@ private function hDefArgExtract_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum end function -private function hDefArgLeft_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum as integer ptr ) as string +private function hDefArgListExpandZ_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum as integer ptr ) as string + + '' __FB_ARG_LISTEXPAND__(MACRONAME, MACROARGCOUNT, ARGS...) + '' Retuns empty string on invalid index, rather than compile error. + '' MacroName : the name of the macro used for extension calls. + '' MacroArgCount : the number of parameters for the MacroName macro.Expand the parameter list Args according to the MacroArgCount value. + '' 1, MacroArgCount>0, pass MacroArgCount parameters each time; + ' 2, MacroArgCount=0, pass all parameters; + '' 3, MacroArgCount<0, for each parameter passed, the previous MacroArgCount parameters are automatically removed on the next pass. + '' args... : argument list(The number of Args parameters passed may not be an integer multiple of MacroArgCount.) + + /' + #macro m( arg... ) + #print " "##arg + #endmacro + + #print "1. MacroArgCount=0:" + __FB_ARG_LISTEXPAND__( m, 0, Hello1, Hello2, Hello3, Hello4) + #print "2. MacroArgCount>0:" + __FB_ARG_LISTEXPAND__( m, 1, Hello1, Hello2, Hello3, Hello4) + #print "3. MacroArgCount<0:" + __FB_ARG_LISTEXPAND__( m, -1, Hello1, Hello2, Hello3, Hello4) + '/ + + /' Compiler output: + 1. MacroArgCount=0: + Hello1, Hello2, Hello3, Hello4 + 2. MacroArgCount>0: + Hello1 + Hello2 + Hello3 + Hello4 + 3. MacroArgCount<0: + Hello1, Hello2, Hello3, Hello4 + Hello2, Hello3, Hello4 + Hello3, Hello4 + Hello4 + '/ + + var res = "" + var MacroNameStr = hMacro_getArgZ( argtb, 0 ) + var numStr = hMacro_getArgZ( argtb, 1 ) + + if( MacroNameStr<>NULL andalso numStr <> NULL ) then + dim as string varstr = hMacro_EvalZ(numStr, errnum) + + dim as long ArgCount, index, index2 = 0 + If hStr2long(varstr, ArgCount) Then + dim As Long numVarArgs = argtb->count-2, MaxVarArgs = any + if numVarArgs>0 then + var argStr = hMacro_getArgZ( argtb, 2 ) + dim varArgs() as string + if ArgCount = 0 then + res &= *MacroNameStr & "(" + res &= *argStr + res &= ")" + else + numVarArgs = hStr2Args( argStr, varArgs() ) - 1 + if ArgCount < 0 then ' Is Negate ? + for index = 0 to numVarArgs step -ArgCount + if( index > 0 ) then + res &= NEWLINE + end if + res &= *MacroNameStr & "(" + for index2 = index to numVarArgs + res &= varArgs(index2) + if index2 <> numVarArgs then + res &= "," + end if + next + res &= ")" + next + else + for index = 0 to numVarArgs step ArgCount + if( index > 0 ) then + res &= NEWLINE + end if + res &= *MacroNameStr & "(" + MaxVarArgs = iif(ArgCount>numVarArgs-index,numVarArgs,index+ArgCount-1) + for index2 = index to MaxVarArgs + res &= varArgs(index2) + if index2 <> MaxVarArgs then + res &= "," + end if + next + res &= ")" + next + end if + end if + ZStrFree(argStr) + else '' No args + *errnum = FB_ERRMSG_ARGCNTMISMATCH + end if + end if + + else '' No args + *errnum = FB_ERRMSG_ARGCNTMISMATCH + end if + ZStrFree(numStr) + ZStrFree(MacroNameStr) + return res + +end function + +private function hDefArgListExpandW_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum as integer ptr ) as wstring ptr + + '' __FB_ARG_LISTEXPAND__(MACRONAME, MACROARGCOUNT, ARGS...) + '' Retuns empty string on invalid index, rather than compile error + + static res as DWSTRING + DWstrAssign(res, "") + dim as DWSTRING MacroNameStr + DWstrAssign(MacroNameStr, hMacro_getArgW( argtb, 0 )) + var numStr = hMacro_getArgW( argtb, 1 ) + + if( MacroNameStr.len<>0 andalso numStr <> NULL ) then + dim as Wstring ptr pvarstr = hMacro_EvalW(numStr, errnum) + + dim as long ArgCount, index, index2 = 0 + If hWStr2long(*pvarstr, ArgCount) Then + dim As Long numVarArgs = argtb->count-2, MaxVarArgs = any + if numVarArgs>0 then + dim as Wstring ptr argStr = hMacro_getArgW( argtb, 2 ) + if ArgCount = 0 then + DWstrAssign(res, *MacroNameStr.data ) + DWstrConcatAssign(res, "(" & *argStr & ")" ) + else + dim varArgs() as DWSTRING + numVarArgs = hWStr2Args( argStr, varArgs() ) - 1 + if ArgCount < 0 then ' Is Negate ? + for index = 0 to numVarArgs step -ArgCount + if( index > 0 ) then + DWstrConcatAssign(res, NEWLINE ) + end if + DWstrConcatAssign(res, *MacroNameStr.data ) + DWstrConcatAssign(res, "(" ) + for index2 = index to numVarArgs + DWstrConcatAssign(res, varArgs(index2).data ) + if index2 <> numVarArgs then + DWstrConcatAssign(res, "," ) + end if + next + DWstrConcatAssign(res, ")" ) + next + else + for index = 0 to numVarArgs step ArgCount + if( index > 0 ) then + DWstrConcatAssign(res, NEWLINE ) + end if + DWstrConcatAssign(res, *MacroNameStr.data ) + DWstrConcatAssign(res, "(" ) + MaxVarArgs = iif(ArgCount>numVarArgs-index,numVarArgs,index+ArgCount-1) + for index2 = index to MaxVarArgs + DWstrConcatAssign(res, varArgs(index2).data ) + if index2 <> MaxVarArgs then + DWstrConcatAssign(res, "," ) + end if + next + DWstrConcatAssign(res, ")" ) + next + end if + end if + else '' No args + *errnum = FB_ERRMSG_ARGCNTMISMATCH + end if + end if + + else '' No args + *errnum = FB_ERRMSG_ARGCNTMISMATCH + end if + return res.data + +end function + +private function hDefArgLeft_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum as integer ptr) as string '' __FB_ARG_LEFTTOF__( ARG, SEP [, RET = ""] ) @@ -1324,7 +1498,8 @@ dim shared macroTb(0 to ...) as SYMBMACRO => _ (@"__FB_UNQUOTE__" , 0 , @hDefUnquoteZ_cb , @hDefUnquoteW_cb , 1, { (@"ARG") } ), _ (@"__FB_EVAL__" , 0 , @hDefEvalZ_cb , @hDefEvalW_cb , 1, { (@"ARG") } ), _ (@"__FB_IIF__" , 0 , @hDefIifZ_cb , @hDefIifW_cb , 3, { (@"CMPEXPR"), (@"TEXPR"), (@"FEXPR") } ), _ - (@"__FB_QUERY_SYMBOL__" , 0 , @hDefQuerySymZ_cb , NULL , 2, { (@"WHAT"), (@"SYM") } ) _ + (@"__FB_QUERY_SYMBOL__" , 0 , @hDefQuerySymZ_cb , NULL , 2, { (@"WHAT"), (@"SYM") } ), _ + (@"__FB_ARG_LISTEXPAND__" , FB_DEFINE_FLAGS_VARIADIC, @hDefArgListExpandZ_cb, @hDefArgListExpandW_cb , 3, { (@"MACRONAME"), (@"MACROARGCOUNT"), (@"ARGS") } ) _ } sub symbDefineInit _ @@ -1350,7 +1525,7 @@ sub symbDefineInit _ end if symbAddDefine( defTb(i).name, value, len( value ), _ - FALSE, defTb(i).proc, defTb(i).flags ) + FALSE, defTb(i).proc, defTb(i).flags ) next '' Add __FB___ define @@ -1453,11 +1628,11 @@ function symbAddDefine _ '' allocate new node (always on global hash, ns' won't work in lexer) sym = symbNewSymbol( FB_SYMBOPT_DOHASH, _ - NULL, _ - NULL, @symbGetGlobalHashTb( ), _ - FB_SYMBCLASS_DEFINE, _ - symbol, NULL, _ - FB_DATATYPE_CHAR, NULL, FB_SYMBATTRIB_NONE, FB_PROCATTRIB_NONE ) + NULL, _ + NULL, @symbGetGlobalHashTb( ), _ + FB_SYMBCLASS_DEFINE, _ + symbol, NULL, _ + FB_DATATYPE_CHAR, NULL, FB_SYMBATTRIB_NONE, FB_PROCATTRIB_NONE ) if( sym = NULL ) then exit function end if @@ -1492,11 +1667,11 @@ function symbAddDefineW _ '' allocate new node (always on global hash, ns' won't work in lexer) sym = symbNewSymbol( FB_SYMBOPT_DOHASH, _ - NULL, _ - NULL, @symbGetGlobalHashTb( ), _ - FB_SYMBCLASS_DEFINE, _ - symbol, NULL, _ - FB_DATATYPE_WCHAR, NULL, FB_SYMBATTRIB_NONE, FB_PROCATTRIB_NONE ) + NULL, _ + NULL, @symbGetGlobalHashTb( ), _ + FB_SYMBCLASS_DEFINE, _ + symbol, NULL, _ + FB_DATATYPE_WCHAR, NULL, FB_SYMBATTRIB_NONE, FB_PROCATTRIB_NONE ) if( sym = NULL ) then exit function end if @@ -1530,11 +1705,11 @@ function symbAddDefineMacro _ '' allocate new node (always on global hash, ns' won't work in lexer) sym = symbNewSymbol( FB_SYMBOPT_DOHASH, _ - NULL, _ - NULL, @symbGetGlobalHashTb( ), _ - FB_SYMBCLASS_DEFINE, _ - symbol, NULL, _ - FB_DATATYPE_INVALID, NULL, FB_SYMBATTRIB_NONE, FB_PROCATTRIB_NONE ) + NULL, _ + NULL, @symbGetGlobalHashTb( ), _ + FB_SYMBCLASS_DEFINE, _ + symbol, NULL, _ + FB_DATATYPE_INVALID, NULL, FB_SYMBATTRIB_NONE, FB_PROCATTRIB_NONE ) if( sym = NULL ) then exit function end if diff --git a/tests/pp/macro-arg-listexpand-utf16le.bas b/tests/pp/macro-arg-listexpand-utf16le.bas new file mode 100644 index 000000000..261a2b4f4 Binary files /dev/null and b/tests/pp/macro-arg-listexpand-utf16le.bas differ diff --git a/tests/pp/macro-arg-listexpand.bas b/tests/pp/macro-arg-listexpand.bas new file mode 100644 index 000000000..4d3fc07b0 --- /dev/null +++ b/tests/pp/macro-arg-listexpand.bas @@ -0,0 +1,574 @@ +#include "fbcunit.bi" + +SUITE( fbc_tests.pp.macro_arg_listexpand ) + + const x0 = 1 + const x1 = 10 + const x2 = 100 + const x3 = 1000 + const x4 = 10000 + + dim shared g_args_remain as integer + dim shared g_next_args as integer + dim shared g_args_step as integer + dim shared g_total_args as integer + dim shared g_total_calls as integer + dim shared g_total_value as integer + + sub hResetCounts( byval stp as integer, byval args as integer ) + g_args_step = stp + g_args_remain = args + if( stp < 0 ) then + g_next_args = args + elseif( stp > 0 ) then + if( g_args_remain >= stp ) then + g_next_args = stp + else + g_next_args = g_args_remain + end if + else + g_next_args = args + end if + g_total_calls = 0 + g_total_args = 0 + g_total_value = 0 + end sub + + sub hUpdateCounts( byval args as integer ) + g_total_calls += 1 + g_total_args += args + if( g_args_step < 0 ) then + if( g_args_remain >= -g_args_step ) then + g_args_remain -= -g_args_step + else + g_args_remain = 0 + end if + g_next_args -= -g_args_step + if( g_next_args < 0 ) then + g_next_args = 0 + end if + elseif( g_args_step > 0 ) then + if( g_args_remain >= g_args_step ) then + g_args_remain -= g_args_step + else + g_args_remain = 0 + end if + if( g_args_remain >= g_args_step ) then + g_next_args = g_args_step + else + g_next_args = g_args_remain + end if + else + g_next_args = 0 + g_args_remain = 0 + end if + '' print "UPDATE:", "remain=" & g_args_remain, "NEXT=" & g_next_args + end sub + + #macro M( args... ) + scope + const n = __FB_ARG_COUNT__( args ) + #if( n >= 1 ) + g_total_value += __FB_ARG_EXTRACT__( 0, args ) + #endif + #if( n >= 2 ) + g_total_value += __FB_ARG_EXTRACT__( 1, args ) + #endif + #if( n >= 3 ) + g_total_value += __FB_ARG_EXTRACT__( 2, args ) + #endif + #if( n >= 4 ) + g_total_value += __FB_ARG_EXTRACT__( 3, args ) + #endif + #if( n >= 5 ) + g_total_value += __FB_ARG_EXTRACT__( 4, args ) + #endif + CU_ASSERT( n = g_next_args ) + hUpdateCounts( n ) + end scope + #endmacro + + '' Will error because there are no arguments in the list + '' __FB_ARG_LISTEXPAND__( M, 0 ) + '' __FB_ARG_LISTEXPAND__( M, 1 ) + '' __FB_ARG_LISTEXPAND__( M, 2 ) + '' __FB_ARG_LISTEXPAND__( M, 3 ) + '' __FB_ARG_LISTEXPAND__( M, 4 ) + '' __FB_ARG_LISTEXPAND__( M, 5 ) + '' __FB_ARG_LISTEXPAND__( M, 6 ) + '' __FB_ARG_LISTEXPAND__( M, -1 ) + '' __FB_ARG_LISTEXPAND__( M, -2 ) + '' __FB_ARG_LISTEXPAND__( M, -3 ) + '' __FB_ARG_LISTEXPAND__( M, -4 ) + '' __FB_ARG_LISTEXPAND__( M, -5 ) + '' __FB_ARG_LISTEXPAND__( M, -6 ) + + TEST( T_zero_1 ) + hResetCounts( 0, 1 ) + __FB_ARG_LISTEXPAND__( M, 0, x0 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 1 ) + CU_ASSERT( g_total_value = 1 ) + END_TEST + TEST( T_zero_2 ) + hResetCounts( 0, 2 ) + __FB_ARG_LISTEXPAND__( M, 0, x0, x1 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 2 ) + CU_ASSERT( g_total_value = 1+10 ) + END_TEST + TEST( T_zero_3 ) + hResetCounts( 0, 3 ) + __FB_ARG_LISTEXPAND__( M, 0, x0, x1, x2 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 3 ) + CU_ASSERT( g_total_value = 1+10+100 ) + END_TEST + TEST( T_zero_4 ) + hResetCounts( 0, 4 ) + __FB_ARG_LISTEXPAND__( M, 0, x0, x1, x2, x3 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 4 ) + CU_ASSERT( g_total_value = 1+10+100+1000 ) + END_TEST + TEST( T_zero_5 ) + hResetCounts( 0, 5 ) + __FB_ARG_LISTEXPAND__( M, 0, x0, x1, x2, x3, x4 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 5 ) + CU_ASSERT( g_total_value = 1+10+100+1000+10000 ) + END_TEST + + TEST( T_pos1_1 ) + hResetCounts( 1, 1 ) + __FB_ARG_LISTEXPAND__( M, 1, x0 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 1 ) + CU_ASSERT( g_total_value = 1 ) + END_TEST + TEST( T_pos1_2 ) + hResetCounts( 1, 2 ) + __FB_ARG_LISTEXPAND__( M, 1, x0, x1 ) + CU_ASSERT( g_total_calls = 2 ) + CU_ASSERT( g_total_args = 2 ) + CU_ASSERT( g_total_value = 1+10 ) + END_TEST + TEST( T_pos1_3 ) + hResetCounts( 1, 3 ) + __FB_ARG_LISTEXPAND__( M, 1, x0, x1, x2 ) + CU_ASSERT( g_total_calls = 3 ) + CU_ASSERT( g_total_args = 3 ) + CU_ASSERT( g_total_value = 1+10+100 ) + END_TEST + TEST( T_pos1_4 ) + hResetCounts( 1, 4 ) + __FB_ARG_LISTEXPAND__( M, 1, x0, x1, x2, x3 ) + CU_ASSERT( g_total_calls = 4 ) + CU_ASSERT( g_total_args = 4 ) + CU_ASSERT( g_total_value = 1+10+100+1000 ) + END_TEST + TEST( T_pos1_5 ) + hResetCounts( 1, 5 ) + __FB_ARG_LISTEXPAND__( M, 1, x0, x1, x2, x3, x4 ) + CU_ASSERT( g_total_calls = 5 ) + CU_ASSERT( g_total_args = 5 ) + CU_ASSERT( g_total_value = 1+10+100+1000+10000 ) + END_TEST + + TEST( T_pos2_1 ) + hResetCounts( 2, 1 ) + __FB_ARG_LISTEXPAND__( M, 2, x0 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 1 ) + CU_ASSERT( g_total_value = 1 ) + END_TEST + TEST( T_pos2_2 ) + hResetCounts( 2, 2 ) + __FB_ARG_LISTEXPAND__( M, 2, x0, x1 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 2 ) + CU_ASSERT( g_total_value = 1+10 ) + END_TEST + TEST( T_pos2_3 ) + hResetCounts( 2, 3 ) + __FB_ARG_LISTEXPAND__( M, 2, x0, x1, x2 ) + CU_ASSERT( g_total_calls = 2 ) + CU_ASSERT( g_total_args = 3 ) + CU_ASSERT( g_total_value = 1+10+100 ) + END_TEST + TEST( T_pos2_4 ) + hResetCounts( 2, 4 ) + __FB_ARG_LISTEXPAND__( M, 2, x0, x1, x2, x3 ) + CU_ASSERT( g_total_calls = 2 ) + CU_ASSERT( g_total_args = 4 ) + CU_ASSERT( g_total_value = 1+10+100+1000 ) + END_TEST + TEST( T_pos2_5 ) + hResetCounts( 2, 5 ) + __FB_ARG_LISTEXPAND__( M, 2, x0, x1, x2, x3, x4 ) + CU_ASSERT( g_total_calls = 3 ) + CU_ASSERT( g_total_args = 5 ) + CU_ASSERT( g_total_value = 1+10+100+1000+10000 ) + END_TEST + + TEST( T_pos3_1 ) + hResetCounts( 3, 1 ) + __FB_ARG_LISTEXPAND__( M, 3, x0 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 1 ) + CU_ASSERT( g_total_value = 1 ) + END_TEST + TEST( T_pos3_2 ) + hResetCounts( 3, 2 ) + __FB_ARG_LISTEXPAND__( M, 3, x0, x1 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 2 ) + CU_ASSERT( g_total_value = 1+10 ) + END_TEST + TEST( T_pos3_3 ) + hResetCounts( 3, 3 ) + __FB_ARG_LISTEXPAND__( M, 3, x0, x1, x2 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 3 ) + CU_ASSERT( g_total_value = 1+10+100 ) + END_TEST + TEST( T_pos3_4 ) + hResetCounts( 3, 4 ) + __FB_ARG_LISTEXPAND__( M, 3, x0, x1, x2, x3 ) + CU_ASSERT( g_total_calls = 2 ) + CU_ASSERT( g_total_args = 4 ) + CU_ASSERT( g_total_value = 1+10+100+1000 ) + END_TEST + TEST( T_pos3_5 ) + hResetCounts( 3, 5 ) + __FB_ARG_LISTEXPAND__( M, 3, x0, x1, x2, x3, x4 ) + CU_ASSERT( g_total_calls = 2 ) + CU_ASSERT( g_total_args = 5 ) + CU_ASSERT( g_total_value = 1+10+100+1000+10000 ) + END_TEST + + TEST( T_pos4_1 ) + hResetCounts( 4, 1 ) + __FB_ARG_LISTEXPAND__( M, 4, x0 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 1 ) + CU_ASSERT( g_total_value = 1 ) + END_TEST + TEST( T_pos4_2 ) + hResetCounts( 4, 2 ) + __FB_ARG_LISTEXPAND__( M, 4, x0, x1 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 2 ) + CU_ASSERT( g_total_value = 1+10 ) + END_TEST + TEST( T_pos4_3 ) + hResetCounts( 4, 3 ) + __FB_ARG_LISTEXPAND__( M, 4, x0, x1, x2 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 3 ) + CU_ASSERT( g_total_value = 1+10+100 ) + END_TEST + TEST( T_pos4_4 ) + hResetCounts( 4, 4 ) + __FB_ARG_LISTEXPAND__( M, 4, x0, x1, x2, x3 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 4 ) + CU_ASSERT( g_total_value = 1+10+100+1000 ) + END_TEST + TEST( T_pos4_5 ) + hResetCounts( 4, 5 ) + __FB_ARG_LISTEXPAND__( M, 4, x0, x1, x2, x3, x4 ) + CU_ASSERT( g_total_calls = 2 ) + CU_ASSERT( g_total_args = 5 ) + CU_ASSERT( g_total_value = 1+10+100+1000+10000 ) + END_TEST + + TEST( T_pos5_1 ) + hResetCounts( 5, 1 ) + __FB_ARG_LISTEXPAND__( M, 5, x0 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 1 ) + CU_ASSERT( g_total_value = 1 ) + END_TEST + TEST( T_pos5_2 ) + hResetCounts( 5, 2 ) + __FB_ARG_LISTEXPAND__( M, 5, x0, x1 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 2 ) + CU_ASSERT( g_total_value = 1+10 ) + END_TEST + TEST( T_pos5_3 ) + hResetCounts( 5, 3 ) + __FB_ARG_LISTEXPAND__( M, 5, x0, x1, x2 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 3 ) + CU_ASSERT( g_total_value = 1+10+100 ) + END_TEST + TEST( T_pos5_4 ) + hResetCounts( 5, 4 ) + __FB_ARG_LISTEXPAND__( M, 5, x0, x1, x2, x3 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 4 ) + CU_ASSERT( g_total_value = 1+10+100+1000 ) + END_TEST + TEST( T_pos5_5 ) + hResetCounts( 5, 5 ) + __FB_ARG_LISTEXPAND__( M, 5, x0, x1, x2, x3, x4 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 5 ) + CU_ASSERT( g_total_value = 1+10+100+1000+10000 ) + END_TEST + + TEST( T_pos6_1 ) + hResetCounts( 6, 1 ) + __FB_ARG_LISTEXPAND__( M, 6, x0 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 1 ) + CU_ASSERT( g_total_value = 1 ) + END_TEST + TEST( T_pos6_2 ) + hResetCounts( 6, 2 ) + __FB_ARG_LISTEXPAND__( M, 6, x0, x1 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 2 ) + CU_ASSERT( g_total_value = 1+10 ) + END_TEST + TEST( T_pos6_3 ) + hResetCounts( 6, 3 ) + __FB_ARG_LISTEXPAND__( M, 6, x0, x1, x2 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 3 ) + CU_ASSERT( g_total_value = 1+10+100 ) + END_TEST + TEST( T_pos6_4 ) + hResetCounts( 6, 4 ) + __FB_ARG_LISTEXPAND__( M, 6, x0, x1, x2, x3 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 4 ) + CU_ASSERT( g_total_value = 1+10+100+1000 ) + END_TEST + TEST( T_pos6_5 ) + hResetCounts( 6, 5 ) + __FB_ARG_LISTEXPAND__( M, 6, x0, x1, x2, x3, x4 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 5 ) + CU_ASSERT( g_total_value = 1+10+100+1000+10000 ) + END_TEST + + TEST( T_neg1_1 ) + hResetCounts( -1, 1 ) + __FB_ARG_LISTEXPAND__( M, -1, x0 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 1 ) + CU_ASSERT( g_total_value = 000001 ) + END_TEST + TEST( T_neg1_2 ) + hResetCounts( -1, 2 ) + __FB_ARG_LISTEXPAND__( M, -1, x0, x1 ) + CU_ASSERT( g_total_calls = 2 ) + CU_ASSERT( g_total_args = 2+1 ) + CU_ASSERT( g_total_value = 00021 ) + END_TEST + TEST( T_neg1_3 ) + hResetCounts( -1, 3 ) + __FB_ARG_LISTEXPAND__( M, -1, x0, x1, x2 ) + CU_ASSERT( g_total_calls = 3 ) + CU_ASSERT( g_total_args = 3+2+1 ) + CU_ASSERT( g_total_value = 00321 ) + END_TEST + TEST( T_neg1_4 ) + hResetCounts( -1, 4 ) + __FB_ARG_LISTEXPAND__( M, -1, x0, x1, x2, x3 ) + CU_ASSERT( g_total_calls = 4 ) + CU_ASSERT( g_total_args = 4+3+2+1 ) + CU_ASSERT( g_total_value = 04321 ) + END_TEST + TEST( T_neg1_5 ) + hResetCounts( -1, 5 ) + __FB_ARG_LISTEXPAND__( M, -1, x0, x1, x2, x3, x4 ) + CU_ASSERT( g_total_calls = 5 ) + CU_ASSERT( g_total_args = 5+4+3+2+1 ) + CU_ASSERT( g_total_value = 54321 ) + END_TEST + + TEST( T_neg2_1 ) + hResetCounts( -2, 1 ) + __FB_ARG_LISTEXPAND__( M, -2, x0 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 1 ) + CU_ASSERT( g_total_value = 00001 ) + END_TEST + TEST( T_neg2_2 ) + hResetCounts( -2, 2 ) + __FB_ARG_LISTEXPAND__( M, -2, x0, x1 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 2 ) + CU_ASSERT( g_total_value = 00011 ) + END_TEST + TEST( T_neg2_3 ) + hResetCounts( -2, 3 ) + __FB_ARG_LISTEXPAND__( M, -2, x0, x1, x2 ) + CU_ASSERT( g_total_calls = 2 ) + CU_ASSERT( g_total_args = 3+1 ) + CU_ASSERT( g_total_value = 00211 ) + END_TEST + TEST( T_neg2_4 ) + hResetCounts( -2, 4 ) + __FB_ARG_LISTEXPAND__( M, -2, x0, x1, x2, x3 ) + CU_ASSERT( g_total_calls = 2 ) + CU_ASSERT( g_total_args = 4+2 ) + CU_ASSERT( g_total_value = 02211 ) + END_TEST + TEST( T_neg2_5 ) + hResetCounts( -2, 5 ) + __FB_ARG_LISTEXPAND__( M, -2, x0, x1, x2, x3, x4 ) + CU_ASSERT( g_total_calls = 3 ) + CU_ASSERT( g_total_args = 5+3+1 ) + CU_ASSERT( g_total_value = 32211 ) + END_TEST + + TEST( T_neg3_1 ) + hResetCounts( -3, 1 ) + __FB_ARG_LISTEXPAND__( M, -3, x0 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 1 ) + CU_ASSERT( g_total_value = 00001 ) + END_TEST + TEST( T_neg3_2 ) + hResetCounts( -3, 2 ) + __FB_ARG_LISTEXPAND__( M, -3, x0, x1 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 2 ) + CU_ASSERT( g_total_value = 00011 ) + END_TEST + TEST( T_neg3_3 ) + hResetCounts( -3, 3 ) + __FB_ARG_LISTEXPAND__( M, -3, x0, x1, x2 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 3 ) + CU_ASSERT( g_total_value = 00111 ) + END_TEST + TEST( T_neg3_4 ) + hResetCounts( -3, 4 ) + __FB_ARG_LISTEXPAND__( M, -3, x0, x1, x2, x3 ) + CU_ASSERT( g_total_calls = 2 ) + CU_ASSERT( g_total_args = 4+1 ) + CU_ASSERT( g_total_value = 02111 ) + END_TEST + TEST( T_neg3_5 ) + hResetCounts( -3, 5 ) + __FB_ARG_LISTEXPAND__( M, -3, x0, x1, x2, x3, x4 ) + CU_ASSERT( g_total_calls = 2 ) + CU_ASSERT( g_total_args = 5+2 ) + CU_ASSERT( g_total_value = 22111 ) + END_TEST + + TEST( T_neg4_1 ) + hResetCounts( -4, 1 ) + __FB_ARG_LISTEXPAND__( M, -4, x0 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 1 ) + CU_ASSERT( g_total_value = 00001 ) + END_TEST + TEST( T_neg4_2 ) + hResetCounts( -4, 2 ) + __FB_ARG_LISTEXPAND__( M, -4, x0, x1 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 2 ) + CU_ASSERT( g_total_value = 00011 ) + END_TEST + TEST( T_neg4_3 ) + hResetCounts( -4, 3 ) + __FB_ARG_LISTEXPAND__( M, -4, x0, x1, x2 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 3 ) + CU_ASSERT( g_total_value = 00111 ) + END_TEST + TEST( T_neg4_4 ) + hResetCounts( -4, 4 ) + __FB_ARG_LISTEXPAND__( M, -4, x0, x1, x2, x3 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 4 ) + CU_ASSERT( g_total_value = 01111 ) + END_TEST + TEST( T_neg4_5 ) + hResetCounts( -4, 5 ) + __FB_ARG_LISTEXPAND__( M, -4, x0, x1, x2, x3, x4 ) + CU_ASSERT( g_total_calls = 2 ) + CU_ASSERT( g_total_args = 5+1 ) + CU_ASSERT( g_total_value = 21111 ) + END_TEST + + TEST( T_neg5_1 ) + hResetCounts( -5, 1 ) + __FB_ARG_LISTEXPAND__( M, -5, x0 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 1 ) + CU_ASSERT( g_total_value = 00001 ) + END_TEST + TEST( T_neg5_2 ) + hResetCounts( -5, 2 ) + __FB_ARG_LISTEXPAND__( M, -5, x0, x1 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 2 ) + CU_ASSERT( g_total_value = 00011 ) + END_TEST + TEST( T_neg5_3 ) + hResetCounts( -5, 3 ) + __FB_ARG_LISTEXPAND__( M, -5, x0, x1, x2 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 3 ) + CU_ASSERT( g_total_value = 00111 ) + END_TEST + TEST( T_neg5_4 ) + hResetCounts( -5, 4 ) + __FB_ARG_LISTEXPAND__( M, -5, x0, x1, x2, x3 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 4 ) + CU_ASSERT( g_total_value = 01111 ) + END_TEST + TEST( T_neg5_5 ) + hResetCounts( -5, 5 ) + __FB_ARG_LISTEXPAND__( M, -5, x0, x1, x2, x3, x4 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 5 ) + CU_ASSERT( g_total_value = 11111 ) + END_TEST + + TEST( T_neg6_1 ) + hResetCounts( -6, 1 ) + __FB_ARG_LISTEXPAND__( M, -6, x0 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 1 ) + CU_ASSERT( g_total_value = 00001 ) + END_TEST + TEST( T_neg6_2 ) + hResetCounts( -6, 2 ) + __FB_ARG_LISTEXPAND__( M, -6, x0, x1 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 2 ) + CU_ASSERT( g_total_value = 00011 ) + END_TEST + TEST( T_neg6_3 ) + hResetCounts( -6, 3 ) + __FB_ARG_LISTEXPAND__( M, -6, x0, x1, x2 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 3 ) + CU_ASSERT( g_total_value = 00111 ) + END_TEST + TEST( T_neg6_4 ) + hResetCounts( -6, 4 ) + __FB_ARG_LISTEXPAND__( M, -6, x0, x1, x2, x3 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 4 ) + CU_ASSERT( g_total_value = 01111 ) + END_TEST + TEST( T_neg6_5 ) + hResetCounts( -6, 5 ) + __FB_ARG_LISTEXPAND__( M, -6, x0, x1, x2, x3, x4 ) + CU_ASSERT( g_total_calls = 1 ) + CU_ASSERT( g_total_args = 5 ) + CU_ASSERT( g_total_value = 11111 ) + END_TEST + +END_SUITE