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, 2014 Henrik Tidefelt
21 #include "breakpoints.h"
22 #include "shapescore.h"
26 using namespace Shapes
;
27 using namespace SimplePDF
;
33 class VoidExpression
: public Expression
36 VoidExpression( const Ast::SourceLocation
& loc
);
37 virtual ~VoidExpression( );
38 virtual void analyze_impl( Ast::Node
* parent
, Ast::AnalysisEnvironment
* env
, Ast::StateIDSet
* freeStatesDst
);
39 virtual void eval( Kernel::EvalState
* evalState
) const;
45 bool theInteractionDone
= false;
47 class InteractionContinuation
: public Kernel::Continuation
49 Ast::AnalysisEnvironment
* parentAnalysisEnv_
;
50 mutable Ast::CodeBracket
* bracket_
;
51 mutable Kernel::Environment
* env_
;
52 Kernel::ContRef resume_
;
53 Kernel::PassedDyn dyn_
;
54 Ast::Expression
* breakExpr_
;
58 std::string outputName_
;
61 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
);
62 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
63 ~InteractionContinuation( );
64 RefCountPtr
< Kernel::InteractionContinuation
> cloneWithNewContinuation( Kernel::ContRef resume
, Kernel::WarmDebugger
* state
);
65 void setDyn( const Kernel::PassedDyn
& dyn
);
66 bool reusable( Kernel::EvalState
& evalState
) const;
67 virtual void takeValue( const RefCountPtr
< const Lang::Value
> & val
, Kernel::EvalState
* evalState
, bool dummy
) const;
68 virtual Kernel::ContRef
up( ) const;
69 virtual RefCountPtr
< const char > description( ) const;
70 virtual void gcMark( Kernel::GCMarkedSet
& marked
);
72 Kernel::ContRef
resume( ) const { return resume_
; } /* For debug backtraces and to skip continuations. */
74 void showValue( const RefCountPtr
< const Lang::Value
> & resultUntyped
) const;
77 class ExitInteractionContinuation
: public Kernel::Continuation
82 ExitInteractionContinuation( bool * done
, int * exitCode
, const Ast::SourceLocation
& traceLoc
);
83 ~ExitInteractionContinuation( );
84 virtual void takeValue( const RefCountPtr
< const Lang::Value
> & val
, Kernel::EvalState
* evalState
, bool dummy
) const;
85 virtual Kernel::ContRef
up( ) const;
86 virtual RefCountPtr
< const char > description( ) const;
87 virtual void gcMark( Kernel::GCMarkedSet
& marked
);
93 typedef enum { EXPR
, STEP
} StepMode
;
97 Ast::SourceLocation refLoc_
; /* Note: Not a const reference. Will be reassigned. Make sure not to initialize const SourceLocation & references with this value! */
100 : active_( false ), mode_( EXPR
), refLoc_( Ast::THE_UNKNOWN_LOCATION
, bool( ) ), count_( 1 )
102 bool stop( const Ast::SourceLocation
& loc
)
107 /* Stop at everything. No need to update refLoc_ . */
111 if( refLoc_
.contains( loc
) )
129 const int NO_INPUT_INPUT_NO
= std::numeric_limits
< int >::max( );
130 bool interactive_debug
= true;
131 typedef typeof Ast::theInteractiveInput InputType
;
132 std::vector
< InputType
> interactive_history
;
133 std::set
< Ast::Expression
* > theBreakpoints
; /* This set shall contain all expressions that have a Kernel::BreakpointInfo, incloding also those thare are not enabled. */
134 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. */
135 DebugStepInfo theDebugStepInfo
;
136 Ast::VoidExpression
* theVoidExpression
= new Ast::VoidExpression( Ast::THE_UNKNOWN_LOCATION
); /* Order of initializaiton of globals?! */
141 const char * CONTINUATION_TOP_REPL_ID
= "top_repl";
146 interactiveEvaluation( std::istream
& in
, std::ostream
& out
, const std::string
& outputName
, SplitMode splitMode
,
147 bool evalTrace
, bool evalBackTrace
, bool cleanupMemory
,
148 RefCountPtr
< std::ifstream
> & labelDBFile
, const std::string
& labelDBName
)
150 if( ! Interaction::blankMode
){
151 /* Clean up outout from earlier sessions. */
158 rmSplitFiles( outputName
, "-" );
163 mkSplitDir( outputName
);
164 rmSplitFiles( outputName
, "/" );
170 RefCountPtr
< const Kernel::GraphicsState
> graphicsState( new Kernel::GraphicsState( true ) );
171 Kernel::PassedDyn
baseDyn( new Kernel::DynamicEnvironment( graphicsState
) );
175 /* Evaluate preamble. */
177 initCore( labelDBFile
, labelDBName
);
180 Kernel::ValueRef resultUntyped
= NullPtr
< const Lang::Value
>( );
181 Kernel::EvalState
evalState( Ast::theProgram
,
182 Kernel::theGlobalEnvironment
,
184 Kernel::ContRef( new Kernel::StoreValueContinuation( & resultUntyped
,
185 Kernel::ContRef( new Kernel::ExitContinuation( & done
, Ast::theProgram
->loc( ) ) ),
186 Ast::theProgram
->loc( ) ) ) );
189 Ast::Expression
* expr
= evalState
.expr_
;
190 expr
->eval( & evalState
);
193 catch( const Exceptions::StaticInconsistency
& ball
)
196 std::cerr
<< ball
.loc( ) << ": " ;
197 ball
.display( std::cerr
);
198 std::cerr
<< "There were errors in the preamble. Aborting interactive evaluation." ;
199 abortProcedure( ball
.exitCode( ) );
201 catch( const Exceptions::Exception
& ball
)
204 ball
.display( std::cerr
);
205 std::cerr
<< "There were errors in the preamble. Aborting interactive evaluation." ;
206 abortProcedure( ball
.exitCode( ) );
209 Ast::theShapesScanner
.setInteractive( true ); /* Do this after reading the preamble! */
211 /* Find the prelude environment... */
212 Kernel::Environment
* preludeEnv
= 0;
213 for( std::list
< Kernel::Environment
* >::iterator e
= Kernel::theEnvironmentList
.begin( ); e
!= Kernel::theEnvironmentList
.end( ); ++e
)
217 if( (*e
)->getParent( ) == Kernel::theGlobalEnvironment
)
223 catch( const Exceptions::MiscellaneousRequirement
& ball
)
225 /* That was the global environment, which doesn't have a parent. Never mind. */
228 if( preludeEnv
== 0 )
230 std::cerr
<< "Internal error: Failed to locate prelude environment." << std::endl
;
231 exit( Interaction::EXIT_INTERNAL_ERROR
);
233 Ast::AnalysisEnvironment
* preludeAnalysisEnvironment
= preludeEnv
->newAnalysisEnvironment( Ast::theGlobalAnalysisEnvironment
);
235 static Ast::SourceLocation
loc( Ast::FileID::build_internal( "{ interactive }" ) );
236 Ast::CodeBracket
* initialBracket( new Ast::CodeBracket( loc
, new std::list
< Ast::Node
* >( ) ) );
238 Ast::StateIDSet freeStates
;
239 initialBracket
->analyze( Ast::theProgram
, preludeAnalysisEnvironment
, & freeStates
);
241 Kernel::Environment
* bracketEnv
= initialBracket
->newEnvironment( preludeEnv
, "Interaction" );
242 bracketEnv
->initDefine( Lang::THE_NAMESPACE_Shapes_Debug
, "db", new Kernel::WarmDebugger( bracketEnv
, baseDyn
, Kernel::ContRef( NullPtr
< Kernel::Continuation
>( ) ), 0 ) );
244 int exitCode
= Interaction::EXIT_OK
;
246 RefCountPtr
< Kernel::InteractionContinuation
> interactionCont
247 ( new Kernel::InteractionContinuation( preludeAnalysisEnvironment
, initialBracket
, bracketEnv
, Kernel::ContRef( NullPtr
< Kernel::Continuation
>( ) ), baseDyn
, 0, Kernel::NO_INPUT_INPUT_NO
,
248 in
, out
, outputName
, splitMode
,
249 initialBracket
->loc( ) ) );
250 Kernel::PassedDyn
interactionDyn( new Kernel::DynamicEnvironment( Kernel::PassedDyn( new Kernel::DynamicEnvironment( baseDyn
, "bye", Kernel::ContRef( new Kernel::ExitInteractionContinuation( & Kernel::theInteractionDone
, & exitCode
, initialBracket
->loc( ) ) ) ) ),
251 Lang::CONTINUATION_TOP_REPL_ID
, interactionCont
) );
252 interactionCont
->setDyn( interactionDyn
);
254 Kernel::EvalState
evalState( Kernel::theVoidExpression
, /* This will invoke the continuation first thing. */
255 Kernel::theGlobalEnvironment
, /* Dummy value */
256 baseDyn
, /* Dummy value */
259 while( ! Kernel::theInteractionDone
)
261 Ast::Expression
* expr
= evalState
.expr_
;
262 if( Kernel::theDebugStepInfo
.active_
&& Kernel::theDebugStepInfo
.stop( expr
->loc( ) ) )
264 out
<< "Reached " << expr
->loc( ) << "." << std::endl
;
265 evalState
.cont_
= Kernel::ContRef( new Kernel::InteractionContinuation( evalState
, Kernel::NO_INPUT_INPUT_NO
, in
, out
, outputName
, splitMode
) );
266 evalState
.expr_
= Kernel::theVoidExpression
;
267 Kernel::theDebugStepInfo
.active_
= false;
270 if( expr
->breakpoint_
!= 0 && expr
->breakpoint_
->enabled_
)
272 if( expr
->breakpoint_
->ignoreCount_
> 0 )
274 /* Don't break this time, but re-enable breaking in the future. */
275 --(expr
->breakpoint_
->ignoreCount_
);
279 out
<< "Stopping at breakpoint " << expr
->loc( ) << "." << std::endl
;
280 typedef typeof Kernel::theTemporaryBreakpoints SetType
;
281 for( SetType::iterator i
= Kernel::theTemporaryBreakpoints
.begin( ); i
!= Kernel::theTemporaryBreakpoints
.end( ); ++i
)
283 if( (*i
)->breakpoint_
->createdForTemporaryUse_
)
285 delete (*i
)->breakpoint_
;
286 (*i
)->breakpoint_
= 0;
287 Kernel::theBreakpoints
.erase( *i
);
291 (*i
)->breakpoint_
->enabled_
= (*i
)->breakpoint_
->persistentEnabled_
;
294 Kernel::theTemporaryBreakpoints
.clear( );
295 evalState
.cont_
= Kernel::ContRef( new Kernel::InteractionContinuation( evalState
, Kernel::NO_INPUT_INPUT_NO
, in
, out
, outputName
, splitMode
) );
296 evalState
.expr_
= Kernel::theVoidExpression
;
297 Kernel::theDebugStepInfo
.active_
= false;
306 expr
->eval( & evalState
);
308 catch( const Exceptions::CatchableError
& ball
)
310 Kernel::ContRef cont
= evalState
.dyn_
->getEscapeContinuation( Lang::CONTINUATION_ID_ERROR
, ball
.getLoc( ) );
311 cont
->takeValue( ball
.clone( evalState
.cont_
),
316 catch( const Exceptions::StaticInconsistency
& ball
)
319 out
<< ball
.loc( ) << ": " ;
322 catch( const Exceptions::Exception
& ball
)
325 if( Interaction::debugBacktrace
)
327 evalState
.cont_
->backTrace( out
);
332 const Exceptions::RuntimeError
& rerr
= dynamic_cast< const Exceptions::RuntimeError
& >( ball
);
333 if( rerr
.getLoc( ).isUnknown( ) )
335 throw std::bad_cast( ); /* It's not a bad cast, but the cast value is just as little useful as a bad cast. */
337 out
<< rerr
.getLoc( ) << Exceptions::Exception::locsep
;
339 catch( std::bad_cast
& bad_cast_ball
)
341 out
<< evalState
.cont_
->traceLoc( ) << Exceptions::Exception::locsep
;
345 if( Kernel::interactive_debug
)
347 Kernel::InteractionContinuation
* iCont
= dynamic_cast< Kernel::InteractionContinuation
* >( evalState
.cont_
.getPtr( ) );
348 if( iCont
!= 0 && iCont
->reusable( evalState
) )
350 /* We don't create a new interactive continuation if the active continuation is already an interactive continuation.
351 * For instance, failing to set a breakpoint is not something that's interesting to debug in itself.
353 out
<< "Reusing interactive continuation." << std::endl
;
355 else if( evalState
.expr_
!= 0 )
357 evalState
.cont_
= Kernel::ContRef( new Kernel::InteractionContinuation( evalState
, Kernel::NO_INPUT_INPUT_NO
, in
, out
, outputName
, splitMode
) );
361 /* We interpret this situation as a failure to explicitly apply a continuation.
362 * See ContinueDynamicECFunction::call .
364 evalState
.cont_
= Kernel::ContRef( new Kernel::InteractionContinuation
365 ( preludeAnalysisEnvironment
, initialBracket
, bracketEnv
, evalState
.cont_
,
366 Kernel::PassedDyn( new Kernel::DynamicEnvironment( baseDyn
, "resume", evalState
.cont_
) ),
368 Kernel::NO_INPUT_INPUT_NO
,
369 in
, out
, outputName
, splitMode
,
370 initialBracket
->loc( ) ) );
375 evalState
.cont_
= interactionCont
;
377 Kernel::theDebugStepInfo
.active_
= false;
378 evalState
.expr_
= Kernel::theVoidExpression
;
381 /* Someone ended the input stream or invoked the exit continuation.
382 * For now, we circumvent the normal termination procedures in <main> by exiting here,
383 * which is similar to stopping the program by pressing ctrl-c, which is probably what
384 * most people will do anyway.
390 Interaction::InteractionFormats::InteractionFormats( )
391 : prompt_( "[%!#!!3R] " ),
392 show_( "%!#!!3R ⇒ " ),
398 Interaction::InteractionFormats::setPrompt( const char * format
)
404 Interaction::InteractionFormats::setShow( const char * format
)
410 Interaction::InteractionFormats::setFile( const char * format
)
416 Interaction::InteractionFormats::setBye( const char * format
)
422 Interaction::InteractionFormats::formatPrompt( std::ostream
& os
, size_t inputNo
) const
424 writePrompt( os
, prompt_
, inputNo
);
428 Interaction::InteractionFormats::formatShow( std::ostream
& os
, size_t inputNo
) const
430 writePrompt( os
, show_
, inputNo
);
434 Interaction::InteractionFormats::formatFile( std::ostream
& os
, size_t inputNo
) const
436 writePrompt( os
, file_
, inputNo
);
440 Interaction::InteractionFormats::formatBye( std::ostream
& os
, size_t inputNo
) const
442 writePrompt( os
, bye_
, inputNo
);
446 Interaction::InteractionFormats::writePrompt( std::ostream
& os
, const char * format
, size_t inputNo
) const
448 for( const char * src
= format
; *src
!= '\0'; ++src
)
453 const char sep
= *src
;
455 std::ostringstream noStr
;
460 std::cerr
<< "Bad interactive prompt format string (expected second '" << sep
<< "'): " << format
<< std::endl
;
461 exit( Interaction::EXIT_INVOCATION_ERROR
);
466 writeEscape( noStr
, *src
);
480 std::cerr
<< "Bad interactive prompt format string (expected third '" << sep
<< "'): " << format
<< std::endl
;
481 exit( Interaction::EXIT_INVOCATION_ERROR
);
486 writeEscape( noStr
, *src
);
496 int width
= strtol( src
, & endp
, 10 );
501 else if( width
< 0 || width
> 10 )
503 std::cerr
<< "Bad interactive prompt format string (the width " << width
<< " is out of the range [0,10]): " << format
<< std::endl
;
504 exit( Interaction::EXIT_INVOCATION_ERROR
);
511 os
.setf(std::ios::left
);
514 os
.setf(std::ios::right
);
517 std::cerr
<< "Bad interactive prompt format string (expected 'L' or 'R' after '%'): " << format
<< std::endl
;
518 exit( Interaction::EXIT_INVOCATION_ERROR
);
522 os
<< std::setw(width
) ;
526 else if( *src
== '\\' )
529 writeEscape( os
, *src
);
539 Interaction::InteractionFormats::writeEscape( std::ostream
& os
, char c
) const
563 Ast::VoidExpression::VoidExpression( const Ast::SourceLocation
& loc
)
564 : Ast::Expression( loc
)
567 Ast::VoidExpression::~VoidExpression( )
571 Ast::VoidExpression::analyze_impl( Ast::Node
* parent
, Ast::AnalysisEnvironment
* env
, Ast::StateIDSet
* freeStatesDst
)
577 Ast::VoidExpression::eval( Kernel::EvalState
* evalState
) const
579 Kernel::ContRef cont
= evalState
->cont_
;
580 cont
->takeValue( Lang::THE_VOID
,
584 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
)
585 : 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
)
588 Ast::SourceLocation
debug_loc( Ast::FileID::build_internal( "{ debug }" ) );
590 Kernel::InteractionContinuation::InteractionContinuation( Kernel::EvalState
& evalState
, int result_inputNo
, std::istream
& is
, std::ostream
& os
, const std::string
& outputName
, SplitMode splitMode
)
591 : Kernel::Continuation( evalState
.expr_
->loc( ) ),
592 parentAnalysisEnv_( evalState
.expr_
->getEnv( ) ),
593 bracket_( new Ast::CodeBracket( debug_loc
, new std::list
< Ast::Node
* >( ) ) ),
594 env_( bracket_
->newEnvironment( evalState
.env_
, "Debug" ) ),
595 resume_( evalState
.cont_
),
596 dyn_( new Kernel::DynamicEnvironment( evalState
.dyn_
, "resume", resume_
) ),
597 breakExpr_( evalState
.expr_
),
598 result_inputNo_( result_inputNo
),
599 is_( is
), os_( os
), outputName_( outputName
), splitMode_( splitMode
)
602 Ast::StateIDSet freeStates
;
603 bracket_
->analyze( evalState
.expr_
, parentAnalysisEnv_
, & freeStates
);
605 env_
->initDefine( Lang::THE_NAMESPACE_Shapes_Debug
, "db", new Kernel::WarmDebugger( env_
, dyn_
, resume_
, breakExpr_
) );
606 env_
->initDefineHandle( Ast::PlacedIdentifier( Lang::THE_NAMESPACE_Shapes_Debug
, "expr" ), Kernel::VariableHandle( new Kernel::Variable( new Kernel::Thunk( evalState
.env_
, evalState
.dyn_
, evalState
.expr_
) ) ) );
609 Kernel::InteractionContinuation::~InteractionContinuation( )
612 RefCountPtr
< Kernel::InteractionContinuation
>
613 Kernel::InteractionContinuation::cloneWithNewContinuation( Kernel::ContRef resume
, Kernel::WarmDebugger
* state
)
616 state
->dyn_
= Kernel::PassedDyn( new Kernel::DynamicEnvironment( dyn_
, "resume", resume
) );
617 state
->breakExpr_
= breakExpr_
;
618 state
->resume_
= resume
;
619 return RefCountPtr
< Kernel::InteractionContinuation
>
620 ( new Kernel::InteractionContinuation( parentAnalysisEnv_
, bracket_
, state
->env_
, resume
,
624 is_
, os_
, outputName_
, splitMode_
,
629 Kernel::InteractionContinuation::setDyn( const Kernel::PassedDyn
& dyn
)
635 Kernel::InteractionContinuation::reusable( Kernel::EvalState
& evalState
) const
637 return env_
== evalState
.env_
&& dyn_
== evalState
.dyn_
;
641 Kernel::InteractionContinuation::takeValue( const RefCountPtr
< const Lang::Value
> & val
, Kernel::EvalState
* evalState
, bool dummy
) const
643 Kernel::theDebugStepInfo
.active_
= false;
646 size_t debugDepth
= 0;
648 Kernel::ContRef tmp
= evalState
->cont_
;
649 while( tmp
!= NullPtr
< Kernel::Continuation
>( ) )
651 RefCountPtr
< Kernel::InteractionContinuation
> inter
= tmp
.down_cast
< Kernel::InteractionContinuation
>( );
652 if( inter
!= NullPtr
< Kernel::InteractionContinuation
>( ) )
654 tmp
= inter
->resume_
;
655 if( tmp
!= NullPtr
< Kernel::Continuation
>( ) )
669 /* As long as we fail to return, we ask for new input... */
673 for( size_t i
= 0; i
< debugDepth
; ++i
)
683 const Ast::FileID
* fileID
= Ast::FileID::build_fresh_inMemory( );
684 int interactive_inputNo
= fileID
->inMemoryIndex( );
685 std::ostringstream inputBuf
;
688 interactionFormats
.formatPrompt( os_
, interactive_inputNo
);
690 std::getline( is_
, line
);
693 interactionFormats
.formatBye( os_
, interactive_inputNo
);
694 Kernel::theInteractionDone
= true;
697 if( line
.length( ) > 1 && line
[ line
.length( ) - 1] == ' ' )
699 inputBuf
<< line
.substr( 0, line
.length( ) - 1 ) << '\n' ;
707 std::string line
= inputBuf
.str( );
708 if( line
.length( ) > 1 && line
[0] == ':' )
710 line
= "#db.[" + line
.substr(1) + "]";
713 const_cast< Ast::FileID
* >( fileID
)->setMem( strdup( line
.c_str( ) ) );
714 std::istringstream
inLine( line
+ "\n" );
715 Ast::theShapesScanner
.queueStream( & inLine
, fileID
);
716 Ast::theShapesScanner
.start( );
720 interactive_history
.push_back( Ast::theInteractiveInput
);
721 Ast::CodeBracket
* extension
= new Ast::CodeBracket( bracket_
->loc( ), Ast::theInteractiveInput
, bracket_
);
723 Ast::StateIDSet freeStates
;
724 extension
->analyze( Ast::theProgram
, parentAnalysisEnv_
, & freeStates
);
726 if( ! Ast::theAnalysisErrorsList
.empty( ) )
729 typedef typeof Ast::theAnalysisErrorsList ListType
;
730 for( ListType::const_iterator i
= Ast::theAnalysisErrorsList
.begin( ); i
!= Ast::theAnalysisErrorsList
.end( ); ++i
)
733 typedef const Exceptions::StaticInconsistency ErrorType
;
734 ErrorType
* err
= dynamic_cast< ErrorType
* >( *i
);
737 std::cerr
<< err
->loc( ) << ": " ;
738 err
->display( std::cerr
);
742 std::cerr
<< "(Bad exception type)" << ": " ;
743 (*i
)->display( std::cerr
);
745 Ast::theAnalysisErrorsList
.clear( );
751 // evalState->env_ = env_; /* Not needed since extension->eval handles this. */
752 evalState
->dyn_
= dyn_
;
753 /* For the continuation, we make a copy of ourselves. */
754 evalState
->cont_
= Kernel::ContRef( new Kernel::InteractionContinuation( parentAnalysisEnv_
, bracket_
, env_
, resume_
, dyn_
, breakExpr_
,
756 is_
, os_
, outputName_
, splitMode_
,
758 extension
->eval( evalState
, env_
); /* Note that this is a special kind of eval that extends the given environment. */
760 catch( const Exceptions::CatchableError
& ball
)
762 Kernel::ContRef cont
= evalState
->dyn_
->getEscapeContinuation( Lang::CONTINUATION_ID_ERROR
, ball
.getLoc( ) );
763 cont
->takeValue( ball
.clone( evalState
->cont_
),
769 catch( const Exceptions::StaticInconsistency
& ball
)
772 os_
<< ball
.loc( ) << ": " ;
775 catch( const Exceptions::Exception
& ball
)
784 Kernel::InteractionContinuation::up( ) const
786 return Kernel::ContRef( NullPtr
< Kernel::Continuation
>( ) );
789 RefCountPtr
< const char >
790 Kernel::InteractionContinuation::description( ) const
792 if( resume_
!= NullPtr
< Kernel::Continuation
>( ) )
794 return strrefdup( "interaction with resume" );
798 return strrefdup( "interaction" );
803 Kernel::InteractionContinuation::gcMark( Kernel::GCMarkedSet
& marked
)
807 Kernel::InteractionContinuation::showValue( const RefCountPtr
< const Lang::Value
> & resultUntyped
) const
811 typedef const Lang::Void ResType
;
812 RefCountPtr
< ResType
> result
= Helpers::try_cast_CoreArgument
< ResType
>( resultUntyped
);
816 catch( const NonLocalExit::NotThisType
& ball
)
818 /* Wrong type; never mind!.. but see below!
823 if( Interaction::blankMode
){
824 /* Skip special handling of Lang::Drawable2D when running the compiler in blank mode. */
825 throw NonLocalExit::NotThisType( );
827 typedef const Lang::Drawable2D ResType
;
828 RefCountPtr
< ResType
> result
= Helpers::try_cast_CoreArgument
< ResType
>( resultUntyped
);
829 Kernel::WarmCatalog catalog
;
830 catalog
.tackOnPage( dyn_
, result
, Ast::THE_UNKNOWN_LOCATION
);
831 Kernel::WarmCatalog::ShipoutList documents
;
832 catalog
.shipout( splitMode_
!= SPLIT_NO
, & documents
);
834 std::string filename
;
839 noSplitOpen( & oFile
, outputName_
);
840 filename
= outputName_
;
845 filename
= splitOpen( & oFile
, outputName_
, "-", result_inputNo_
);
850 filename
= splitOpen( & oFile
, outputName_
, "/", result_inputNo_
);
854 documents
.front( ).writeFile( oFile
, Kernel::the_PDF_version
);
856 interactionFormats
.formatFile( os_
, result_inputNo_
) ;
857 os_
<< filename
<< std::endl
;
858 previewOptions
.preview( filename
);
859 if( previewOptions
.xpdfAction
== Interaction::PreviewOptions::XPDF_RAISE
&& splitMode_
== SPLIT_NO
)
861 /* It is disturbing to raise the window more than the first time. */
862 previewOptions
.xpdfAction
= Interaction::PreviewOptions::XPDF_RELOAD
;
866 catch( const NonLocalExit::NotThisType
& ball
)
868 /* Wrong type; never mind!.. but see below!
872 /* This is the default action taken in case non of the types above matched. */
873 interactionFormats
.formatShow( os_
, result_inputNo_
) ;
874 resultUntyped
->show( os_
);
878 Kernel::ExitInteractionContinuation::ExitInteractionContinuation( bool * done
, int * exitCode
, const Ast::SourceLocation
& traceLoc
)
879 : Kernel::Continuation( traceLoc
), done_( done
), exitCode_( exitCode
)
882 Kernel::ExitInteractionContinuation::~ExitInteractionContinuation( )
886 Kernel::ExitInteractionContinuation::takeValue( const RefCountPtr
< const Lang::Value
> & val
, Kernel::EvalState
* evalState
, bool dummy
) const
890 typedef const Lang::Symbol ArgType
;
891 RefCountPtr
< ArgType
> key
= Helpers::try_cast_CoreArgument
< ArgType
>( val
);
893 static Lang::Symbol
CODE_OK( "OK" );
894 static Lang::Symbol
CODE_GENERIC_ERROR( "GenericError" );
895 static Lang::Symbol
CODE_USER_DETECTED_ERROR( "UserDetectedError" );
896 if( *key
== CODE_OK
)
898 *exitCode_
= Interaction::EXIT_OK
;
900 else if( *key
== CODE_GENERIC_ERROR
)
902 *exitCode_
= Interaction::EXIT_GENERIC_ERROR
;
904 else if( *key
== CODE_USER_DETECTED_ERROR
)
906 *exitCode_
= Interaction::EXIT_USER_DETECTED_ERROR
;
910 std::ostringstream oss
;
911 oss
<< "Valid exit codes symbols are { "
912 << CODE_OK
.name( ).getPtr( ) << ", "
913 << CODE_GENERIC_ERROR
.name( ).getPtr( ) << ", "
914 << CODE_USER_DETECTED_ERROR
.name( ).getPtr( )
916 throw Exceptions::OutOfRange( traceLoc_
, strrefdup( oss
) );
922 catch( const NonLocalExit::NotThisType
& ball
)
924 /* Wrong type; never mind!.. but see below!
930 typedef const Lang::Integer ArgType
;
931 *exitCode_
= Helpers::try_cast_CoreArgument
< ArgType
>( val
)->val_
;
932 if( -99 <= *exitCode_
|| *exitCode_
<= 99 )
934 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." );
939 catch( const NonLocalExit::NotThisType
& ball
)
941 /* Wrong type; never mind!.. but see below!
945 throw Exceptions::ContinuationTypeMismatch( this, val
->getTypeName( ), Helpers::typeSetString( Lang::Symbol::staticTypeName( ), Lang::Integer::staticTypeName( ) ) );
949 Kernel::ExitInteractionContinuation::up( ) const
951 return Kernel::ContRef( NullPtr
< Kernel::Continuation
>( ) );
954 RefCountPtr
< const char >
955 Kernel::ExitInteractionContinuation::description( ) const
957 return strrefdup( "exit (non-forcing)" );
961 Kernel::ExitInteractionContinuation::gcMark( Kernel::GCMarkedSet
& marked
)
971 class Mutator_resume
: public Lang::CoreMutator
974 Mutator_resume( const char * name
)
975 : CoreMutator( name
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name
), false ) )
977 formals_
->appendEvaluatedCoreFormal( "result", Kernel::THE_VOID_VARIABLE
);
980 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
982 args
.applyDefaults( callLoc
);
985 StateType
* state
= Helpers::mutator_cast_self
< StateType
>( args
.getMutatorSelf( ) );
986 if( state
->resume_
== NullPtr
< typeof *(state
->resume_
) >( ) )
988 throw Exceptions::CoreRequirement( "The top level debug state has no continuation to resume.", new Interaction::MutatorLocation( state
, name_
), callLoc
);
991 if( args
.getHandle( 0 ) == Kernel::THE_VOID_VARIABLE
&& state
->breakExpr_
!= 0 )
993 /* 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.
994 * 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.
995 * 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
996 * minimum. Hence, using the <ignoreCount_> is preferred.
998 if( state
->breakExpr_
->breakpoint_
!= 0 &&
999 state
->breakExpr_
->breakpoint_
->enabled_
)
1001 ++(state
->breakExpr_
->breakpoint_
->ignoreCount_
);
1003 evalState
->cont_
= state
->resume_
;
1004 evalState
->env_
= state
->env_
->getParent( );
1005 evalState
->dyn_
= state
->dyn_
;
1006 evalState
->expr_
= state
->breakExpr_
;
1010 /* Invoke the escape continuation exactly as in ContinueDynamicECFunction::call.
1012 evalState
->cont_
= state
->resume_
;
1013 evalState
->expr_
= 0;
1014 state
->resume_
->takeHandle( args
.getHandle( 0 ),
1021 class Mutator_top_repl
: public Lang::CoreMutator
1024 Mutator_top_repl( const char * name
)
1025 : CoreMutator( name
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name
), false ) )
1027 formals_
->appendEvaluatedCoreFormal( "result", Kernel::THE_VOID_VARIABLE
);
1030 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1032 args
.applyDefaults( callLoc
);
1034 // typedef T StateType;
1035 // StateType * state = Helpers::mutator_cast_self< StateType >( args.getMutatorSelf( ) );
1037 /* Invoke the escape continuation exactly as in ContinueDynamicECFunction::call.
1039 Kernel::ContRef cont
= evalState
->dyn_
->getEscapeContinuation( Lang::CONTINUATION_TOP_REPL_ID
, callLoc
);
1040 evalState
->cont_
= cont
;
1041 evalState
->expr_
= 0;
1042 cont
->takeHandle( args
.getHandle( 0 ),
1048 class Mutator_cont
: public Lang::CoreMutator
1051 typedef enum { UP
, EXIT_DEBUG
} Kind
;
1055 Mutator_cont( const char * name
, Kind kind
)
1056 : CoreMutator( name
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name
), false ) ),
1059 formals_
->appendEvaluatedCoreFormal( "count", Helpers::newValHandle( new Lang::Integer( 1 ) ) );
1062 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1064 args
.applyDefaults( callLoc
);
1066 /* While activating an already existing interactive continuation allows an old WarmDebugger to be reused as is,
1067 * changing the resume continuation within the current interactive context requires the current WarmDebugger to
1068 * be modified. Hence, to not modify any other state than that that calls this method, the UP mode can not be
1069 * used to reach continuations beyond the next interactive continuation.
1072 /* Note that we don't start counting in state->resume_, but search an interactive continuation from evalState->cont_.
1073 * The reason is that this provides a unified way of obtaining an interactive continuation _below_ the new resume continuation.
1074 * In most cases, this will be exactly what one expects, but in rare cases this behavior may seem strange.
1077 typedef T StateType
;
1078 StateType
* state
= Helpers::mutator_cast_self
< StateType
>( args
.getMutatorSelf( ) );
1081 typedef const Lang::Integer ArgType
;
1082 size_t argsi_count
= argsi
;
1083 int count
= Helpers::down_cast_MutatorArgument
< ArgType
>( state
, name_
, args
, argsi_count
, callLoc
)->val_
;
1086 throw Exceptions::CoreOutOfRange( new Interaction::MutatorLocation( state
, name_
), args
, argsi_count
, "The count must be positive." );
1089 Kernel::ContRef tmp
= evalState
->cont_
;
1090 RefCountPtr
< Kernel::InteractionContinuation
> bottom_interactive
= tmp
.down_cast
< Kernel::InteractionContinuation
>( );
1091 while( bottom_interactive
== NullPtr
< typeof *bottom_interactive
>( ) )
1093 if( tmp
== NullPtr
< Kernel::Continuation
>( ) )
1095 throw Exceptions::CoreOutOfRange( new Interaction::MutatorLocation( state
, name_
), args
, argsi_count
, "There is no interactive continuation in the backtrace to start counting from." );
1098 bottom_interactive
= tmp
.down_cast
< Kernel::InteractionContinuation
>( );
1100 tmp
= bottom_interactive
->resume( );
1104 if( tmp
== NullPtr
< Kernel::Continuation
>( ) )
1106 throw Exceptions::CoreOutOfRange( new Interaction::MutatorLocation( state
, name_
), args
, argsi_count
, "The count exceeds the current depth." );
1108 RefCountPtr
< Kernel::InteractionContinuation
> inter
= tmp
.down_cast
< Kernel::InteractionContinuation
>( );
1109 if( inter
!= NullPtr
< typeof *inter
>( ) )
1113 throw Exceptions::CoreOutOfRange( new Interaction::MutatorLocation( state
, name_
), args
, argsi_count
, "The count exceeds depth down to the next interactive continuations." );
1115 bottom_interactive
= inter
;
1118 /* The continuation will be reused, which corresponds to one decrement of <count>. */
1121 tmp
= bottom_interactive
->resume( );
1133 if( tmp
== NullPtr
< Kernel::Continuation
>( ) )
1135 throw Exceptions::CoreOutOfRange( new Interaction::MutatorLocation( state
, name_
), args
, argsi_count
, "The count exceeds the current depth." );
1138 /* If tmp is an interactive continuation, we reuse it, otherwise we set up a new one.
1140 if( tmp
.down_cast
< Kernel::InteractionContinuation
>( ) != NullPtr
< Kernel::InteractionContinuation
>( ) )
1142 evalState
->cont_
= tmp
;
1148 throw Exceptions::InternalError( "Mutator_cont: Expected kind_ to be UP when unable to reuse continuation." );
1150 RefCountPtr
< Kernel::InteractionContinuation
> inter
= bottom_interactive
->cloneWithNewContinuation( tmp
, state
);
1151 evalState
->cont_
= inter
;
1153 evalState
->expr_
= Kernel::theVoidExpression
;
1158 class Mutator_step
: public Lang::CoreMutator
1160 Kernel::DebugStepInfo::StepMode mode_
;
1162 Mutator_step( const char * name
, Kernel::DebugStepInfo::StepMode mode
)
1163 : CoreMutator( name
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name
), true ) ),
1166 formals_
->appendEvaluatedCoreFormal( "count", Helpers::newValHandle( new Lang::Integer( 1 ) ) );
1169 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1171 args
.applyDefaults( callLoc
);
1173 typedef T StateType
;
1174 StateType
* state
= Helpers::mutator_cast_self
< StateType
>( args
.getMutatorSelf( ) );
1175 if( state
->breakExpr_
== 0 )
1177 throw Exceptions::CoreRequirement( "Currently not at any source location, so source stepping is not possible.", new Interaction::MutatorLocation( state
, name_
), callLoc
);
1181 typedef const Lang::Integer ArgType
;
1182 int count
= Helpers::down_cast_MutatorArgument
< ArgType
>( state
, name_
, args
, argsi
, callLoc
)->val_
;
1185 throw Exceptions::CoreOutOfRange( new Interaction::MutatorLocation( state
, name_
), args
, argsi
, "The count must be at least 1." );
1188 Kernel::theDebugStepInfo
.active_
= true;
1189 Kernel::theDebugStepInfo
.mode_
= mode_
;
1190 Kernel::theDebugStepInfo
.refLoc_
= state
->breakExpr_
->loc( );
1191 Kernel::theDebugStepInfo
.count_
= static_cast< size_t >( count
) + ( ( mode_
== Kernel::DebugStepInfo::EXPR
) ? 1 : 0 );
1193 /* The rest is more or less the same as in Mutator_resume. */
1194 if( state
->breakExpr_
->breakpoint_
!= 0 &&
1195 state
->breakExpr_
->breakpoint_
->enabled_
)
1197 ++(state
->breakExpr_
->breakpoint_
->ignoreCount_
);
1199 evalState
->cont_
= state
->resume_
;
1200 evalState
->env_
= state
->env_
->getParent( );
1201 evalState
->dyn_
= state
->dyn_
;
1202 evalState
->expr_
= state
->breakExpr_
;
1207 class Mutator_step_to_temporary
: public Lang::CoreMutator
1210 typedef enum { CHILD
, SIBLING
} Destination
;
1212 Destination destination_
;
1214 Mutator_step_to_temporary( const char * name
, Destination destination
)
1215 : CoreMutator( name
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name
), true ) ),
1216 destination_( destination
)
1219 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1221 args
.applyDefaults( callLoc
);
1223 typedef T StateType
;
1224 StateType
* state
= Helpers::mutator_cast_self
< StateType
>( args
.getMutatorSelf( ) );
1225 if( state
->breakExpr_
== 0 )
1227 throw Exceptions::CoreRequirement( "Currently not at any source location, so source stepping is not possible.", new Interaction::MutatorLocation( state
, name_
), callLoc
);
1230 /* Now, depending on destination_, temporary breakpoints are set.
1231 * 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
1232 * 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.
1234 size_t count
= 0; /* Count number of expression where we set a temporary breakpoint. */
1236 switch( destination_
)
1240 Ast::Node::ChildrenType
& exprs
= state
->breakExpr_
->children( );
1241 for( Ast::Node::ChildrenType::iterator i
= exprs
.begin( ); i
!= exprs
.end( ); ++i
)
1243 Ast::Expression
* expr
= dynamic_cast< Ast::Expression
* >( *i
);
1249 if( expr
->breakpoint_
== 0 )
1251 expr
->breakpoint_
= new Kernel::BreakpointInfo( );
1252 expr
->breakpoint_
->createdForTemporaryUse_
= true;
1253 Kernel::theBreakpoints
.insert( expr
);
1255 expr
->breakpoint_
->persistentEnabled_
= expr
->breakpoint_
->enabled_
;
1256 expr
->breakpoint_
->enabled_
= true;
1257 Kernel::theTemporaryBreakpoints
.insert( expr
);
1263 Ast::Node
* parent
= state
->breakExpr_
->parent( );
1266 throw Exceptions::CoreRequirement( "Unable to locate siblings since there is no parent here.", new Interaction::MutatorLocation( state
, name_
), callLoc
);
1268 Ast::Node::ChildrenType
& exprs
= parent
->children( );
1269 for( Ast::Node::ChildrenType::iterator i
= exprs
.begin( ); i
!= exprs
.end( ); ++i
)
1271 Ast::Expression
* expr
= dynamic_cast< Ast::Expression
* >( *i
);
1272 if( expr
== 0 || expr
== state
->breakExpr_
)
1277 if( expr
->breakpoint_
== 0 )
1279 expr
->breakpoint_
= new Kernel::BreakpointInfo( );
1280 expr
->breakpoint_
->createdForTemporaryUse_
= true;
1281 Kernel::theBreakpoints
.insert( expr
);
1283 expr
->breakpoint_
->persistentEnabled_
= expr
->breakpoint_
->enabled_
;
1284 expr
->breakpoint_
->enabled_
= true;
1285 Kernel::theTemporaryBreakpoints
.insert( expr
);
1293 throw Exceptions::CoreRequirement( "No temporary breakpoints were set. Not resuming evaluation.", new Interaction::MutatorLocation( state
, name_
), callLoc
);
1296 /* The rest is more or less the same as in Mutator_resume. */
1297 if( state
->breakExpr_
->breakpoint_
!= 0 &&
1298 state
->breakExpr_
->breakpoint_
->enabled_
)
1300 ++(state
->breakExpr_
->breakpoint_
->ignoreCount_
);
1302 evalState
->cont_
= state
->resume_
;
1303 evalState
->env_
= state
->env_
->getParent( );
1304 evalState
->dyn_
= state
->dyn_
;
1305 evalState
->expr_
= state
->breakExpr_
;
1310 class Mutator_backtrace
: public Lang::CoreMutator
1313 Mutator_backtrace( const char * name
)
1314 : CoreMutator( name
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name
), true ) )
1318 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1320 args
.applyDefaults( callLoc
);
1322 typedef T StateType
;
1323 StateType
* state
= Helpers::mutator_cast_self
< StateType
>( args
.getMutatorSelf( ) );
1325 std::ostringstream oss
;
1327 typedef std::list
< std::pair
< const Kernel::Continuation
*, RefCountPtr
< const char > > > ListType
;
1329 size_t debugDepth
= 0;
1330 trace
.push_front( ListType::value_type( 0, strrefdup( "==( bottom resume )==" ) ) );
1331 const Kernel::Continuation
* tmp
= state
->resume_
.getPtr( );
1332 while( tmp
!= NullPtr
< Kernel::Continuation
>( ) )
1334 trace
.push_front( ListType::value_type( tmp
, tmp
->description( ) ) );
1335 const Kernel::InteractionContinuation
* inter
= dynamic_cast< const Kernel::InteractionContinuation
* >( tmp
);
1338 tmp
= inter
->resume( ).getPtr( );
1341 trace
.push_front( ListType::value_type( 0, strrefdup( "--( next resume )--" ) ) );
1347 tmp
= tmp
->up( ).getPtr( );
1350 trace
.push_front( ListType::value_type( 0, strrefdup( "==( top )==" ) ) );
1352 oss
<< std::endl
; /* Ensure we start on a new line. */
1353 ListType::const_iterator i
= trace
.begin( );
1354 for( ; i
!= trace
.end( ); ++i
)
1358 oss
<< i
->second
<< std::endl
;
1362 oss
<< " " << i
->first
->traceLoc( ) << "\t" << i
->second
<< std::endl
;
1367 Kernel::ContRef cont
= evalState
->cont_
;
1368 cont
->takeValue( Kernel::ValueRef( new Lang::String( strrefdup( oss
) ) ),
1374 class Mutator_printEnv
: public Lang::CoreMutator
1377 Mutator_printEnv( const char * name
)
1378 : CoreMutator( name
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name
), true ) )
1382 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1384 args
.applyDefaults( callLoc
);
1386 typedef T StateType
;
1387 StateType
* state
= Helpers::mutator_cast_self
< StateType
>( args
.getMutatorSelf( ) );
1389 std::ostringstream oss
;
1390 oss
<< std::endl
; /* Ensure we start on a new line. */
1391 state
->env_
->print( oss
);
1393 Kernel::ContRef cont
= evalState
->cont_
;
1394 cont
->takeValue( Kernel::ValueRef( new Lang::String( strrefdup( oss
) ) ),
1400 class Mutator_printDyn
: public Lang::CoreMutator
1403 Mutator_printDyn( const char * name
)
1404 : CoreMutator( name
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name
), true ) )
1408 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1410 args
.applyDefaults( callLoc
);
1412 typedef T StateType
;
1413 StateType
* state
= Helpers::mutator_cast_self
< StateType
>( args
.getMutatorSelf( ) );
1415 std::ostringstream oss
;
1416 oss
<< std::endl
; /* Ensure we start on a new line. */
1417 state
->dyn_
->print( oss
);
1419 Kernel::ContRef cont
= evalState
->cont_
;
1420 cont
->takeValue( Kernel::ValueRef( new Lang::String( strrefdup( oss
) ) ),
1426 class Mutator_printBreakpoints
: public Lang::CoreMutator
1429 Mutator_printBreakpoints( const char * name
)
1430 : CoreMutator( name
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name
), true ) )
1434 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1436 args
.applyDefaults( callLoc
);
1438 // typedef T StateType;
1439 // StateType * state = Helpers::mutator_cast_self< StateType >( args.getMutatorSelf( ) );
1441 std::ostringstream oss
;
1442 oss
<< std::endl
; /* Ensure we start on a new line. */
1443 typedef typeof Kernel::theBreakpoints ListType
;
1445 for( ListType::const_iterator i
= Kernel::theBreakpoints
.begin( ); i
!= Kernel::theBreakpoints
.end( ); ++i
, ++index
)
1447 oss
<< std::setw(3) << index
<< ( ( (*i
)->breakpoint_
->enabled_
) ? " (on )" : " (off)" ) ;
1448 if( (*i
)->breakpoint_
->ignoreCount_
> 0 )
1450 oss
<< " (ignore " << (*i
)->breakpoint_
->ignoreCount_
<< " times)" ;
1452 oss
<< ": " << (*i
)->loc( ) << std::endl
;
1455 Kernel::ContRef cont
= evalState
->cont_
;
1456 cont
->takeValue( Kernel::ValueRef( new Lang::String( strrefdup( oss
) ) ),
1462 class Mutator_clearBreak
: public Lang::CoreMutator
1465 Mutator_clearBreak( const char * name
)
1466 : CoreMutator( name
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name
), true ) )
1468 formals_
->appendEvaluatedCoreFormal( "index", Helpers::newValHandle( new Lang::Integer( 0 ) ) );
1471 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1473 args
.applyDefaults( callLoc
);
1475 typedef T StateType
;
1476 StateType
* state
= Helpers::mutator_cast_self
< StateType
>( args
.getMutatorSelf( ) );
1479 typedef const Lang::Integer ArgType
;
1480 int index
= Helpers::down_cast_MutatorArgument
< ArgType
>( state
, name_
, args
, argsi
, callLoc
)->val_
;
1483 if( state
->breakExpr_
== 0 )
1485 throw Exceptions::CoreOutOfRange( new Interaction::MutatorLocation( state
, name_
), args
, argsi
, "Currently not at any source location, so the breakpoint index 0 is invalid." );
1488 if( index
< 0 || static_cast< int >( Kernel::theBreakpoints
.size( ) ) < index
)
1490 throw Exceptions::CoreOutOfRange( new Interaction::MutatorLocation( state
, name_
), args
, argsi
, "The index must be either zero (meaning the current breakpoint) or a positive number not greater than the number of breakpoints." );
1494 Ast::Expression
* expr
= state
->breakExpr_
;
1495 if( expr
->breakpoint_
!= 0 )
1497 delete expr
->breakpoint_
;
1498 expr
->breakpoint_
= 0;
1499 Kernel::theBreakpoints
.erase( expr
);
1504 typedef typeof Kernel::theBreakpoints SetType
;
1505 SetType::iterator i
= Kernel::theBreakpoints
.begin( );
1506 for( int tmp
= 1; tmp
< index
; ++tmp
, ++i
)
1508 delete (*i
)->breakpoint_
;
1509 (*i
)->breakpoint_
= 0;
1510 Kernel::theBreakpoints
.erase( *i
);
1513 Kernel::ContRef cont
= evalState
->cont_
;
1514 cont
->takeValue( Lang::THE_VOID
,
1520 class Mutator_clearAllBreak
: public Lang::CoreMutator
1523 Mutator_clearAllBreak( const char * name
)
1524 : CoreMutator( name
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name
), true ) )
1528 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1530 args
.applyDefaults( callLoc
);
1532 /* The state is not used at the moment. */
1533 // typedef T StateType;
1534 // StateType * state = Helpers::mutator_cast_self< StateType >( args.getMutatorSelf( ) );
1536 typedef typeof Kernel::theBreakpoints SetType
;
1537 for( SetType::iterator i
= Kernel::theBreakpoints
.begin( ); i
!= Kernel::theBreakpoints
.end( ); ++i
)
1539 delete (*i
)->breakpoint_
;
1540 (*i
)->breakpoint_
= 0;
1542 Kernel::theBreakpoints
.clear( );
1544 Kernel::ContRef cont
= evalState
->cont_
;
1545 cont
->takeValue( Lang::THE_VOID
,
1551 class Mutator_ignoreBreak
: public Lang::CoreMutator
1554 Mutator_ignoreBreak( const char * name
)
1555 : CoreMutator( name
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name
), true ) )
1557 formals_
->appendEvaluatedCoreFormal( "index", Helpers::newValHandle( new Lang::Integer( 0 ) ) );
1558 formals_
->appendEvaluatedCoreFormal( "count", Helpers::newValHandle( new Lang::Integer( 1 ) ) );
1561 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1563 args
.applyDefaults( callLoc
);
1565 typedef T StateType
;
1566 StateType
* state
= Helpers::mutator_cast_self
< StateType
>( args
.getMutatorSelf( ) );
1569 typedef const Lang::Integer ArgType
;
1570 int index
= Helpers::down_cast_MutatorArgument
< ArgType
>( state
, name_
, args
, argsi
, callLoc
)->val_
;
1573 if( state
->breakExpr_
== 0 )
1575 throw Exceptions::CoreOutOfRange( new Interaction::MutatorLocation( state
, name_
), args
, argsi
, "Currently not at any source location, so the breakpoint index 0 is invalid." );
1578 else if( index
< 0 || static_cast< int >( Kernel::theBreakpoints
.size( ) ) < index
)
1580 throw Exceptions::CoreOutOfRange( new Interaction::MutatorLocation( state
, name_
), args
, argsi
, "The index must be either zero (meaning the current breakpoint) or a positive number not greater than the number of breakpoints." );
1583 int count
= Helpers::down_cast_MutatorArgument
< ArgType
>( state
, name_
, args
, argsi
, callLoc
)->val_
;
1586 throw Exceptions::CoreOutOfRange( new Interaction::MutatorLocation( state
, name_
), args
, argsi
, "The count must be non-negative." );
1590 Ast::Expression
* expr
= state
->breakExpr_
;
1591 if( expr
->breakpoint_
== 0 )
1593 expr
->breakpoint_
= new Kernel::BreakpointInfo( );
1594 Kernel::theBreakpoints
.insert( expr
);
1596 expr
->breakpoint_
->ignoreCount_
= static_cast< size_t >( count
);
1600 typedef typeof Kernel::theBreakpoints SetType
;
1601 SetType::iterator i
= Kernel::theBreakpoints
.begin( );
1602 for( int tmp
= 1; tmp
< index
; ++tmp
, ++i
)
1604 (*i
)->breakpoint_
->ignoreCount_
= static_cast< size_t >( count
);
1607 Kernel::ContRef cont
= evalState
->cont_
;
1608 cont
->takeValue( Lang::THE_VOID
,
1615 class Mutator_setBreakLocation
: public Lang::CoreMutator
1618 Mutator_setBreakLocation( const char * name
)
1619 : CoreMutator( name
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name
), true ) )
1621 formals_
->appendEvaluatedCoreFormal( "file", Kernel::THE_SLOT_VARIABLE
);
1622 formals_
->appendEvaluatedCoreFormal( "line", Kernel::THE_SLOT_VARIABLE
);
1623 formals_
->appendEvaluatedCoreFormal( "column", Helpers::newValHandle( new Lang::Integer( 0 ) ) );
1624 formals_
->appendEvaluatedCoreFormal( "enable", Kernel::THE_VOID_VARIABLE
);
1627 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1629 args
.applyDefaults( callLoc
);
1631 /* The state is only used for error handling at the moment. */
1632 typedef T StateType
;
1633 StateType
* state
= Helpers::mutator_cast_self
< StateType
>( args
.getMutatorSelf( ) );
1636 struct stat theStat
;
1637 std::string fileArg
= Helpers::down_cast_MutatorArgument
< const Lang::String
>( state
, name_
, args
, argsi
, callLoc
)->val_
.getPtr( );
1639 int line
= Helpers::down_cast_MutatorArgument
< const Lang::Integer
>( state
, name_
, args
, argsi
, callLoc
)->val_
;
1642 throw Exceptions::CoreOutOfRange( new Interaction::MutatorLocation( state
, name_
), args
, argsi
, "The line number must be positive." );
1645 int column
= Helpers::down_cast_MutatorArgument
< const Lang::Integer
>( state
, name_
, args
, argsi
, callLoc
)->val_
;
1648 throw Exceptions::CoreOutOfRange( new Interaction::MutatorLocation( state
, name_
), args
, argsi
, "The column number must be non-negative." );
1651 RefCountPtr
< const Lang::Boolean
> breakPtr
= Helpers::down_cast_MutatorArgument
< const Lang::Boolean
>( state
, name_
, args
, argsi
, callLoc
, true );
1653 const Ast::FileID
* fileID
= 0;
1654 if( ! Ast::FileID::is_inMemory( fileArg
, & fileID
) )
1658 std::string filename
= Ast::theShapesScanner
.searchFile( fileArg
, & theStat
);
1659 fileID
= Ast::FileID::build_stat( theStat
, fileArg
);
1661 catch( const Exceptions::Exception
& ball
)
1663 throw Exceptions::CoreOutOfRange( new Interaction::MutatorLocation( state
, name_
), args
, 0, "Failed to locate source file." );
1666 Ast::SourceLocation
loc( fileID
); /* Warning: Automatic storage of Ast::SourceLocation, don't create references to this! */
1667 loc
.firstLine
= line
;
1668 loc
.lastLine
= line
;
1669 if( Interaction::characterColumnInBytes
)
1671 loc
.firstColumn
= column
;
1672 loc
.lastColumn
= column
;
1676 /* Column is the UTF8 column, and needs to be converted to byte column. */
1679 int byteColumn
= fileID
->UTF8ColumnTobyteColumn( line
, column
);
1680 loc
.firstColumn
= byteColumn
;
1681 loc
.lastColumn
= byteColumn
;
1683 catch( const Exceptions::OutOfRange
& ball
)
1685 /* Without actually looking into ball we guess what the problem is... */
1686 throw Exceptions::CoreOutOfRange( new Interaction::MutatorLocation( state
, name_
), args
, 1, "Line seems past end of file." );
1689 Ast::Expression
* expr
= loc
.findExpression( );
1692 throw Exceptions::CoreOutOfRange( new Interaction::MutatorLocation( state
, name_
), args
, 0, "Failed to locate position within the source file." );
1694 if( expr
->breakpoint_
== 0 )
1696 expr
->breakpoint_
= new Kernel::BreakpointInfo( );
1697 Kernel::theBreakpoints
.insert( expr
);
1701 if( breakPtr
== NullPtr
< const Lang::Boolean
>( ) )
1703 newEnabled
= ! expr
->breakpoint_
->enabled_
;
1707 newEnabled
= breakPtr
->val_
;
1710 expr
->breakpoint_
->enabled_
= newEnabled
;
1712 Kernel::ContRef cont
= evalState
->cont_
;
1713 cont
->takeValue( Lang::THE_VOID
,
1719 class Mutator_setBreakFunctionBody
: public Lang::CoreMutator
1722 Mutator_setBreakFunctionBody( const char * name
)
1723 : CoreMutator( name
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name
), true ) )
1725 formals_
->appendEvaluatedCoreFormal( "function", Kernel::THE_SLOT_VARIABLE
);
1726 formals_
->appendEvaluatedCoreFormal( "enable", Kernel::THE_VOID_VARIABLE
);
1729 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1731 args
.applyDefaults( callLoc
);
1733 /* The state is only used for error handling at the moment. */
1734 typedef T StateType
;
1735 StateType
* state
= Helpers::mutator_cast_self
< StateType
>( args
.getMutatorSelf( ) );
1738 typedef const Lang::UserFunction ArgType
;
1739 RefCountPtr
< ArgType
> fun
= Helpers::down_cast_MutatorArgument
< ArgType
>( state
, name_
, args
, argsi
, callLoc
);
1741 RefCountPtr
< const Lang::Boolean
> breakPtr
= Helpers::down_cast_MutatorArgument
< const Lang::Boolean
>( state
, name_
, args
, argsi
, callLoc
, true );
1743 Ast::Expression
* expr
= const_cast< Lang::UserFunction
* >( fun
.getPtr( ) )->body( );
1744 if( expr
->breakpoint_
== 0 )
1746 expr
->breakpoint_
= new Kernel::BreakpointInfo( );
1747 Kernel::theBreakpoints
.insert( expr
);
1751 if( breakPtr
== NullPtr
< const Lang::Boolean
>( ) )
1753 newEnabled
= ! expr
->breakpoint_
->enabled_
;
1757 newEnabled
= breakPtr
->val_
;
1760 expr
->breakpoint_
->enabled_
= newEnabled
;
1762 Kernel::ContRef cont
= evalState
->cont_
;
1763 cont
->takeValue( Lang::THE_VOID
,
1771 Kernel::WarmDebugger::WarmDebugger( Kernel::Environment
* env
, Kernel::PassedDyn dyn
, Kernel::ContRef resume
, Ast::Expression
* breakExpr
)
1772 : env_( env
), dyn_( dyn
), resume_( resume
), breakExpr_( breakExpr
)
1775 Kernel::WarmDebugger::~WarmDebugger( )
1779 Debugger_register_mutators( Lang::SystemFinalClass
* dstClass
)
1781 dstClass
->registerMutator( new Kernel::Mutator_resume
< Kernel::WarmDebugger
>( "resume" ), "r" );
1782 dstClass
->registerMutator( new Kernel::Mutator_top_repl
< Kernel::WarmDebugger
>( "top_repl" ) );
1783 dstClass
->registerMutator( new Kernel::Mutator_backtrace
< Kernel::WarmDebugger
>( "backtrace" ), "t" );
1784 dstClass
->registerMutator( new Kernel::Mutator_printEnv
< Kernel::WarmDebugger
>( "env" ), "e" );
1785 dstClass
->registerMutator( new Kernel::Mutator_printDyn
< Kernel::WarmDebugger
>( "dyn" ), "d" );
1786 dstClass
->registerMutator( new Kernel::Mutator_printBreakpoints
< Kernel::WarmDebugger
>( "breakList" ), "bl" );
1787 dstClass
->registerMutator( new Kernel::Mutator_setBreakLocation
< Kernel::WarmDebugger
>( "breakAt" ), "ba" );
1788 dstClass
->registerMutator( new Kernel::Mutator_setBreakFunctionBody
< Kernel::WarmDebugger
>( "breakIn" ), "bi" );
1789 dstClass
->registerMutator( new Kernel::Mutator_ignoreBreak
< Kernel::WarmDebugger
>( "breakIgnore" ), "bg" );
1790 dstClass
->registerMutator( new Kernel::Mutator_clearBreak
< Kernel::WarmDebugger
>( "breakClear" ), "bc" );
1791 dstClass
->registerMutator( new Kernel::Mutator_clearAllBreak
< Kernel::WarmDebugger
>( "breakClearAll" ), "bC" );
1792 dstClass
->registerMutator( new Kernel::Mutator_step
< Kernel::WarmDebugger
>( "stepe", Kernel::DebugStepInfo::EXPR
), "se" );
1793 dstClass
->registerMutator( new Kernel::Mutator_step
< Kernel::WarmDebugger
>( "step", Kernel::DebugStepInfo::STEP
), "s" );
1794 dstClass
->registerMutator( new Kernel::Mutator_step_to_temporary
< Kernel::WarmDebugger
>( "stepc", Kernel::Mutator_step_to_temporary
< Kernel::WarmDebugger
>::CHILD
), "sc" );
1795 dstClass
->registerMutator( new Kernel::Mutator_step_to_temporary
< Kernel::WarmDebugger
>( "steps", Kernel::Mutator_step_to_temporary
< Kernel::WarmDebugger
>::SIBLING
), "ss" );
1796 dstClass
->registerMutator( new Kernel::Mutator_cont
< Kernel::WarmDebugger
>( "contUp", Kernel::Mutator_cont
< Kernel::WarmDebugger
>::UP
), "cu" );
1797 dstClass
->registerMutator( new Kernel::Mutator_cont
< Kernel::WarmDebugger
>( "contExit", Kernel::Mutator_cont
< Kernel::WarmDebugger
>::EXIT_DEBUG
), "ce" );
1800 RefCountPtr
< const Lang::Class
> Kernel::WarmDebugger::TypeID( new Lang::SystemFinalClass( strrefdup( "#Debugger" ), Debugger_register_mutators
) );
1801 TYPEINFOIMPL_STATE( WarmDebugger
);
1804 Kernel::WarmDebugger::tackOnImpl( Kernel::EvalState
* evalState
, const RefCountPtr
< const Lang::Value
> & piece
,const Ast::SourceLocation
& callLoc
)
1806 throw Exceptions::MiscellaneousRequirement( strrefdup( "The debugger only interacts through named mutators; there is no tack-on mutator." ) );
1810 Kernel::WarmDebugger::freezeImpl( Kernel::EvalState
* evalState
, const Ast::SourceLocation
& callLoc
)
1812 throw Exceptions::MiscellaneousRequirement( strrefdup( "The debugger cannot be frozen." ) );
1816 Kernel::WarmDebugger::peekImpl( Kernel::EvalState
* evalState
, const Ast::SourceLocation
& callLoc
)
1818 throw Exceptions::MiscellaneousRequirement( strrefdup( "The debugger cannot be peeked." ) );
1822 Kernel::WarmDebugger::gcMark( Kernel::GCMarkedSet
& marked
)
1826 Kernel::BreakpointInfo::BreakpointInfo( )
1827 : enabled_( false ), createdForTemporaryUse_( false ), ignoreCount_( 0 )
1830 Kernel::BreakpointInfo::~BreakpointInfo( )