From a9d356b2f3322a1d244dda2f70304f754473259d Mon Sep 17 00:00:00 2001 From: SkyFIsh Date: Fri, 31 May 2024 10:43:48 +0800 Subject: [PATCH 1/3] Preprocess the target macro based on the macro parameter list. --- src/compiler/hlp-str.bas | 206 +++++++++++++++++++++++++++++++++- src/compiler/hlp-str.bi | 5 + src/compiler/symb-define.bas | 211 +++++++++++++++++++++++++++++++---- 3 files changed, 397 insertions(+), 25 deletions(-) diff --git a/src/compiler/hlp-str.bas b/src/compiler/hlp-str.bas index cd48183d6..4a8649c46 100644 --- a/src/compiler/hlp-str.bas +++ b/src/compiler/hlp-str.bas @@ -1321,6 +1321,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 ushort 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 +1463,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 +1624,168 @@ 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 + + '' add the wstring version + + dim as integer t = 0 + dim as const ushort ptr s = cast(const ushort 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..36d3f67f1 100644 --- a/src/compiler/symb-define.bas +++ b/src/compiler/symb-define.bas @@ -687,7 +687,169 @@ 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 + res &= *MacroNameStr & "(" + for index2 = index to numVarArgs + res &= varArgs(index2) + if index2 <> numVarArgs then + res &= "," + end if + next + res &= ")" & NEWLINE + next + else + for index = 0 to numVarArgs step ArgCount + 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 &= ")" & NEWLINE + 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 + 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, ")" & NEWLINE ) + next + else + for index = 0 to numVarArgs step ArgCount + 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, ")" & NEWLINE ) + 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 = ""] ) @@ -733,7 +895,7 @@ private function hDefArgLeft_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum as end function -private function hDefArgRight_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum as integer ptr ) as string +private function hDefArgRight_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum as integer ptr) as string '' __FB_ARG_RIGHTOF__( ARG, SEP [, RET = ""] ) @@ -778,7 +940,7 @@ private function hDefArgRight_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum a end function -private function hDefJoinZ_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum as integer ptr ) as string +private function hDefJoinZ_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum as integer ptr) as string '' __FB_JOIN__( L, R ) @@ -799,7 +961,7 @@ private function hDefJoinZ_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum as i end function -private function hDefJoinW_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum as integer ptr ) as wstring ptr +private function hDefJoinW_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum as integer ptr) as wstring ptr '' __FB_JOIN__( L, R ) @@ -820,7 +982,7 @@ private function hDefJoinW_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum as i end function -private function hDefQuoteZ_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum as integer ptr ) as string +private function hDefQuoteZ_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum as integer ptr) as string '' __FB_QUOTE__( arg ) @@ -843,7 +1005,7 @@ private function hDefQuoteZ_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum as end function -private function hDefQuoteW_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum as integer ptr ) as wstring ptr +private function hDefQuoteW_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum as integer ptr) as wstring ptr '' __FB_QUOTE__( arg ) @@ -901,7 +1063,7 @@ private function hDefUnquoteZ_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum a end function -private function hDefUnquoteW_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum as integer ptr ) as wstring ptr +private function hDefUnquoteW_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum as integer ptr) as wstring ptr '' __FB_UNQUOTE__( arg ) @@ -1324,7 +1486,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 +1513,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 +1616,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 +1655,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 +1693,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 From 392937ee900c94457b651bc989061e1428efe46c Mon Sep 17 00:00:00 2001 From: Jeff Marshall Date: Sat, 1 Jun 2024 07:23:27 -0400 Subject: [PATCH 2/3] fbc: clean-up whitespace --- src/compiler/symb-define.bas | 46 ++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/compiler/symb-define.bas b/src/compiler/symb-define.bas index 36d3f67f1..fded20c86 100644 --- a/src/compiler/symb-define.bas +++ b/src/compiler/symb-define.bas @@ -895,7 +895,7 @@ private function hDefArgLeft_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum as end function -private function hDefArgRight_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum as integer ptr) as string +private function hDefArgRight_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum as integer ptr ) as string '' __FB_ARG_RIGHTOF__( ARG, SEP [, RET = ""] ) @@ -940,7 +940,7 @@ private function hDefArgRight_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum a end function -private function hDefJoinZ_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum as integer ptr) as string +private function hDefJoinZ_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum as integer ptr ) as string '' __FB_JOIN__( L, R ) @@ -961,7 +961,7 @@ private function hDefJoinZ_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum as i end function -private function hDefJoinW_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum as integer ptr) as wstring ptr +private function hDefJoinW_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum as integer ptr ) as wstring ptr '' __FB_JOIN__( L, R ) @@ -982,7 +982,7 @@ private function hDefJoinW_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum as i end function -private function hDefQuoteZ_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum as integer ptr) as string +private function hDefQuoteZ_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum as integer ptr ) as string '' __FB_QUOTE__( arg ) @@ -1005,7 +1005,7 @@ private function hDefQuoteZ_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum as end function -private function hDefQuoteW_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum as integer ptr) as wstring ptr +private function hDefQuoteW_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum as integer ptr ) as wstring ptr '' __FB_QUOTE__( arg ) @@ -1063,7 +1063,7 @@ private function hDefUnquoteZ_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum a end function -private function hDefUnquoteW_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum as integer ptr) as wstring ptr +private function hDefUnquoteW_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum as integer ptr ) as wstring ptr '' __FB_UNQUOTE__( arg ) @@ -1487,7 +1487,7 @@ dim shared macroTb(0 to ...) as SYMBMACRO => _ (@"__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_ARG_LISTEXPAND__" , FB_DEFINE_FLAGS_VARIADIC , @hDefArgListExpandZ_cb , @hDefArgListExpandW_cb , 3, { (@"MACRONAME"), (@"MACROARGCOUNT"), (@"ARGS") } ) _ + (@"__FB_ARG_LISTEXPAND__" , FB_DEFINE_FLAGS_VARIADIC, @hDefArgListExpandZ_cb, @hDefArgListExpandW_cb , 3, { (@"MACRONAME"), (@"MACROARGCOUNT"), (@"ARGS") } ) _ } sub symbDefineInit _ @@ -1513,7 +1513,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 @@ -1616,11 +1616,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 @@ -1655,11 +1655,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 @@ -1693,11 +1693,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 From 60d77872cfd550004e7b873f40843a5e858bee65 Mon Sep 17 00:00:00 2001 From: Jeff Marshall Date: Sat, 1 Jun 2024 14:06:57 -0400 Subject: [PATCH 3/3] fbc: github # 426: add __FB_ARG_LISTEXPAND__( macroname, macroargcount, args... ) - tests added - only emit NEWLINE if the expansion is multiple source lines - fix pointers to string characters to use sizeof(wstring) since it will vary depending on host platform - 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 /' #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 '/ --- changelog.txt | 1 + src/compiler/hlp-str.bas | 15 +- src/compiler/symb-define.bas | 20 +- tests/pp/macro-arg-listexpand-utf16le.bas | Bin 0 -> 32380 bytes tests/pp/macro-arg-listexpand.bas | 574 ++++++++++++++++++++++ 5 files changed, 602 insertions(+), 8 deletions(-) create mode 100644 tests/pp/macro-arg-listexpand-utf16le.bas create mode 100644 tests/pp/macro-arg-listexpand.bas 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 4a8649c46..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 @@ -1333,7 +1341,7 @@ function hWStr2long( byref txt as wstring, byref value as long ) as integer return FALSE end if - dim s as ushort ptr = strptr(txt) + dim s as WSTRING_CHAR ptr = strptr(txt) if( s = NULL orelse *s = CHAR_NULL ) then return FALSE @@ -1628,10 +1636,9 @@ end function ''::::: function hWStr2Args( byval txt as const wstring ptr, res() as DWSTRING ) as integer - '' add the wstring version - dim as integer t = 0 - dim as const ushort ptr s = cast(const ushort ptr, txt) + 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 diff --git a/src/compiler/symb-define.bas b/src/compiler/symb-define.bas index fded20c86..a2c9a49de 100644 --- a/src/compiler/symb-define.bas +++ b/src/compiler/symb-define.bas @@ -747,6 +747,9 @@ private function hDefArgListExpandZ_cb( byval argtb as LEXPP_ARGTB ptr, byval er 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) @@ -754,10 +757,13 @@ private function hDefArgListExpandZ_cb( byval argtb as LEXPP_ARGTB ptr, byval er res &= "," end if next - res &= ")" & NEWLINE + 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 @@ -766,7 +772,7 @@ private function hDefArgListExpandZ_cb( byval argtb as LEXPP_ARGTB ptr, byval er res &= "," end if next - res &= ")" & NEWLINE + res &= ")" next end if end if @@ -812,6 +818,9 @@ private function hDefArgListExpandW_cb( byval argtb as LEXPP_ARGTB ptr, byval er 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 @@ -820,10 +829,13 @@ private function hDefArgListExpandW_cb( byval argtb as LEXPP_ARGTB ptr, byval er DWstrConcatAssign(res, "," ) end if next - DWstrConcatAssign(res, ")" & NEWLINE ) + 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) @@ -833,7 +845,7 @@ private function hDefArgListExpandW_cb( byval argtb as LEXPP_ARGTB ptr, byval er DWstrConcatAssign(res, "," ) end if next - DWstrConcatAssign(res, ")" & NEWLINE ) + DWstrConcatAssign(res, ")" ) next end if 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 0000000000000000000000000000000000000000..261a2b4f49b678ec84979611944637ced5371018 GIT binary patch literal 32380 zcmeI5ZEqAu49Dl~RqA&*6{!@_M0tKu6(pL{s#2kd2et1a9s)#4A<88c?T2q`uQQDQ zd%H8UUavr~it<3>^^N@-+yC9WJ^uUmS~v-B!t-z%F2jp(9G2m$@G?B3-(1q~Pr^mm zq<@{zZ@&y*G@p;clkiJ;9PWm1$XaZV$nH3-=n-}+ZYtSOO_Ao0?_XW=z?tJ}=ZNBO z*B^&H)n|0wBOkAKwyqMU5_^`!qb=i3kPg~!r)x!fjPXf@aD)$K`KQiGxmS(iTv55kY(PNTiQqkpr$_zLvoE&BH|e4UL~j=E3!{SWelN36#samN+5 zd;c}1@|WRWqby>~n{*DaNh=XG&pl<;sQEMMEh(E?-?JWOR!8*lQ}}_t-XRtCGkre{ zzftt}X}$b6)-Ul`Qb5pB1DvM0KU7ik^5fE7n&a*?LGTI#jFJY8dpb zMY6^#O7V8Bkk3n|TH&_K3i-Tfsuk|ItdP&jrdr{y%L?}=T;bl}6&_MOaeY0akGoW5 zkDIEB71-C~bcSD(hkm`so|1LyA6)OL16;e(8R=R9SBg}Nbim)KqEG2#NtWmI@s>XM z4D6VC$x}Kj<1>zU=E6NzIs<=yL$?Ot?c+P&!Nv3ofn`f*p6+ zCm%mPoHl|Fsg2;nY9sj2+Mp|fG0#$0Tz_1JtN>UG{6keOR~R*sMfU2A%xtu`)R_2@ zYm#wKEl3@7^;PbtT5;&}SXMl^nmQjzbyz)U-P87Q_o~CijFG;}|xp@H^3G=z#JAO2J@zHwB9%@{hm%hu3AdtW+2$&w#` zN*JdPrATWGFFnm_c%l6?yo8%2WB%MQUTxJnBpi-!`WNUJno7R~h^eg2tv;S4PELi=fW z`Dp}Pt%aM#Lp`@du*@*05_Sfu1i5lOUL}a1StYCj=O3qIu975gXm6>clz%^!fV;v{ zF&I~!hrWuj%^{|NQ?X0~?R{wYsRT<-QM+M$2EJXh(?NS*IcV*IJd~;{R@qiaKaEof zdqfgDNsgqvf(z{}B*o9H5?0jphNuL|8}7|<`JYvSRtZc4r((Gp(B6l}tP=1QRHEUS z4o>|t9klnQ? z`^_tj(cVH*{LCt0MO8FJB}m@JtAv#QStV$dz%+2`m#YEo$5lh5A>Wa6UFY|Ibrr@} zw~EsIu}vMOgVV4~2km|72qjB?{3&6aK9tg#sGS#1{W34KpN5xkvt-Pl8^-I+EfE}d zE#Y90N;q&*3F2o~2`jn}Wr#|Uyy5h)R8q=+oJ*+>e7HMJFs^YGlj0fj`Z%V6T|d{? zB#UV8Lt|D6UDpzr4)*pk9klnQGpmIBGY-rPr(l^E+E2r4Rtfdj68L=^UJbm*f$w7F z9FM=65IucLN@0uczmpH0pSmfPXyB~O)m6+P9$~4h=!t1a4e1E1x&hZ!H}&y4>Q3{_ zTAKK^D`}t03Y8t$w?nz08mQrdM|g1&K9=0J&xCM&7CyVg$CJ@6dDA;@C?nJaHH`2G zZ$`q(lIJ!nT&IQA9aXuhHX>`IEPB=$vIN=dfaS~p*Cv3bd%(1RmDR|WutAo1Q$|(eX zWvZs0eD~D-_Syooz-rD{k=H#Ck*e>t1>7Tb6^GS=xv2B7-r1On zeF8BPtos@!c*NNHkPa5#b;OdDwn7-s1|zhyVKRC(L(~DY!M0}P2bKW5p#4K=UQA@9`{}?6^Mr5rZxniJw z4XL1EcR55BxFg51kV?@J)b7uArC5AmrC?-ZnAlapuzMXM6PyZOOoWXkEB2>Uc&~D@MbeBf^|kX?P?g|5mPbxTonQ9fv6PH{~XW1{U5!#xH13$ literal 0 HcmV?d00001 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