Subject: assert
From: "Per Hedbor () @ Pike (-) importmöte för mailinglistan" <6341@lyskom.lysator.liu.se>
Date: Fri, 3 May 2013 AD 15:00:02 -0400
> Does anyone happen to have any boilerplate code they use to handle
> assertions in pike? I know that it's pretty easy to put one
> together, I just figured if there was a popular version floating
> around, I'd use that rather than rolling my own.
I know of no popular versions, really.
In our project (Opera Mini) we use the "new" define functionality,
combined with a loader.
Basically, we have code that add macros that expand to suitable things
depending on the debug level setting. This must be called before the
main code is compiled.
| // loader, normally named after the program
| int main( int argc, array argv )
| {
| // Read debug settings
| int level = read_setting( "debug" );
|
| // Initialize the debug macros etc.
| _DEBUG.init( level );
|
| // Pass control to a newly compiled main file.
| return compile_file( "main.pike" )->main( argc, argv );
| }
It would be nice to do away with the loader, but that requires a
modified master (basically, add the DEBUG, IFDEBUG and assert() macros
to the base language, and read the debug level setting).
Especially reading the debug level setting is something that does not
really belong to the pike core language, since how you want that to be
done varies from project to project.
The main advantage of this method is that it automatically removes the
debug code when debug is not enabled, it is at least a small saving in
performance, and you do not have to be quite as careful with things
passed as arguments to DEBUG().
I have extracted some of the debug code we use to _DEBUG.pmod
below. No guarantees for it's suitability for other projects given. No
documentation included for now.
->->->->->->->->->-> _DEBUG.pmod START ->->->->->->->->->->
int debug = 0;
void _DEBUG( object ths, int line, mixed format, mixed ... args )
{
if( !stringp( format ) )
{
format = "%O";
args = ({ format });
}
if( sizeof( args ) )
format = sprintf(format, @args );
if( format[-1] == '\n' )
format = format[..<1];
// Use as short a name as possible.
string name = ths->module_name || sprintf("%O", ths );
while(sscanf(name, "%*s/%s", name ) );
if( name[-1] == '#' )
name = name[..<1];
string header = sprintf("%s:%-4d | ",name,line);
foreach( format /"\n", string line )
werror(header+line+"\n");
}
string expand_assert( string ... args )
{
string code = args*",";
// This is debatable. The code in assert() is kept even when asserts
// are disabled.
if( debug < 0 ) return code;
return
"do if(!("+code+")) {"
" exit(1,\"%s:%d: %s\\n\", __FILE__,__LINE__,\"Assertion \" "+
sprintf("%q",code)+" \" failed\");"
"} while(0)";
}
function(string...:string) expand_debug( string pre, string post )
{
return lambda( string ... args ) {
int level = 1;
if( (int)args[0] )
{
level = (int)args[0];
args = args[1..];
}
if( debug < level )
return "";
return pre + args*","+ post;
};
}
void set_debug( int level )
{
// Can be used to change debug level for newly compiled code.
debug = level;
}
void init(int level)
{
set_debug( level );
master()->add_predefine( "assert()", expand_assert);
master()->add_predefine( "IFDEBUG()", expand_debug("","") );
master()->add_predefine( "DEBUG()",
expand_debug("_DEBUG._DEBUG(this,__LINE__,",")") );
}
->->->->->->->->->-> _DEBUG.pmod END ->->->->->->->->->->
A simple test-case:
void main()
{
_DEBUG.init( 1 );
compile_string( "void foo(){ DEBUG( \"Simple debug message\" );}",
"testcase" )()->foo();
compile_string( "void foo(){ assert( 1 == 2 ); }", "testcase" )()->foo();
}
--
Per Hedbor
Return to results