1 /* This file is part of Shapes.
3 * Shapes is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
8 * Shapes is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with Shapes. If not, see <http://www.gnu.org/licenses/>.
16 * Copyright 2008, 2009 Henrik Tidefelt
21 #include "breakpoints.h"
22 #include "shapescore.h"
24 using namespace Shapes
;
25 using namespace SimplePDF
;
31 class VoidExpression
: public Expression
34 VoidExpression( const Ast::SourceLocation
& loc
);
35 virtual ~VoidExpression( );
36 virtual void analyze_impl( Ast::Node
* parent
, Ast::AnalysisEnvironment
* env
, Ast::StateIDSet
* freeStatesDst
);
37 virtual void eval( Kernel::EvalState
* evalState
) const;
43 bool theInteractionDone
= false;
45 class InteractionContinuation
: public Kernel::Continuation
47 Ast::AnalysisEnvironment
* parentAnalysisEnv_
;
48 mutable Ast::CodeBracket
* bracket_
;
49 mutable Kernel::Environment
* env_
;
50 Kernel::ContRef resume_
;
51 Kernel::PassedDyn dyn_
;
52 Ast::Expression
* breakExpr_
;
56 std::string outputName_
;
59 InteractionContinuation( Ast::AnalysisEnvironment
* parentAnalysisEnv
, Ast::CodeBracket
* bracket
, Kernel::Environment
* env
, Kernel::ContRef resume
, const Kernel::PassedDyn
& dyn
, Ast::Expression
* breakExpr
, int result_inputNo
, std::istream
& is
, std::ostream
& os
, const std::string
& outputName
, SplitMode splitMode
, const Ast::SourceLocation
& traceLoc
);
60 InteractionContinuation( Kernel::EvalState
& evalState
, int result_inputNo
, std::istream
& is
, std::ostream
& os
, const std::string
& outputName
, SplitMode splitMode
); // set up new dynamic and lexical environment for debugging an error at evalState
61 ~InteractionContinuation( );
62 RefCountPtr
< Kernel::InteractionContinuation
> cloneWithNewContinuation( Kernel::ContRef resume
, Kernel::WarmDebugger
* state
);
63 void setDyn( const Kernel::PassedDyn
& dyn
);
64 bool reusable( Kernel::EvalState
& evalState
) const;
65 virtual void takeValue( const RefCountPtr
< const Lang::Value
> & val
, Kernel::EvalState
* evalState
, bool dummy
) const;
66 virtual Kernel::ContRef
up( ) const;
67 virtual RefCountPtr
< const char > description( ) const;
68 virtual void gcMark( Kernel::GCMarkedSet
& marked
);
70 Kernel::ContRef
resume( ) const { return resume_
; } /* For debug backtraces and to skip continuations. */
72 void showValue( const RefCountPtr
< const Lang::Value
> & resultUntyped
) const;
75 class ExitInteractionContinuation
: public Kernel::Continuation
80 ExitInteractionContinuation( bool * done
, int * exitCode
, const Ast::SourceLocation
& traceLoc
);
81 ~ExitInteractionContinuation( );
82 virtual void takeValue( const RefCountPtr
< const Lang::Value
> & val
, Kernel::EvalState
* evalState
, bool dummy
) const;
83 virtual Kernel::ContRef
up( ) const;
84 virtual RefCountPtr
< const char > description( ) const;
85 virtual void gcMark( Kernel::GCMarkedSet
& marked
);
91 typedef enum { EXPR
, STEP
} StepMode
;
95 Ast::SourceLocation refLoc_
;
98 : active_( false ), mode_( EXPR
), refLoc_( Ast::THE_UNKNOWN_LOCATION
), count_( 1 )
100 bool stop( const Ast::SourceLocation
& loc
)
105 /* Stop at everything. No need to update refLoc_ . */
109 if( refLoc_
.contains( loc
) )
127 const int NO_INPUT_INPUT_NO
= std::numeric_limits
< int >::max( );
128 bool interactive_debug
= true;
129 typedef typeof Ast::theInteractiveInput InputType
;
130 std::vector
< InputType
> interactive_history
;
131 std::set
< Ast::Expression
* > theBreakpoints
; /* This set shall contain all expressions that have a Kernel::BreakpointInfo, incloding also those thare are not enabled. */
132 std::set
< Ast::Expression
* > theTemporaryBreakpoints
; /* This set shall be a subset of theBreakpoints, and contain the breakpoints that should be reset when evaluation is interrupted. */
133 DebugStepInfo theDebugStepInfo
;
134 Ast::VoidExpression
* theVoidExpression
= new Ast::VoidExpression( Ast::THE_UNKNOWN_LOCATION
); /* Order of initializaiton of globals?! */
139 const char * CONTINUATION_TOP_REPL_ID
= "top_repl";
144 interactiveEvaluation( std::istream
& in
, std::ostream
& out
, const std::string
& outputName
, SplitMode splitMode
,
145 bool evalTrace
, bool evalBackTrace
, bool cleanupMemory
,
146 RefCountPtr
< std::ifstream
> & labelDBFile
, const std::string
& labelDBName
)
148 /* Clean up outout from earlier sessions. */
155 rmSplitFiles( outputName
, "-" );
160 mkSplitDir( outputName
);
161 rmSplitFiles( outputName
, "/" );
166 RefCountPtr
< const Kernel::GraphicsState
> graphicsState( new Kernel::GraphicsState( true ) );
167 Kernel::PassedDyn
baseDyn( new Kernel::DynamicEnvironment( graphicsState
) );
171 /* Evaluate preamble. */
173 initCore( labelDBFile
, labelDBName
);
176 Kernel::ValueRef resultUntyped
= NullPtr
< const Lang::Value
>( );
177 Kernel::EvalState
evalState( Ast::theProgram
,
178 Kernel::theGlobalEnvironment
,
180 Kernel::ContRef( new Kernel::StoreValueContinuation( & resultUntyped
,
181 Kernel::ContRef( new Kernel::ExitContinuation( & done
, Ast::theProgram
->loc( ) ) ),
182 Ast::theProgram
->loc( ) ) ) );
185 Ast::Expression
* expr
= evalState
.expr_
;
186 expr
->eval( & evalState
);
189 catch( const Exceptions::StaticInconsistency
& ball
)
192 std::cerr
<< ball
.loc( ) << ": " ;
193 ball
.display( std::cerr
);
194 std::cerr
<< "There were errors in the preamble. Aborting interactive evaluation." ;
195 abortProcedure( ball
.exitCode( ) );
197 catch( const Exceptions::Exception
& ball
)
200 ball
.display( std::cerr
);
201 std::cerr
<< "There were errors in the preamble. Aborting interactive evaluation." ;
202 abortProcedure( ball
.exitCode( ) );
205 Ast::theShapesScanner
.setInteractive( true ); /* Do this after reading the preamble! */
207 /* Find the prelude environment... */
208 Kernel::Environment
* preludeEnv
= 0;
209 for( std::list
< Kernel::Environment
* >::iterator e
= Kernel::theEnvironmentList
.begin( ); e
!= Kernel::theEnvironmentList
.end( ); ++e
)
213 if( (*e
)->getParent( ) == Kernel::theGlobalEnvironment
)
219 catch( const Exceptions::MiscellaneousRequirement
& ball
)
221 /* That was the global environment, which doesn't have a parent. Never mind. */
224 if( preludeEnv
== 0 )
226 std::cerr
<< "Internal error: Failed to locate prelude environment." << std::endl
;
227 exit( Interaction::EXIT_INTERNAL_ERROR
);
229 Ast::AnalysisEnvironment
* preludeAnalysisEnvironment
= preludeEnv
->newAnalysisEnvironment( Ast::theGlobalAnalysisEnvironment
);
231 Ast::CodeBracket
* initialBracket( new Ast::CodeBracket( Ast::SourceLocation( Ast::FileID::build_internal( "{ interactive }" ) ), new std::list
< Ast::Node
* >( ) ) );
233 Ast::StateIDSet freeStates
;
234 initialBracket
->analyze( Ast::theProgram
, preludeAnalysisEnvironment
, & freeStates
);
236 Kernel::Environment
* bracketEnv
= initialBracket
->newEnvironment( preludeEnv
, "Interaction" );
237 bracketEnv
->initDefine( "db", new Kernel::WarmDebugger( bracketEnv
, baseDyn
, Kernel::ContRef( NullPtr
< Kernel::Continuation
>( ) ), 0 ) );
239 int exitCode
= Interaction::EXIT_OK
;
241 RefCountPtr
< Kernel::InteractionContinuation
> interactionCont
242 ( new Kernel::InteractionContinuation( preludeAnalysisEnvironment
, initialBracket
, bracketEnv
, Kernel::ContRef( NullPtr
< Kernel::Continuation
>( ) ), baseDyn
, 0, Kernel::NO_INPUT_INPUT_NO
,
243 in
, out
, outputName
, splitMode
,
244 initialBracket
->loc( ) ) );
245 Kernel::PassedDyn
interactionDyn( new Kernel::DynamicEnvironment( Kernel::PassedDyn( new Kernel::DynamicEnvironment( baseDyn
, "bye", Kernel::ContRef( new Kernel::ExitInteractionContinuation( & Kernel::theInteractionDone
, & exitCode
, initialBracket
->loc( ) ) ) ) ),
246 Lang::CONTINUATION_TOP_REPL_ID
, interactionCont
) );
247 interactionCont
->setDyn( interactionDyn
);
249 Kernel::EvalState
evalState( Kernel::theVoidExpression
, /* This will invoke the continuation first thing. */
250 Kernel::theGlobalEnvironment
, /* Dummy value */
251 baseDyn
, /* Dummy value */
254 while( ! Kernel::theInteractionDone
)
256 Ast::Expression
* expr
= evalState
.expr_
;
257 if( Kernel::theDebugStepInfo
.active_
&& Kernel::theDebugStepInfo
.stop( expr
->loc( ) ) )
259 out
<< "Reached " << expr
->loc( ) << "." << std::endl
;
260 evalState
.cont_
= Kernel::ContRef( new Kernel::InteractionContinuation( evalState
, Kernel::NO_INPUT_INPUT_NO
, in
, out
, outputName
, splitMode
) );
261 evalState
.expr_
= Kernel::theVoidExpression
;
262 Kernel::theDebugStepInfo
.active_
= false;
265 if( expr
->breakpoint_
!= 0 && expr
->breakpoint_
->enabled_
)
267 if( expr
->breakpoint_
->ignoreCount_
> 0 )
269 /* Don't break this time, but re-enable breaking in the future. */
270 --(expr
->breakpoint_
->ignoreCount_
);
274 out
<< "Stopping at breakpoint " << expr
->loc( ) << "." << std::endl
;
275 typedef typeof Kernel::theTemporaryBreakpoints SetType
;
276 for( SetType::iterator i
= Kernel::theTemporaryBreakpoints
.begin( ); i
!= Kernel::theTemporaryBreakpoints
.end( ); ++i
)
278 if( (*i
)->breakpoint_
->createdForTemporaryUse_
)
280 delete (*i
)->breakpoint_
;
281 (*i
)->breakpoint_
= 0;
282 Kernel::theBreakpoints
.erase( *i
);
286 (*i
)->breakpoint_
->enabled_
= (*i
)->breakpoint_
->persistentEnabled_
;
289 Kernel::theTemporaryBreakpoints
.clear( );
290 evalState
.cont_
= Kernel::ContRef( new Kernel::InteractionContinuation( evalState
, Kernel::NO_INPUT_INPUT_NO
, in
, out
, outputName
, splitMode
) );
291 evalState
.expr_
= Kernel::theVoidExpression
;
292 Kernel::theDebugStepInfo
.active_
= false;
301 expr
->eval( & evalState
);
303 catch( const Exceptions::CatchableError
& ball
)
305 Kernel::ContRef cont
= evalState
.dyn_
->getEscapeContinuation( Lang::CONTINUATION_ID_ERROR
, ball
.getLoc( ) );
306 cont
->takeValue( ball
.clone( evalState
.cont_
),
311 catch( const Exceptions::StaticInconsistency
& ball
)
314 out
<< ball
.loc( ) << ": " ;
317 catch( const Exceptions::Exception
& ball
)
320 if( Interaction::debugBacktrace
)
322 evalState
.cont_
->backTrace( out
);
325 const Exceptions::RuntimeError
& rerr
= dynamic_cast< const Exceptions::RuntimeError
& >( ball
);
326 if( & rerr
!= 0 && ! rerr
.getLoc( ).isUnknown( ) )
328 out
<< rerr
.getLoc( ) << Exceptions::Exception::locsep
;
332 out
<< evalState
.cont_
->traceLoc( ) << Exceptions::Exception::locsep
;
336 if( Kernel::interactive_debug
)
338 Kernel::InteractionContinuation
* iCont
= dynamic_cast< Kernel::InteractionContinuation
* >( evalState
.cont_
.getPtr( ) );
339 if( iCont
!= 0 && iCont
->reusable( evalState
) )
341 /* We don't create a new interactive continuation if the active continuation is already an interactive continuation.
342 * For instance, failing to set a breakpoint is not something that's interesting to debug in itself.
344 out
<< "Reusing interactive continuation." << std::endl
;
346 else if( evalState
.expr_
!= 0 )
348 evalState
.cont_
= Kernel::ContRef( new Kernel::InteractionContinuation( evalState
, Kernel::NO_INPUT_INPUT_NO
, in
, out
, outputName
, splitMode
) );
352 /* We interpret this situation as a failure to explicitly apply a continuation.
353 * See ContinueDynamicECFunction::call .
355 evalState
.cont_
= Kernel::ContRef( new Kernel::InteractionContinuation
356 ( preludeAnalysisEnvironment
, initialBracket
, bracketEnv
, evalState
.cont_
,
357 Kernel::PassedDyn( new Kernel::DynamicEnvironment( baseDyn
, "resume", evalState
.cont_
) ),
359 Kernel::NO_INPUT_INPUT_NO
,
360 in
, out
, outputName
, splitMode
,
361 initialBracket
->loc( ) ) );
366 evalState
.cont_
= interactionCont
;
368 Kernel::theDebugStepInfo
.active_
= false;
369 evalState
.expr_
= Kernel::theVoidExpression
;
372 /* Someone ended the input stream or invoked the exit continuation.
373 * For now, we circumvent the normal termination procedures in <main> by exiting here,
374 * which is similar to stopping the program by pressing ctrl-c, which is probably what
375 * most people will do anyway.
381 Interaction::InteractionFormats::InteractionFormats( )
382 : prompt_( "[%!#!!3R] " ),
383 show_( "%!#!!3R ⇒ " ),
389 Interaction::InteractionFormats::setPrompt( const char * format
)
395 Interaction::InteractionFormats::setShow( const char * format
)
401 Interaction::InteractionFormats::setFile( const char * format
)
407 Interaction::InteractionFormats::setBye( const char * format
)
413 Interaction::InteractionFormats::formatPrompt( std::ostream
& os
, size_t inputNo
) const
415 writePrompt( os
, prompt_
, inputNo
);
419 Interaction::InteractionFormats::formatShow( std::ostream
& os
, size_t inputNo
) const
421 writePrompt( os
, show_
, inputNo
);
425 Interaction::InteractionFormats::formatFile( std::ostream
& os
, size_t inputNo
) const
427 writePrompt( os
, file_
, inputNo
);
431 Interaction::InteractionFormats::formatBye( std::ostream
& os
, size_t inputNo
) const
433 writePrompt( os
, bye_
, inputNo
);
437 Interaction::InteractionFormats::writePrompt( std::ostream
& os
, const char * format
, size_t inputNo
) const
439 for( const char * src
= format
; *src
!= '\0'; ++src
)
444 const char sep
= *src
;
446 std::ostringstream noStr
;
451 std::cerr
<< "Bad interactive prompt format string (expected second '" << sep
<< "'): " << format
<< std::endl
;
452 exit( Interaction::EXIT_INVOCATION_ERROR
);
457 writeEscape( noStr
, *src
);
471 std::cerr
<< "Bad interactive prompt format string (expected third '" << sep
<< "'): " << format
<< std::endl
;
472 exit( Interaction::EXIT_INVOCATION_ERROR
);
477 writeEscape( noStr
, *src
);
487 int width
= strtol( src
, & endp
, 10 );
492 else if( width
< 0 || width
> 10 )
494 std::cerr
<< "Bad interactive prompt format string (the width " << width
<< " is out of the range [0,10]): " << format
<< std::endl
;
495 exit( Interaction::EXIT_INVOCATION_ERROR
);
502 os
.setf(std::ios::left
);
505 os
.setf(std::ios::right
);
508 std::cerr
<< "Bad interactive prompt format string (expected 'L' or 'R' after '%'): " << format
<< std::endl
;
509 exit( Interaction::EXIT_INVOCATION_ERROR
);
513 os
<< std::setw(width
) ;
517 else if( *src
== '\\' )
520 writeEscape( os
, *src
);
530 Interaction::InteractionFormats::writeEscape( std::ostream
& os
, char c
) const
554 Ast::VoidExpression::VoidExpression( const Ast::SourceLocation
& loc
)
555 : Ast::Expression( loc
)
558 Ast::VoidExpression::~VoidExpression( )
562 Ast::VoidExpression::analyze_impl( Ast::Node
* parent
, Ast::AnalysisEnvironment
* env
, Ast::StateIDSet
* freeStatesDst
)
568 Ast::VoidExpression::eval( Kernel::EvalState
* evalState
) const
570 Kernel::ContRef cont
= evalState
->cont_
;
571 cont
->takeValue( Lang::THE_VOID
,
575 Kernel::InteractionContinuation::InteractionContinuation( Ast::AnalysisEnvironment
* parentAnalysisEnv
, Ast::CodeBracket
* bracket
, Kernel::Environment
* env
, Kernel::ContRef resume
, const Kernel::PassedDyn
& dyn
, Ast::Expression
* breakExpr
, int result_inputNo
, std::istream
& is
, std::ostream
& os
, const std::string
& outputName
, SplitMode splitMode
, const Ast::SourceLocation
& traceLoc
)
576 : Kernel::Continuation( traceLoc
), parentAnalysisEnv_( parentAnalysisEnv
), bracket_( bracket
), env_( env
), resume_( resume
), dyn_( dyn
), breakExpr_( breakExpr
), result_inputNo_( result_inputNo
), is_( is
), os_( os
), outputName_( outputName
), splitMode_( splitMode
)
579 Ast::SourceLocation
debug_loc( Ast::FileID::build_internal( "{ debug }" ) );
581 Kernel::InteractionContinuation::InteractionContinuation( Kernel::EvalState
& evalState
, int result_inputNo
, std::istream
& is
, std::ostream
& os
, const std::string
& outputName
, SplitMode splitMode
)
582 : Kernel::Continuation( evalState
.expr_
->loc( ) ),
583 parentAnalysisEnv_( evalState
.expr_
->getEnv( ) ),
584 bracket_( new Ast::CodeBracket( debug_loc
, new std::list
< Ast::Node
* >( ) ) ),
585 env_( bracket_
->newEnvironment( evalState
.env_
, "Debug" ) ),
586 resume_( evalState
.cont_
),
587 dyn_( new Kernel::DynamicEnvironment( evalState
.dyn_
, "resume", resume_
) ),
588 breakExpr_( evalState
.expr_
),
589 result_inputNo_( result_inputNo
),
590 is_( is
), os_( os
), outputName_( outputName
), splitMode_( splitMode
)
593 Ast::StateIDSet freeStates
;
594 bracket_
->analyze( evalState
.expr_
, parentAnalysisEnv_
, & freeStates
);
596 env_
->initDefine( "db", new Kernel::WarmDebugger( env_
, dyn_
, resume_
, breakExpr_
) );
597 env_
->initDefineHandle( "expr", Kernel::VariableHandle( new Kernel::Variable( new Kernel::Thunk( evalState
.env_
, evalState
.dyn_
, evalState
.expr_
) ) ) );
600 Kernel::InteractionContinuation::~InteractionContinuation( )
603 RefCountPtr
< Kernel::InteractionContinuation
>
604 Kernel::InteractionContinuation::cloneWithNewContinuation( Kernel::ContRef resume
, Kernel::WarmDebugger
* state
)
607 state
->dyn_
= Kernel::PassedDyn( new Kernel::DynamicEnvironment( dyn_
, "resume", resume
) );
608 state
->breakExpr_
= breakExpr_
;
609 state
->resume_
= resume
;
610 return RefCountPtr
< Kernel::InteractionContinuation
>
611 ( new Kernel::InteractionContinuation( parentAnalysisEnv_
, bracket_
, state
->env_
, resume
,
615 is_
, os_
, outputName_
, splitMode_
,
620 Kernel::InteractionContinuation::setDyn( const Kernel::PassedDyn
& dyn
)
626 Kernel::InteractionContinuation::reusable( Kernel::EvalState
& evalState
) const
628 return env_
== evalState
.env_
&& dyn_
== evalState
.dyn_
;
632 Kernel::InteractionContinuation::takeValue( const RefCountPtr
< const Lang::Value
> & val
, Kernel::EvalState
* evalState
, bool dummy
) const
634 Kernel::theDebugStepInfo
.active_
= false;
637 size_t debugDepth
= 0;
639 Kernel::ContRef tmp
= evalState
->cont_
;
640 while( tmp
!= NullPtr
< Kernel::Continuation
>( ) )
642 RefCountPtr
< Kernel::InteractionContinuation
> inter
= tmp
.down_cast
< Kernel::InteractionContinuation
>( );
643 if( inter
!= NullPtr
< Kernel::InteractionContinuation
>( ) )
645 tmp
= inter
->resume_
;
646 if( tmp
!= NullPtr
< Kernel::Continuation
>( ) )
660 /* As long as we fail to return, we ask for new input... */
664 for( size_t i
= 0; i
< debugDepth
; ++i
)
674 const Ast::FileID
* fileID
= Ast::FileID::build_fresh_inMemory( );
675 int interactive_inputNo
= fileID
->inMemoryIndex( );
676 std::ostringstream inputBuf
;
679 interactionFormats
.formatPrompt( os_
, interactive_inputNo
);
681 std::getline( is_
, line
);
684 interactionFormats
.formatBye( os_
, interactive_inputNo
);
685 Kernel::theInteractionDone
= true;
688 if( line
.length( ) > 1 && line
[ line
.length( ) - 1] == ' ' )
690 inputBuf
<< line
.substr( 0, line
.length( ) - 1 ) << '\n' ;
698 std::string line
= inputBuf
.str( );
699 if( line
.length( ) > 1 && line
[0] == ':' )
701 line
= "#db.[" + line
.substr(1) + "]";
704 const_cast< Ast::FileID
* >( fileID
)->setMem( strdup( line
.c_str( ) ) );
705 std::istringstream
inLine( line
+ "\n" );
706 Ast::theShapesScanner
.queueStream( & inLine
, fileID
);
707 Ast::theShapesScanner
.start( );
711 interactive_history
.push_back( Ast::theInteractiveInput
);
712 Ast::CodeBracket
* extension
= new Ast::CodeBracket( bracket_
->loc( ), Ast::theInteractiveInput
, bracket_
);
714 Ast::StateIDSet freeStates
;
715 extension
->analyze( Ast::theProgram
, parentAnalysisEnv_
, & freeStates
);
717 if( ! Ast::theAnalysisErrorsList
.empty( ) )
720 typedef typeof Ast::theAnalysisErrorsList ListType
;
721 for( ListType::const_iterator i
= Ast::theAnalysisErrorsList
.begin( ); i
!= Ast::theAnalysisErrorsList
.end( ); ++i
)
724 typedef const Exceptions::StaticInconsistency ErrorType
;
725 ErrorType
* err
= dynamic_cast< ErrorType
* >( *i
);
728 std::cerr
<< err
->loc( ) << ": " ;
729 err
->display( std::cerr
);
733 std::cerr
<< "(Bad exception type)" << ": " ;
734 (*i
)->display( std::cerr
);
736 Ast::theAnalysisErrorsList
.clear( );
742 // evalState->env_ = env_; /* Not needed since extension->eval handles this. */
743 evalState
->dyn_
= dyn_
;
744 /* For the continuation, we make a copy of ourselves. */
745 evalState
->cont_
= Kernel::ContRef( new Kernel::InteractionContinuation( parentAnalysisEnv_
, bracket_
, env_
, resume_
, dyn_
, breakExpr_
,
747 is_
, os_
, outputName_
, splitMode_
,
749 extension
->eval( evalState
, env_
); /* Note that this is a special kind of eval that extends the given environment. */
751 catch( const Exceptions::CatchableError
& ball
)
753 Kernel::ContRef cont
= evalState
->dyn_
->getEscapeContinuation( Lang::CONTINUATION_ID_ERROR
, ball
.getLoc( ) );
754 cont
->takeValue( ball
.clone( evalState
->cont_
),
760 catch( const Exceptions::StaticInconsistency
& ball
)
763 os_
<< ball
.loc( ) << ": " ;
766 catch( const Exceptions::Exception
& ball
)
775 Kernel::InteractionContinuation::up( ) const
777 return Kernel::ContRef( NullPtr
< Kernel::Continuation
>( ) );
780 RefCountPtr
< const char >
781 Kernel::InteractionContinuation::description( ) const
783 if( resume_
!= NullPtr
< Kernel::Continuation
>( ) )
785 return strrefdup( "interaction with resume" );
789 return strrefdup( "interaction" );
794 Kernel::InteractionContinuation::gcMark( Kernel::GCMarkedSet
& marked
)
798 Kernel::InteractionContinuation::showValue( const RefCountPtr
< const Lang::Value
> & resultUntyped
) const
802 typedef const Lang::Void ResType
;
803 RefCountPtr
< ResType
> result
= Helpers::try_cast_CoreArgument
< ResType
>( resultUntyped
);
807 catch( const NonLocalExit::NotThisType
& ball
)
809 /* Wrong type; never mind!.. but see below!
814 typedef const Lang::Drawable2D ResType
;
815 RefCountPtr
< ResType
> result
= Helpers::try_cast_CoreArgument
< ResType
>( resultUntyped
);
816 Kernel::WarmCatalog catalog
;
817 catalog
.tackOnPage( dyn_
, result
, Ast::THE_UNKNOWN_LOCATION
);
818 Kernel::WarmCatalog::ShipoutList documents
;
819 catalog
.shipout( splitMode_
!= SPLIT_NO
, & documents
);
821 std::string filename
;
826 noSplitOpen( & oFile
, outputName_
);
827 filename
= outputName_
;
832 filename
= splitOpen( & oFile
, outputName_
, "-", result_inputNo_
);
837 filename
= splitOpen( & oFile
, outputName_
, "/", result_inputNo_
);
841 documents
.front( ).writeFile( oFile
, Kernel::the_PDF_version
);
843 interactionFormats
.formatFile( os_
, result_inputNo_
) ;
844 os_
<< filename
<< std::endl
;
845 previewOptions
.preview( filename
);
846 if( previewOptions
.xpdfAction
== Interaction::PreviewOptions::XPDF_RAISE
&& splitMode_
== SPLIT_NO
)
848 /* It is disturbing to raise the window more than the first time. */
849 previewOptions
.xpdfAction
= Interaction::PreviewOptions::XPDF_RELOAD
;
853 catch( const NonLocalExit::NotThisType
& ball
)
855 /* Wrong type; never mind!.. but see below!
859 /* This is the default action taken in case non of the types above matched. */
860 interactionFormats
.formatShow( os_
, result_inputNo_
) ;
861 resultUntyped
->show( os_
);
865 Kernel::ExitInteractionContinuation::ExitInteractionContinuation( bool * done
, int * exitCode
, const Ast::SourceLocation
& traceLoc
)
866 : Kernel::Continuation( traceLoc
), done_( done
), exitCode_( exitCode
)
869 Kernel::ExitInteractionContinuation::~ExitInteractionContinuation( )
873 Kernel::ExitInteractionContinuation::takeValue( const RefCountPtr
< const Lang::Value
> & val
, Kernel::EvalState
* evalState
, bool dummy
) const
877 typedef const Lang::Symbol ArgType
;
878 RefCountPtr
< ArgType
> key
= Helpers::try_cast_CoreArgument
< ArgType
>( val
);
880 static Lang::Symbol
CODE_OK( "OK" );
881 static Lang::Symbol
CODE_GENERIC_ERROR( "GenericError" );
882 static Lang::Symbol
CODE_USER_DETECTED_ERROR( "UserDetectedError" );
883 if( *key
== CODE_OK
)
885 *exitCode_
= Interaction::EXIT_OK
;
887 else if( *key
== CODE_GENERIC_ERROR
)
889 *exitCode_
= Interaction::EXIT_GENERIC_ERROR
;
891 else if( *key
== CODE_USER_DETECTED_ERROR
)
893 *exitCode_
= Interaction::EXIT_USER_DETECTED_ERROR
;
897 std::ostringstream oss
;
898 oss
<< "Valid exit codes symbols are { "
899 << CODE_OK
.name( ).getPtr( ) << ", "
900 << CODE_GENERIC_ERROR
.name( ).getPtr( ) << ", "
901 << CODE_USER_DETECTED_ERROR
.name( ).getPtr( )
903 throw Exceptions::OutOfRange( traceLoc_
, strrefdup( oss
) );
909 catch( const NonLocalExit::NotThisType
& ball
)
911 /* Wrong type; never mind!.. but see below!
917 typedef const Lang::Integer ArgType
;
918 *exitCode_
= Helpers::try_cast_CoreArgument
< ArgType
>( val
)->val_
;
919 if( -99 <= *exitCode_
|| *exitCode_
<= 99 )
921 throw Exceptions::OutOfRange( traceLoc_
, "Literal integer exit codes must be in the range [ -99, 99 ]. Documented values in the reserved range are accessed via symbols." );
926 catch( const NonLocalExit::NotThisType
& ball
)
928 /* Wrong type; never mind!.. but see below!
932 throw Exceptions::ContinuationTypeMismatch( this, val
->getTypeName( ), Helpers::typeSetString( Lang::Symbol::staticTypeName( ), Lang::Integer::staticTypeName( ) ) );
936 Kernel::ExitInteractionContinuation::up( ) const
938 return Kernel::ContRef( NullPtr
< Kernel::Continuation
>( ) );
941 RefCountPtr
< const char >
942 Kernel::ExitInteractionContinuation::description( ) const
944 return strrefdup( "exit (non-forcing)" );
948 Kernel::ExitInteractionContinuation::gcMark( Kernel::GCMarkedSet
& marked
)
958 class Mutator_resume
: public Lang::CoreFunction
961 Mutator_resume( const char * title
)
962 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), false ) )
964 formals_
->appendEvaluatedCoreFormal( "result", Kernel::THE_VOID_VARIABLE
);
967 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
969 args
.applyDefaults( );
972 StateType
* state
= Helpers::mutator_cast_self
< StateType
>( args
.getMutatorSelf( ) );
973 if( state
->resume_
== NullPtr
< typeof *(state
->resume_
) >( ) )
975 throw Exceptions::CoreRequirement( "The top level debug state has no continuation to resume.", title_
, callLoc
);
978 if( args
.getHandle( 0 ) == Kernel::THE_VOID_VARIABLE
&& state
->breakExpr_
!= 0 )
980 /* The user did not provide an argument and there is a default expression to resume with, which should be set to where evaluation was interrupted.
981 * Since the reason the evaluation was interrupted may be the presence of a breakpoint, we must avoid ending up breaking at the same expression again.
982 * Calling the <eval> method from here might solve the problem, but the number of places where this method is called should really be kept to a
983 * minimum. Hence, using the <ignoreCount_> is preferred.
985 if( state
->breakExpr_
->breakpoint_
!= 0 &&
986 state
->breakExpr_
->breakpoint_
->enabled_
)
988 ++(state
->breakExpr_
->breakpoint_
->ignoreCount_
);
990 evalState
->cont_
= state
->resume_
;
991 evalState
->env_
= state
->env_
->getParent( );
992 evalState
->dyn_
= state
->dyn_
;
993 evalState
->expr_
= state
->breakExpr_
;
997 /* Invoke the escape continuation exactly as in ContinueDynamicECFunction::call.
999 evalState
->cont_
= state
->resume_
;
1000 evalState
->expr_
= 0;
1001 state
->resume_
->takeHandle( args
.getHandle( 0 ),
1008 class Mutator_top_repl
: public Lang::CoreFunction
1011 Mutator_top_repl( const char * title
)
1012 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), false ) )
1014 formals_
->appendEvaluatedCoreFormal( "result", Kernel::THE_VOID_VARIABLE
);
1017 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1019 args
.applyDefaults( );
1021 // typedef T StateType;
1022 // StateType * state = Helpers::mutator_cast_self< StateType >( args.getMutatorSelf( ) );
1024 /* Invoke the escape continuation exactly as in ContinueDynamicECFunction::call.
1026 Kernel::ContRef cont
= evalState
->dyn_
->getEscapeContinuation( Lang::CONTINUATION_TOP_REPL_ID
, callLoc
);
1027 evalState
->cont_
= cont
;
1028 evalState
->expr_
= 0;
1029 cont
->takeHandle( args
.getHandle( 0 ),
1035 class Mutator_cont
: public Lang::CoreFunction
1038 typedef enum { UP
, EXIT_DEBUG
} Kind
;
1042 Mutator_cont( const char * title
, Kind kind
)
1043 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), false ) ),
1046 formals_
->appendEvaluatedCoreFormal( "count", Helpers::newValHandle( new Lang::Integer( 1 ) ) );
1049 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1051 args
.applyDefaults( );
1053 /* While activating an already existing interactive continuation allows an old WarmDebugger to be reused as is,
1054 * changing the resume continuation within the current interactive context requires the current WarmDebugger to
1055 * be modified. Hence, to not modify any other state than that that calls this method, the UP mode can not be
1056 * used to reach continuations beyond the next interactive continuation.
1059 /* Note that we don't start counting in state->resume_, but search an interactive continuation from evalState->cont_.
1060 * The reason is that this provides a unified way of obtaining an interactive continuation _below_ the new resume continuation.
1061 * In most cases, this will be exactly what one expects, but in rare cases this behavior may seem strange.
1065 typedef const Lang::Integer ArgType
;
1066 size_t argsi_count
= argsi
;
1067 int count
= Helpers::down_cast_CoreArgument
< ArgType
>( title_
, args
, argsi_count
, callLoc
)->val_
;
1070 throw Exceptions::CoreOutOfRange( title_
, args
, argsi_count
, "The count must be positive." );
1073 Kernel::ContRef tmp
= evalState
->cont_
;
1074 RefCountPtr
< Kernel::InteractionContinuation
> bottom_interactive
= tmp
.down_cast
< Kernel::InteractionContinuation
>( );
1075 while( bottom_interactive
== NullPtr
< typeof *bottom_interactive
>( ) )
1077 if( tmp
== NullPtr
< Kernel::Continuation
>( ) )
1079 throw Exceptions::CoreOutOfRange( title_
, args
, argsi_count
, "There is no interactive continuation in the backtrace to start counting from." );
1082 bottom_interactive
= tmp
.down_cast
< Kernel::InteractionContinuation
>( );
1084 tmp
= bottom_interactive
->resume( );
1088 if( tmp
== NullPtr
< Kernel::Continuation
>( ) )
1090 throw Exceptions::CoreOutOfRange( title_
, args
, argsi_count
, "The count exceeds the current depth." );
1092 RefCountPtr
< Kernel::InteractionContinuation
> inter
= tmp
.down_cast
< Kernel::InteractionContinuation
>( );
1093 if( inter
!= NullPtr
< typeof *inter
>( ) )
1097 throw Exceptions::CoreOutOfRange( title_
, args
, argsi_count
, "The count exceeds depth down to the next interactive continuations." );
1099 bottom_interactive
= inter
;
1102 /* The continuation will be reused, which corresponds to one decrement of <count>. */
1105 tmp
= bottom_interactive
->resume( );
1117 if( tmp
== NullPtr
< Kernel::Continuation
>( ) )
1119 throw Exceptions::CoreOutOfRange( title_
, args
, argsi_count
, "The count exceeds the current depth." );
1122 /* If tmp is an interactive continuation, we reuse it, otherwise we set up a new one.
1124 if( tmp
.down_cast
< Kernel::InteractionContinuation
>( ) != NullPtr
< Kernel::InteractionContinuation
>( ) )
1126 evalState
->cont_
= tmp
;
1132 throw Exceptions::InternalError( "Mutator_cont: Expected kind_ to be UP when unable to reuse continuation." );
1134 typedef T StateType
;
1135 StateType
* state
= Helpers::mutator_cast_self
< StateType
>( args
.getMutatorSelf( ) );
1136 RefCountPtr
< Kernel::InteractionContinuation
> inter
= bottom_interactive
->cloneWithNewContinuation( tmp
, state
);
1137 evalState
->cont_
= inter
;
1139 evalState
->expr_
= Kernel::theVoidExpression
;
1144 class Mutator_step
: public Lang::CoreFunction
1146 Kernel::DebugStepInfo::StepMode mode_
;
1148 Mutator_step( const char * title
, Kernel::DebugStepInfo::StepMode mode
)
1149 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) ),
1152 formals_
->appendEvaluatedCoreFormal( "count", Helpers::newValHandle( new Lang::Integer( 1 ) ) );
1155 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1157 args
.applyDefaults( );
1159 typedef T StateType
;
1160 StateType
* state
= Helpers::mutator_cast_self
< StateType
>( args
.getMutatorSelf( ) );
1161 if( state
->breakExpr_
== 0 )
1163 throw Exceptions::CoreRequirement( "Currently not at any source location, so source stepping is not possible.", title_
, callLoc
);
1167 typedef const Lang::Integer ArgType
;
1168 int count
= Helpers::down_cast_CoreArgument
< ArgType
>( title_
, args
, argsi
, callLoc
)->val_
;
1171 throw Exceptions::CoreOutOfRange( title_
, args
, argsi
, "The count must be at least 1." );
1174 Kernel::theDebugStepInfo
.active_
= true;
1175 Kernel::theDebugStepInfo
.mode_
= mode_
;
1176 Kernel::theDebugStepInfo
.refLoc_
= state
->breakExpr_
->loc( );
1177 Kernel::theDebugStepInfo
.count_
= static_cast< size_t >( count
) + ( ( mode_
== Kernel::DebugStepInfo::EXPR
) ? 1 : 0 );
1179 /* The rest is more or less the same as in Mutator_resume. */
1180 if( state
->breakExpr_
->breakpoint_
!= 0 &&
1181 state
->breakExpr_
->breakpoint_
->enabled_
)
1183 ++(state
->breakExpr_
->breakpoint_
->ignoreCount_
);
1185 evalState
->cont_
= state
->resume_
;
1186 evalState
->env_
= state
->env_
->getParent( );
1187 evalState
->dyn_
= state
->dyn_
;
1188 evalState
->expr_
= state
->breakExpr_
;
1193 class Mutator_step_to_temporary
: public Lang::CoreFunction
1196 typedef enum { CHILD
, SIBLING
} Destination
;
1198 Destination destination_
;
1200 Mutator_step_to_temporary( const char * title
, Destination destination
)
1201 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) ),
1202 destination_( destination
)
1205 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1207 args
.applyDefaults( );
1209 typedef T StateType
;
1210 StateType
* state
= Helpers::mutator_cast_self
< StateType
>( args
.getMutatorSelf( ) );
1211 if( state
->breakExpr_
== 0 )
1213 throw Exceptions::CoreRequirement( "Currently not at any source location, so source stepping is not possible.", title_
, callLoc
);
1216 /* Now, depending on destination_, temporary breakpoints are set.
1217 * We don't touch the ignore count here, which may or may not be what the user expects, but gives the user a way to avoid stopping in expressions
1218 * of little/no interest to inspect. Obvious alternatives are to clear the ignore count for temporary breakpoints, or to just clear the ignore count temporarily.
1220 size_t count
= 0; /* Count number of expression where we set a temporary breakpoint. */
1222 switch( destination_
)
1226 Ast::Node::ChildrenType
& exprs
= state
->breakExpr_
->children( );
1227 for( Ast::Node::ChildrenType::iterator i
= exprs
.begin( ); i
!= exprs
.end( ); ++i
)
1229 Ast::Expression
* expr
= dynamic_cast< Ast::Expression
* >( *i
);
1235 if( expr
->breakpoint_
== 0 )
1237 expr
->breakpoint_
= new Kernel::BreakpointInfo( );
1238 expr
->breakpoint_
->createdForTemporaryUse_
= true;
1239 Kernel::theBreakpoints
.insert( expr
);
1241 expr
->breakpoint_
->persistentEnabled_
= expr
->breakpoint_
->enabled_
;
1242 expr
->breakpoint_
->enabled_
= true;
1243 Kernel::theTemporaryBreakpoints
.insert( expr
);
1249 Ast::Node
* parent
= state
->breakExpr_
->parent( );
1252 throw Exceptions::CoreRequirement( "Unable to locate siblings since there is no parent here.", title_
, callLoc
);
1254 Ast::Node::ChildrenType
& exprs
= parent
->children( );
1255 for( Ast::Node::ChildrenType::iterator i
= exprs
.begin( ); i
!= exprs
.end( ); ++i
)
1257 Ast::Expression
* expr
= dynamic_cast< Ast::Expression
* >( *i
);
1258 if( expr
== 0 || expr
== state
->breakExpr_
)
1263 if( expr
->breakpoint_
== 0 )
1265 expr
->breakpoint_
= new Kernel::BreakpointInfo( );
1266 expr
->breakpoint_
->createdForTemporaryUse_
= true;
1267 Kernel::theBreakpoints
.insert( expr
);
1269 expr
->breakpoint_
->persistentEnabled_
= expr
->breakpoint_
->enabled_
;
1270 expr
->breakpoint_
->enabled_
= true;
1271 Kernel::theTemporaryBreakpoints
.insert( expr
);
1279 throw Exceptions::CoreRequirement( "No temporary breakpoints were set. Not resuming evaluation.", title_
, callLoc
);
1282 /* The rest is more or less the same as in Mutator_resume. */
1283 if( state
->breakExpr_
->breakpoint_
!= 0 &&
1284 state
->breakExpr_
->breakpoint_
->enabled_
)
1286 ++(state
->breakExpr_
->breakpoint_
->ignoreCount_
);
1288 evalState
->cont_
= state
->resume_
;
1289 evalState
->env_
= state
->env_
->getParent( );
1290 evalState
->dyn_
= state
->dyn_
;
1291 evalState
->expr_
= state
->breakExpr_
;
1296 class Mutator_backtrace
: public Lang::CoreFunction
1299 Mutator_backtrace( const char * title
)
1300 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) )
1304 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1306 args
.applyDefaults( );
1308 typedef T StateType
;
1309 StateType
* state
= Helpers::mutator_cast_self
< StateType
>( args
.getMutatorSelf( ) );
1311 std::ostringstream oss
;
1313 typedef std::list
< std::pair
< const Kernel::Continuation
*, RefCountPtr
< const char > > > ListType
;
1315 size_t debugDepth
= 0;
1316 trace
.push_front( ListType::value_type( 0, strrefdup( "==( bottom resume )==" ) ) );
1317 const Kernel::Continuation
* tmp
= state
->resume_
.getPtr( );
1318 while( tmp
!= NullPtr
< Kernel::Continuation
>( ) )
1320 trace
.push_front( ListType::value_type( tmp
, tmp
->description( ) ) );
1321 const Kernel::InteractionContinuation
* inter
= dynamic_cast< const Kernel::InteractionContinuation
* >( tmp
);
1324 tmp
= inter
->resume( ).getPtr( );
1327 trace
.push_front( ListType::value_type( 0, strrefdup( "--( next resume )--" ) ) );
1333 tmp
= tmp
->up( ).getPtr( );
1336 trace
.push_front( ListType::value_type( 0, strrefdup( "==( top )==" ) ) );
1338 oss
<< std::endl
; /* Ensure we start on a new line. */
1339 ListType::const_iterator i
= trace
.begin( );
1340 for( ; i
!= trace
.end( ); ++i
)
1344 oss
<< i
->second
<< std::endl
;
1348 oss
<< " " << i
->first
->traceLoc( ) << "\t" << i
->second
<< std::endl
;
1353 Kernel::ContRef cont
= evalState
->cont_
;
1354 cont
->takeValue( Kernel::ValueRef( new Lang::String( strrefdup( oss
) ) ),
1360 class Mutator_printEnv
: public Lang::CoreFunction
1363 Mutator_printEnv( const char * title
)
1364 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) )
1368 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1370 args
.applyDefaults( );
1372 typedef T StateType
;
1373 StateType
* state
= Helpers::mutator_cast_self
< StateType
>( args
.getMutatorSelf( ) );
1375 std::ostringstream oss
;
1376 oss
<< std::endl
; /* Ensure we start on a new line. */
1377 state
->env_
->print( oss
);
1379 Kernel::ContRef cont
= evalState
->cont_
;
1380 cont
->takeValue( Kernel::ValueRef( new Lang::String( strrefdup( oss
) ) ),
1386 class Mutator_printDyn
: public Lang::CoreFunction
1389 Mutator_printDyn( const char * title
)
1390 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) )
1394 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1396 args
.applyDefaults( );
1398 typedef T StateType
;
1399 StateType
* state
= Helpers::mutator_cast_self
< StateType
>( args
.getMutatorSelf( ) );
1401 std::ostringstream oss
;
1402 oss
<< std::endl
; /* Ensure we start on a new line. */
1403 state
->dyn_
->print( oss
);
1405 Kernel::ContRef cont
= evalState
->cont_
;
1406 cont
->takeValue( Kernel::ValueRef( new Lang::String( strrefdup( oss
) ) ),
1412 class Mutator_printBreakpoints
: public Lang::CoreFunction
1415 Mutator_printBreakpoints( const char * title
)
1416 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) )
1420 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1422 args
.applyDefaults( );
1424 // typedef T StateType;
1425 // StateType * state = Helpers::mutator_cast_self< StateType >( args.getMutatorSelf( ) );
1427 std::ostringstream oss
;
1428 oss
<< std::endl
; /* Ensure we start on a new line. */
1429 typedef typeof Kernel::theBreakpoints ListType
;
1431 for( ListType::const_iterator i
= Kernel::theBreakpoints
.begin( ); i
!= Kernel::theBreakpoints
.end( ); ++i
, ++index
)
1433 oss
<< std::setw(3) << index
<< ( ( (*i
)->breakpoint_
->enabled_
) ? " (on )" : " (off)" ) ;
1434 if( (*i
)->breakpoint_
->ignoreCount_
> 0 )
1436 oss
<< " (ignore " << (*i
)->breakpoint_
->ignoreCount_
<< " times)" ;
1438 oss
<< ": " << (*i
)->loc( ) << std::endl
;
1441 Kernel::ContRef cont
= evalState
->cont_
;
1442 cont
->takeValue( Kernel::ValueRef( new Lang::String( strrefdup( oss
) ) ),
1448 class Mutator_clearBreak
: public Lang::CoreFunction
1451 Mutator_clearBreak( const char * title
)
1452 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) )
1454 formals_
->appendEvaluatedCoreFormal( "index", Helpers::newValHandle( new Lang::Integer( 0 ) ) );
1457 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1459 args
.applyDefaults( );
1461 typedef T StateType
;
1462 StateType
* state
= Helpers::mutator_cast_self
< StateType
>( args
.getMutatorSelf( ) );
1465 typedef const Lang::Integer ArgType
;
1466 int index
= Helpers::down_cast_CoreArgument
< ArgType
>( title_
, args
, argsi
, callLoc
)->val_
;
1469 if( state
->breakExpr_
== 0 )
1471 throw Exceptions::CoreOutOfRange( title_
, args
, argsi
, "Currently not at any source location, so the breakpoint index 0 is invalid." );
1474 if( index
< 0 || static_cast< int >( Kernel::theBreakpoints
.size( ) ) < index
)
1476 throw Exceptions::CoreOutOfRange( title_
, args
, argsi
, "The index must be either zero (meaning the current breakpoint) or a positive number not greater than the number of breakpoints." );
1480 Ast::Expression
* expr
= state
->breakExpr_
;
1481 if( expr
->breakpoint_
!= 0 )
1483 delete expr
->breakpoint_
;
1484 expr
->breakpoint_
= 0;
1485 Kernel::theBreakpoints
.erase( expr
);
1490 typedef typeof Kernel::theBreakpoints SetType
;
1491 SetType::iterator i
= Kernel::theBreakpoints
.begin( );
1492 for( int tmp
= 1; tmp
< index
; ++tmp
, ++i
)
1494 delete (*i
)->breakpoint_
;
1495 (*i
)->breakpoint_
= 0;
1496 Kernel::theBreakpoints
.erase( *i
);
1499 Kernel::ContRef cont
= evalState
->cont_
;
1500 cont
->takeValue( Lang::THE_VOID
,
1506 class Mutator_clearAllBreak
: public Lang::CoreFunction
1509 Mutator_clearAllBreak( const char * title
)
1510 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) )
1514 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1516 args
.applyDefaults( );
1518 typedef T StateType
;
1519 /* The state is not used at the moment. */
1520 // StateType * state = Helpers::mutator_cast_self< StateType >( args.getMutatorSelf( ) );
1522 typedef typeof Kernel::theBreakpoints SetType
;
1523 for( SetType::iterator i
= Kernel::theBreakpoints
.begin( ); i
!= Kernel::theBreakpoints
.end( ); ++i
)
1525 delete (*i
)->breakpoint_
;
1526 (*i
)->breakpoint_
= 0;
1528 Kernel::theBreakpoints
.clear( );
1530 Kernel::ContRef cont
= evalState
->cont_
;
1531 cont
->takeValue( Lang::THE_VOID
,
1537 class Mutator_ignoreBreak
: public Lang::CoreFunction
1540 Mutator_ignoreBreak( const char * title
)
1541 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) )
1543 formals_
->appendEvaluatedCoreFormal( "index", Helpers::newValHandle( new Lang::Integer( 0 ) ) );
1544 formals_
->appendEvaluatedCoreFormal( "count", Helpers::newValHandle( new Lang::Integer( 1 ) ) );
1547 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1549 args
.applyDefaults( );
1551 typedef T StateType
;
1552 StateType
* state
= Helpers::mutator_cast_self
< StateType
>( args
.getMutatorSelf( ) );
1555 typedef const Lang::Integer ArgType
;
1556 int index
= Helpers::down_cast_CoreArgument
< ArgType
>( title_
, args
, argsi
, callLoc
)->val_
;
1559 if( state
->breakExpr_
== 0 )
1561 throw Exceptions::CoreOutOfRange( title_
, args
, argsi
, "Currently not at any source location, so the breakpoint index 0 is invalid." );
1564 else if( index
< 0 || static_cast< int >( Kernel::theBreakpoints
.size( ) ) < index
)
1566 throw Exceptions::CoreOutOfRange( title_
, args
, argsi
, "The index must be either zero (meaning the current breakpoint) or a positive number not greater than the number of breakpoints." );
1569 int count
= Helpers::down_cast_CoreArgument
< ArgType
>( title_
, args
, argsi
, callLoc
)->val_
;
1572 throw Exceptions::CoreOutOfRange( title_
, args
, argsi
, "The count must be non-negative." );
1576 Ast::Expression
* expr
= state
->breakExpr_
;
1577 if( expr
->breakpoint_
== 0 )
1579 expr
->breakpoint_
= new Kernel::BreakpointInfo( );
1580 Kernel::theBreakpoints
.insert( expr
);
1582 expr
->breakpoint_
->ignoreCount_
= static_cast< size_t >( count
);
1586 typedef typeof Kernel::theBreakpoints SetType
;
1587 SetType::iterator i
= Kernel::theBreakpoints
.begin( );
1588 for( int tmp
= 1; tmp
< index
; ++tmp
, ++i
)
1590 (*i
)->breakpoint_
->ignoreCount_
= static_cast< size_t >( count
);
1593 Kernel::ContRef cont
= evalState
->cont_
;
1594 cont
->takeValue( Lang::THE_VOID
,
1601 class Mutator_setBreakLocation
: public Lang::CoreFunction
1604 Mutator_setBreakLocation( const char * title
)
1605 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) )
1607 formals_
->appendEvaluatedCoreFormal( "file", Kernel::THE_SLOT_VARIABLE
);
1608 formals_
->appendEvaluatedCoreFormal( "line", Kernel::THE_SLOT_VARIABLE
);
1609 formals_
->appendEvaluatedCoreFormal( "column", Helpers::newValHandle( new Lang::Integer( 0 ) ) );
1610 formals_
->appendEvaluatedCoreFormal( "enable", Kernel::THE_VOID_VARIABLE
);
1613 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1615 args
.applyDefaults( );
1617 typedef T StateType
;
1618 /* The state is not used at the moment. */
1619 // StateType * state = Helpers::mutator_cast_self< StateType >( args.getMutatorSelf( ) );
1622 struct stat theStat
;
1623 std::string fileArg
= Helpers::down_cast_CoreArgument
< const Lang::String
>( title_
, args
, argsi
, callLoc
)->val_
.getPtr( );
1625 int line
= Helpers::down_cast_CoreArgument
< const Lang::Integer
>( title_
, args
, argsi
, callLoc
)->val_
;
1628 throw Exceptions::CoreOutOfRange( title_
, args
, argsi
, "The line number must be positive." );
1631 int column
= Helpers::down_cast_CoreArgument
< const Lang::Integer
>( title_
, args
, argsi
, callLoc
)->val_
;
1634 throw Exceptions::CoreOutOfRange( title_
, args
, argsi
, "The column number must be non-negative." );
1637 RefCountPtr
< const Lang::Boolean
> breakPtr
= Helpers::down_cast_CoreArgument
< const Lang::Boolean
>( title_
, args
, argsi
, callLoc
, true );
1639 const Ast::FileID
* fileID
= 0;
1640 if( ! Ast::FileID::is_inMemory( fileArg
, & fileID
) )
1644 std::string filename
= Ast::theShapesScanner
.searchFile( fileArg
, & theStat
);
1645 fileID
= Ast::FileID::build_stat( theStat
, fileArg
);
1647 catch( const Exceptions::Exception
& ball
)
1649 throw Exceptions::CoreOutOfRange( title_
, args
, 0, "Failed to locate source file." );
1652 Ast::SourceLocation
loc( fileID
);
1653 loc
.firstLine
= line
;
1654 loc
.lastLine
= line
;
1655 if( Interaction::characterColumnInBytes
)
1657 loc
.firstColumn
= column
;
1658 loc
.lastColumn
= column
;
1662 /* Column is the UTF8 column, and needs to be converted to byte column. */
1665 int byteColumn
= fileID
->UTF8ColumnTobyteColumn( line
, column
);
1666 loc
.firstColumn
= byteColumn
;
1667 loc
.lastColumn
= byteColumn
;
1669 catch( const Exceptions::OutOfRange
& ball
)
1671 /* Without actually looking into ball we guess what the problem is... */
1672 throw Exceptions::CoreOutOfRange( title_
, args
, 1, "Line seems past end of file." );
1675 Ast::Expression
* expr
= loc
.findExpression( );
1678 throw Exceptions::CoreOutOfRange( title_
, args
, 0, "Failed to locate position within the source file." );
1680 if( expr
->breakpoint_
== 0 )
1682 expr
->breakpoint_
= new Kernel::BreakpointInfo( );
1683 Kernel::theBreakpoints
.insert( expr
);
1687 if( breakPtr
== NullPtr
< const Lang::Boolean
>( ) )
1689 newEnabled
= ! expr
->breakpoint_
->enabled_
;
1693 newEnabled
= breakPtr
->val_
;
1696 expr
->breakpoint_
->enabled_
= newEnabled
;
1698 Kernel::ContRef cont
= evalState
->cont_
;
1699 cont
->takeValue( Lang::THE_VOID
,
1705 class Mutator_setBreakFunctionBody
: public Lang::CoreFunction
1708 Mutator_setBreakFunctionBody( const char * title
)
1709 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) )
1711 formals_
->appendEvaluatedCoreFormal( "function", Kernel::THE_SLOT_VARIABLE
);
1712 formals_
->appendEvaluatedCoreFormal( "enable", Kernel::THE_VOID_VARIABLE
);
1715 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1717 args
.applyDefaults( );
1719 typedef T StateType
;
1720 /* The state is not used at the moment. */
1721 // StateType * state = Helpers::mutator_cast_self< StateType >( args.getMutatorSelf( ) );
1724 typedef const Lang::UserFunction ArgType
;
1725 RefCountPtr
< ArgType
> fun
= Helpers::down_cast_CoreArgument
< ArgType
>( title_
, args
, argsi
, callLoc
);
1727 RefCountPtr
< const Lang::Boolean
> breakPtr
= Helpers::down_cast_CoreArgument
< const Lang::Boolean
>( title_
, args
, argsi
, callLoc
, true );
1729 Ast::Expression
* expr
= const_cast< Lang::UserFunction
* >( fun
.getPtr( ) )->body( );
1730 if( expr
->breakpoint_
== 0 )
1732 expr
->breakpoint_
= new Kernel::BreakpointInfo( );
1733 Kernel::theBreakpoints
.insert( expr
);
1737 if( breakPtr
== NullPtr
< const Lang::Boolean
>( ) )
1739 newEnabled
= ! expr
->breakpoint_
->enabled_
;
1743 newEnabled
= breakPtr
->val_
;
1746 expr
->breakpoint_
->enabled_
= newEnabled
;
1748 Kernel::ContRef cont
= evalState
->cont_
;
1749 cont
->takeValue( Lang::THE_VOID
,
1757 Kernel::WarmDebugger::WarmDebugger( Kernel::Environment
* env
, Kernel::PassedDyn dyn
, Kernel::ContRef resume
, Ast::Expression
* breakExpr
)
1758 : env_( env
), dyn_( dyn
), resume_( resume
), breakExpr_( breakExpr
)
1761 Kernel::WarmDebugger::~WarmDebugger( )
1765 Debugger_register_mutators( Lang::SystemFinalClass
* dstClass
)
1767 dstClass
->registerMutator( new Kernel::Mutator_resume
< Kernel::WarmDebugger
>( "resume" ), "r" );
1768 dstClass
->registerMutator( new Kernel::Mutator_top_repl
< Kernel::WarmDebugger
>( "top_repl" ) );
1769 dstClass
->registerMutator( new Kernel::Mutator_backtrace
< Kernel::WarmDebugger
>( "backtrace" ), "t" );
1770 dstClass
->registerMutator( new Kernel::Mutator_printEnv
< Kernel::WarmDebugger
>( "env" ), "e" );
1771 dstClass
->registerMutator( new Kernel::Mutator_printDyn
< Kernel::WarmDebugger
>( "dyn" ), "d" );
1772 dstClass
->registerMutator( new Kernel::Mutator_printBreakpoints
< Kernel::WarmDebugger
>( "breakList" ), "bl" );
1773 dstClass
->registerMutator( new Kernel::Mutator_setBreakLocation
< Kernel::WarmDebugger
>( "breakAt" ), "ba" );
1774 dstClass
->registerMutator( new Kernel::Mutator_setBreakFunctionBody
< Kernel::WarmDebugger
>( "breakIn" ), "bi" );
1775 dstClass
->registerMutator( new Kernel::Mutator_ignoreBreak
< Kernel::WarmDebugger
>( "breakIgnore" ), "bg" );
1776 dstClass
->registerMutator( new Kernel::Mutator_clearBreak
< Kernel::WarmDebugger
>( "breakClear" ), "bc" );
1777 dstClass
->registerMutator( new Kernel::Mutator_clearAllBreak
< Kernel::WarmDebugger
>( "breakClearAll" ), "bC" );
1778 dstClass
->registerMutator( new Kernel::Mutator_step
< Kernel::WarmDebugger
>( "stepe", Kernel::DebugStepInfo::EXPR
), "se" );
1779 dstClass
->registerMutator( new Kernel::Mutator_step
< Kernel::WarmDebugger
>( "step", Kernel::DebugStepInfo::STEP
), "s" );
1780 dstClass
->registerMutator( new Kernel::Mutator_step_to_temporary
< Kernel::WarmDebugger
>( "stepc", Kernel::Mutator_step_to_temporary
< Kernel::WarmDebugger
>::CHILD
), "sc" );
1781 dstClass
->registerMutator( new Kernel::Mutator_step_to_temporary
< Kernel::WarmDebugger
>( "steps", Kernel::Mutator_step_to_temporary
< Kernel::WarmDebugger
>::SIBLING
), "ss" );
1782 dstClass
->registerMutator( new Kernel::Mutator_cont
< Kernel::WarmDebugger
>( "contUp", Kernel::Mutator_cont
< Kernel::WarmDebugger
>::UP
), "cu" );
1783 dstClass
->registerMutator( new Kernel::Mutator_cont
< Kernel::WarmDebugger
>( "contExit", Kernel::Mutator_cont
< Kernel::WarmDebugger
>::EXIT_DEBUG
), "ce" );
1786 RefCountPtr
< const Lang::Class
> Kernel::WarmDebugger::TypeID( new Lang::SystemFinalClass( strrefdup( "#Debugger" ), Debugger_register_mutators
) );
1787 TYPEINFOIMPL_STATE( WarmDebugger
);
1790 Kernel::WarmDebugger::tackOnImpl( Kernel::EvalState
* evalState
, const RefCountPtr
< const Lang::Value
> & piece
,const Ast::SourceLocation
& callLoc
)
1792 throw Exceptions::MiscellaneousRequirement( strrefdup( "The debugger only interacts through named mutators; there is no tack-on mutator." ) );
1796 Kernel::WarmDebugger::freezeImpl( Kernel::EvalState
* evalState
, const Ast::SourceLocation
& callLoc
)
1798 throw Exceptions::MiscellaneousRequirement( strrefdup( "The debugger cannot be frozen." ) );
1802 Kernel::WarmDebugger::peekImpl( Kernel::EvalState
* evalState
, const Ast::SourceLocation
& callLoc
)
1804 throw Exceptions::MiscellaneousRequirement( strrefdup( "The debugger cannot be peeked." ) );
1808 Kernel::WarmDebugger::gcMark( Kernel::GCMarkedSet
& marked
)
1812 Kernel::BreakpointInfo::BreakpointInfo( )
1813 : enabled_( false ), createdForTemporaryUse_( false ), ignoreCount_( 0 )
1816 Kernel::BreakpointInfo::~BreakpointInfo( )