
* new/targets.jam (main-target.select-alternatives): New rule. (main-target.generate): Simplify, using the above. * new/errors.jam (error): Do EXIT if --no-error-backtrace is given. * tests/alternatives.py: New test. [SVN r17673]
208 lines
5.6 KiB
Plaintext
208 lines
5.6 KiB
Plaintext
# (C) Copyright David Abrahams 2001. Permission to copy, use, modify, sell and
|
|
# distribute this software is granted provided this copyright notice appears in
|
|
# all copies. This software is provided "as is" without express or implied
|
|
# warranty, and with no claim as to its suitability for any purpose.
|
|
|
|
# Print a stack backtrace leading to this rule's caller. Each
|
|
# argument represents a line of output to be printed after the first
|
|
# line of the backtrace.
|
|
rule backtrace ( skip-frames messages * : * )
|
|
{
|
|
local frame-skips = 5 9 13 17 21 25 29 33 37 41 45 49 53 57 61 65 69 73 77 81 ;
|
|
local drop-elements = $(frame-skips[$(skip-frames)]) ;
|
|
if ! ( $(skip-frames) in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 )
|
|
{
|
|
ECHO warning: backtrace doesn't support skipping
|
|
$(skip-frames) frames; using 1 instead. ;
|
|
drop-elements = 5 ;
|
|
}
|
|
|
|
# get the whole backtrace, then drop the initial quadruples
|
|
# corresponding to the frames that must be skipped.
|
|
local bt = [ BACKTRACE ] ;
|
|
bt = $(bt[$(drop-elements)-]) ;
|
|
|
|
local args = $(.args) ;
|
|
while $(bt)
|
|
{
|
|
local m = [ MATCH ^(.+)\\.$ : $(bt[3]) ] ;
|
|
ECHO $(bt[1]):$(bt[2]): "in" $(bt[4]) "from module" $(m) ;
|
|
|
|
# the first time through, print each argument on a separate
|
|
# line
|
|
for local n in $(args)
|
|
{
|
|
if $($(n))-is-not-empty
|
|
{
|
|
ECHO $($(n)) ;
|
|
}
|
|
}
|
|
args = ; # kill args so that this never happens again
|
|
|
|
# Move on to the next quadruple
|
|
bt = $(bt[5-]) ;
|
|
}
|
|
}
|
|
|
|
.args ?= messages 2 3 4 5 6 7 8 9 ;
|
|
.disabled ?= ;
|
|
.last-error-$(.args) ?= ;
|
|
|
|
# try-catch --
|
|
#
|
|
# This is not really an exception-handling mechanism, but it does
|
|
# allow us to perform some error-checking on our
|
|
# error-checking. Errors are suppressed after a try, and the first one
|
|
# is recorded. Use catch to check that the error message matched
|
|
# expectations.
|
|
|
|
# begin looking for error messages
|
|
rule try ( )
|
|
{
|
|
.disabled += true ;
|
|
.last-error-$(.args) = ;
|
|
}
|
|
|
|
# stop looking for error messages; generate an error if an argument of
|
|
# messages is not found in the corresponding argument in the error call.
|
|
rule catch ( messages * : * )
|
|
{
|
|
.disabled = $(.disabled[2-]) ; # pop the stack
|
|
|
|
import sequence ;
|
|
|
|
if ! $(.last-error-$(.args))-is-nonempty
|
|
{
|
|
error-skip-frames 3 expected an error, but none occurred ;
|
|
}
|
|
else
|
|
{
|
|
for local n in $(.args)
|
|
{
|
|
if ! $($(n)) in $(.last-error-$(n))
|
|
{
|
|
local v = [ sequence.join $($(n)) : " " ] ;
|
|
v ?= "" ;
|
|
local joined = [ sequence.join $(.last-error-$(n)) : " " ] ;
|
|
|
|
.last-error-$(.args) = ;
|
|
error-skip-frames 3 expected \"$(v)\" in argument $(n) of error
|
|
: got \"$(joined)\" instead ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
rule error-skip-frames ( skip-frames messages * : * )
|
|
{
|
|
if ! $(.disabled)
|
|
{
|
|
backtrace $(skip-frames) error: $(messages) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ;
|
|
EXIT ;
|
|
}
|
|
else if ! $(.last-error-$(.args))
|
|
{
|
|
for local n in $(.args)
|
|
{
|
|
# Add an extra empty string so that we always have
|
|
# something in the event of an error
|
|
.last-error-$(n) = $($(n)) "" ;
|
|
}
|
|
}
|
|
}
|
|
|
|
if --no-error-backtrace in [ modules.peek : ARGV ]
|
|
{
|
|
.no-error-backtrace = true ;
|
|
}
|
|
|
|
|
|
# Print an error message with a stack backtrace and exit.
|
|
rule error ( messages * : * )
|
|
{
|
|
if $(.no-error-backtrace)
|
|
{
|
|
# Print each argument on a separate line.
|
|
for local n in $(.args)
|
|
{
|
|
if $($(n))-is-not-empty
|
|
{
|
|
if ! $(first-printed)
|
|
{
|
|
ECHO error: $($(n)) ;
|
|
first-printed = true ;
|
|
}
|
|
else
|
|
{
|
|
ECHO $($(n)) ;
|
|
}
|
|
}
|
|
}
|
|
EXIT ;
|
|
}
|
|
else
|
|
{
|
|
error-skip-frames 3 $(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ;
|
|
}
|
|
}
|
|
|
|
# Print a warning message with a stack backtrace and exit.
|
|
rule warning
|
|
{
|
|
backtrace 2 warning: $(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ;
|
|
}
|
|
|
|
# convert an arbitrary argument list into a list with ":" separators
|
|
# and quoted elements representing the same information. This is
|
|
# mostly useful for formatting descriptions of the arguments with
|
|
# which a rule was called when reporting an error.
|
|
rule lol->list ( * )
|
|
{
|
|
local result ;
|
|
local remaining = 1 2 3 4 5 6 7 8 9 ;
|
|
while $($(remaining))
|
|
{
|
|
local n = $(remaining[1]) ;
|
|
remaining = $(remaining[2-]) ;
|
|
|
|
if $(n) != 1
|
|
{
|
|
result += ":" ;
|
|
}
|
|
result += \"$($(n))\" ;
|
|
}
|
|
return $(result) ;
|
|
}
|
|
|
|
rule __test__ ( )
|
|
{
|
|
# show that we can correctly catch an expected error
|
|
try ;
|
|
{
|
|
error an error occurred : somewhere ;
|
|
}
|
|
catch an error occurred : somewhere ;
|
|
|
|
# show that unexpected errors generate real errors
|
|
try ;
|
|
{
|
|
try ;
|
|
{
|
|
error an error occurred : somewhere ;
|
|
}
|
|
catch an error occurred : nowhere ;
|
|
}
|
|
catch expected \"nowhere\" in argument 2 ;
|
|
|
|
# show that not catching an error where one was expected is an
|
|
# error
|
|
try ;
|
|
{
|
|
try ;
|
|
{
|
|
}
|
|
catch ;
|
|
}
|
|
catch expected an error, but none occurred ;
|
|
}
|