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"
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_
;
100 : active_( false ), mode_( EXPR
), refLoc_( Ast::THE_UNKNOWN_LOCATION
), 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 /* Clean up outout from earlier sessions. */
157 rmSplitFiles( outputName
, "-" );
162 mkSplitDir( outputName
);
163 rmSplitFiles( outputName
, "/" );
168 RefCountPtr
< const Kernel::GraphicsState
> graphicsState( new Kernel::GraphicsState( true ) );
169 Kernel::PassedDyn
baseDyn( new Kernel::DynamicEnvironment( graphicsState
) );
173 /* Evaluate preamble. */
175 initCore( labelDBFile
, labelDBName
);
178 Kernel::ValueRef resultUntyped
= NullPtr
< const Lang::Value
>( );
179 Kernel::EvalState
evalState( Ast::theProgram
,
180 Kernel::theGlobalEnvironment
,
182 Kernel::ContRef( new Kernel::StoreValueContinuation( & resultUntyped
,
183 Kernel::ContRef( new Kernel::ExitContinuation( & done
, Ast::theProgram
->loc( ) ) ),
184 Ast::theProgram
->loc( ) ) ) );
187 Ast::Expression
* expr
= evalState
.expr_
;
188 expr
->eval( & evalState
);
191 catch( const Exceptions::StaticInconsistency
& ball
)
194 std::cerr
<< ball
.loc( ) << ": " ;
195 ball
.display( std::cerr
);
196 std::cerr
<< "There were errors in the preamble. Aborting interactive evaluation." ;
197 abortProcedure( ball
.exitCode( ) );
199 catch( const Exceptions::Exception
& ball
)
202 ball
.display( std::cerr
);
203 std::cerr
<< "There were errors in the preamble. Aborting interactive evaluation." ;
204 abortProcedure( ball
.exitCode( ) );
207 Ast::theShapesScanner
.setInteractive( true ); /* Do this after reading the preamble! */
209 /* Find the prelude environment... */
210 Kernel::Environment
* preludeEnv
= 0;
211 for( std::list
< Kernel::Environment
* >::iterator e
= Kernel::theEnvironmentList
.begin( ); e
!= Kernel::theEnvironmentList
.end( ); ++e
)
215 if( (*e
)->getParent( ) == Kernel::theGlobalEnvironment
)
221 catch( const Exceptions::MiscellaneousRequirement
& ball
)
223 /* That was the global environment, which doesn't have a parent. Never mind. */
226 if( preludeEnv
== 0 )
228 std::cerr
<< "Internal error: Failed to locate prelude environment." << std::endl
;
229 exit( Interaction::EXIT_INTERNAL_ERROR
);
231 Ast::AnalysisEnvironment
* preludeAnalysisEnvironment
= preludeEnv
->newAnalysisEnvironment( Ast::theGlobalAnalysisEnvironment
);
233 Ast::CodeBracket
* initialBracket( new Ast::CodeBracket( Ast::SourceLocation( Ast::FileID::build_internal( "{ interactive }" ) ), new std::list
< Ast::Node
* >( ) ) );
235 Ast::StateIDSet freeStates
;
236 initialBracket
->analyze( Ast::theProgram
, preludeAnalysisEnvironment
, & freeStates
);
238 Kernel::Environment
* bracketEnv
= initialBracket
->newEnvironment( preludeEnv
, "Interaction" );
239 bracketEnv
->initDefine( "db", new Kernel::WarmDebugger( bracketEnv
, baseDyn
, Kernel::ContRef( NullPtr
< Kernel::Continuation
>( ) ), 0 ) );
241 int exitCode
= Interaction::EXIT_OK
;
243 RefCountPtr
< Kernel::InteractionContinuation
> interactionCont
244 ( new Kernel::InteractionContinuation( preludeAnalysisEnvironment
, initialBracket
, bracketEnv
, Kernel::ContRef( NullPtr
< Kernel::Continuation
>( ) ), baseDyn
, 0, Kernel::NO_INPUT_INPUT_NO
,
245 in
, out
, outputName
, splitMode
,
246 initialBracket
->loc( ) ) );
247 Kernel::PassedDyn
interactionDyn( new Kernel::DynamicEnvironment( Kernel::PassedDyn( new Kernel::DynamicEnvironment( baseDyn
, "bye", Kernel::ContRef( new Kernel::ExitInteractionContinuation( & Kernel::theInteractionDone
, & exitCode
, initialBracket
->loc( ) ) ) ) ),
248 Lang::CONTINUATION_TOP_REPL_ID
, interactionCont
) );
249 interactionCont
->setDyn( interactionDyn
);
251 Kernel::EvalState
evalState( Kernel::theVoidExpression
, /* This will invoke the continuation first thing. */
252 Kernel::theGlobalEnvironment
, /* Dummy value */
253 baseDyn
, /* Dummy value */
256 while( ! Kernel::theInteractionDone
)
258 Ast::Expression
* expr
= evalState
.expr_
;
259 if( Kernel::theDebugStepInfo
.active_
&& Kernel::theDebugStepInfo
.stop( expr
->loc( ) ) )
261 out
<< "Reached " << expr
->loc( ) << "." << std::endl
;
262 evalState
.cont_
= Kernel::ContRef( new Kernel::InteractionContinuation( evalState
, Kernel::NO_INPUT_INPUT_NO
, in
, out
, outputName
, splitMode
) );
263 evalState
.expr_
= Kernel::theVoidExpression
;
264 Kernel::theDebugStepInfo
.active_
= false;
267 if( expr
->breakpoint_
!= 0 && expr
->breakpoint_
->enabled_
)
269 if( expr
->breakpoint_
->ignoreCount_
> 0 )
271 /* Don't break this time, but re-enable breaking in the future. */
272 --(expr
->breakpoint_
->ignoreCount_
);
276 out
<< "Stopping at breakpoint " << expr
->loc( ) << "." << std::endl
;
277 typedef typeof Kernel::theTemporaryBreakpoints SetType
;
278 for( SetType::iterator i
= Kernel::theTemporaryBreakpoints
.begin( ); i
!= Kernel::theTemporaryBreakpoints
.end( ); ++i
)
280 if( (*i
)->breakpoint_
->createdForTemporaryUse_
)
282 delete (*i
)->breakpoint_
;
283 (*i
)->breakpoint_
= 0;
284 Kernel::theBreakpoints
.erase( *i
);
288 (*i
)->breakpoint_
->enabled_
= (*i
)->breakpoint_
->persistentEnabled_
;
291 Kernel::theTemporaryBreakpoints
.clear( );
292 evalState
.cont_
= Kernel::ContRef( new Kernel::InteractionContinuation( evalState
, Kernel::NO_INPUT_INPUT_NO
, in
, out
, outputName
, splitMode
) );
293 evalState
.expr_
= Kernel::theVoidExpression
;
294 Kernel::theDebugStepInfo
.active_
= false;
303 expr
->eval( & evalState
);
305 catch( const Exceptions::CatchableError
& ball
)
307 Kernel::ContRef cont
= evalState
.dyn_
->getEscapeContinuation( Lang::CONTINUATION_ID_ERROR
, ball
.getLoc( ) );
308 cont
->takeValue( ball
.clone( evalState
.cont_
),
313 catch( const Exceptions::StaticInconsistency
& ball
)
316 out
<< ball
.loc( ) << ": " ;
319 catch( const Exceptions::Exception
& ball
)
322 if( Interaction::debugBacktrace
)
324 evalState
.cont_
->backTrace( out
);
329 const Exceptions::RuntimeError
& rerr
= dynamic_cast< const Exceptions::RuntimeError
& >( ball
);
330 if( rerr
.getLoc( ).isUnknown( ) )
332 throw std::bad_cast( ); /* It's not a bad cast, but the cast value is just as little useful as a bad cast. */
334 out
<< rerr
.getLoc( ) << Exceptions::Exception::locsep
;
336 catch( std::bad_cast
& bad_cast_ball
)
338 out
<< evalState
.cont_
->traceLoc( ) << Exceptions::Exception::locsep
;
342 if( Kernel::interactive_debug
)
344 Kernel::InteractionContinuation
* iCont
= dynamic_cast< Kernel::InteractionContinuation
* >( evalState
.cont_
.getPtr( ) );
345 if( iCont
!= 0 && iCont
->reusable( evalState
) )
347 /* We don't create a new interactive continuation if the active continuation is already an interactive continuation.
348 * For instance, failing to set a breakpoint is not something that's interesting to debug in itself.
350 out
<< "Reusing interactive continuation." << std::endl
;
352 else if( evalState
.expr_
!= 0 )
354 evalState
.cont_
= Kernel::ContRef( new Kernel::InteractionContinuation( evalState
, Kernel::NO_INPUT_INPUT_NO
, in
, out
, outputName
, splitMode
) );
358 /* We interpret this situation as a failure to explicitly apply a continuation.
359 * See ContinueDynamicECFunction::call .
361 evalState
.cont_
= Kernel::ContRef( new Kernel::InteractionContinuation
362 ( preludeAnalysisEnvironment
, initialBracket
, bracketEnv
, evalState
.cont_
,
363 Kernel::PassedDyn( new Kernel::DynamicEnvironment( baseDyn
, "resume", evalState
.cont_
) ),
365 Kernel::NO_INPUT_INPUT_NO
,
366 in
, out
, outputName
, splitMode
,
367 initialBracket
->loc( ) ) );
372 evalState
.cont_
= interactionCont
;
374 Kernel::theDebugStepInfo
.active_
= false;
375 evalState
.expr_
= Kernel::theVoidExpression
;
378 /* Someone ended the input stream or invoked the exit continuation.
379 * For now, we circumvent the normal termination procedures in <main> by exiting here,
380 * which is similar to stopping the program by pressing ctrl-c, which is probably what
381 * most people will do anyway.
387 Interaction::InteractionFormats::InteractionFormats( )
388 : prompt_( "[%!#!!3R] " ),
389 show_( "%!#!!3R ⇒ " ),
395 Interaction::InteractionFormats::setPrompt( const char * format
)
401 Interaction::InteractionFormats::setShow( const char * format
)
407 Interaction::InteractionFormats::setFile( const char * format
)
413 Interaction::InteractionFormats::setBye( const char * format
)
419 Interaction::InteractionFormats::formatPrompt( std::ostream
& os
, size_t inputNo
) const
421 writePrompt( os
, prompt_
, inputNo
);
425 Interaction::InteractionFormats::formatShow( std::ostream
& os
, size_t inputNo
) const
427 writePrompt( os
, show_
, inputNo
);
431 Interaction::InteractionFormats::formatFile( std::ostream
& os
, size_t inputNo
) const
433 writePrompt( os
, file_
, inputNo
);
437 Interaction::InteractionFormats::formatBye( std::ostream
& os
, size_t inputNo
) const
439 writePrompt( os
, bye_
, inputNo
);
443 Interaction::InteractionFormats::writePrompt( std::ostream
& os
, const char * format
, size_t inputNo
) const
445 for( const char * src
= format
; *src
!= '\0'; ++src
)
450 const char sep
= *src
;
452 std::ostringstream noStr
;
457 std::cerr
<< "Bad interactive prompt format string (expected second '" << sep
<< "'): " << format
<< std::endl
;
458 exit( Interaction::EXIT_INVOCATION_ERROR
);
463 writeEscape( noStr
, *src
);
477 std::cerr
<< "Bad interactive prompt format string (expected third '" << sep
<< "'): " << format
<< std::endl
;
478 exit( Interaction::EXIT_INVOCATION_ERROR
);
483 writeEscape( noStr
, *src
);
493 int width
= strtol( src
, & endp
, 10 );
498 else if( width
< 0 || width
> 10 )
500 std::cerr
<< "Bad interactive prompt format string (the width " << width
<< " is out of the range [0,10]): " << format
<< std::endl
;
501 exit( Interaction::EXIT_INVOCATION_ERROR
);
508 os
.setf(std::ios::left
);
511 os
.setf(std::ios::right
);
514 std::cerr
<< "Bad interactive prompt format string (expected 'L' or 'R' after '%'): " << format
<< std::endl
;
515 exit( Interaction::EXIT_INVOCATION_ERROR
);
519 os
<< std::setw(width
) ;
523 else if( *src
== '\\' )
526 writeEscape( os
, *src
);
536 Interaction::InteractionFormats::writeEscape( std::ostream
& os
, char c
) const
560 Ast::VoidExpression::VoidExpression( const Ast::SourceLocation
& loc
)
561 : Ast::Expression( loc
)
564 Ast::VoidExpression::~VoidExpression( )
568 Ast::VoidExpression::analyze_impl( Ast::Node
* parent
, Ast::AnalysisEnvironment
* env
, Ast::StateIDSet
* freeStatesDst
)
574 Ast::VoidExpression::eval( Kernel::EvalState
* evalState
) const
576 Kernel::ContRef cont
= evalState
->cont_
;
577 cont
->takeValue( Lang::THE_VOID
,
581 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
)
582 : 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
)
585 Ast::SourceLocation
debug_loc( Ast::FileID::build_internal( "{ debug }" ) );
587 Kernel::InteractionContinuation::InteractionContinuation( Kernel::EvalState
& evalState
, int result_inputNo
, std::istream
& is
, std::ostream
& os
, const std::string
& outputName
, SplitMode splitMode
)
588 : Kernel::Continuation( evalState
.expr_
->loc( ) ),
589 parentAnalysisEnv_( evalState
.expr_
->getEnv( ) ),
590 bracket_( new Ast::CodeBracket( debug_loc
, new std::list
< Ast::Node
* >( ) ) ),
591 env_( bracket_
->newEnvironment( evalState
.env_
, "Debug" ) ),
592 resume_( evalState
.cont_
),
593 dyn_( new Kernel::DynamicEnvironment( evalState
.dyn_
, "resume", resume_
) ),
594 breakExpr_( evalState
.expr_
),
595 result_inputNo_( result_inputNo
),
596 is_( is
), os_( os
), outputName_( outputName
), splitMode_( splitMode
)
599 Ast::StateIDSet freeStates
;
600 bracket_
->analyze( evalState
.expr_
, parentAnalysisEnv_
, & freeStates
);
602 env_
->initDefine( "db", new Kernel::WarmDebugger( env_
, dyn_
, resume_
, breakExpr_
) );
603 env_
->initDefineHandle( "expr", Kernel::VariableHandle( new Kernel::Variable( new Kernel::Thunk( evalState
.env_
, evalState
.dyn_
, evalState
.expr_
) ) ) );
606 Kernel::InteractionContinuation::~InteractionContinuation( )
609 RefCountPtr
< Kernel::InteractionContinuation
>
610 Kernel::InteractionContinuation::cloneWithNewContinuation( Kernel::ContRef resume
, Kernel::WarmDebugger
* state
)
613 state
->dyn_
= Kernel::PassedDyn( new Kernel::DynamicEnvironment( dyn_
, "resume", resume
) );
614 state
->breakExpr_
= breakExpr_
;
615 state
->resume_
= resume
;
616 return RefCountPtr
< Kernel::InteractionContinuation
>
617 ( new Kernel::InteractionContinuation( parentAnalysisEnv_
, bracket_
, state
->env_
, resume
,
621 is_
, os_
, outputName_
, splitMode_
,
626 Kernel::InteractionContinuation::setDyn( const Kernel::PassedDyn
& dyn
)
632 Kernel::InteractionContinuation::reusable( Kernel::EvalState
& evalState
) const
634 return env_
== evalState
.env_
&& dyn_
== evalState
.dyn_
;
638 Kernel::InteractionContinuation::takeValue( const RefCountPtr
< const Lang::Value
> & val
, Kernel::EvalState
* evalState
, bool dummy
) const
640 Kernel::theDebugStepInfo
.active_
= false;
643 size_t debugDepth
= 0;
645 Kernel::ContRef tmp
= evalState
->cont_
;
646 while( tmp
!= NullPtr
< Kernel::Continuation
>( ) )
648 RefCountPtr
< Kernel::InteractionContinuation
> inter
= tmp
.down_cast
< Kernel::InteractionContinuation
>( );
649 if( inter
!= NullPtr
< Kernel::InteractionContinuation
>( ) )
651 tmp
= inter
->resume_
;
652 if( tmp
!= NullPtr
< Kernel::Continuation
>( ) )
666 /* As long as we fail to return, we ask for new input... */
670 for( size_t i
= 0; i
< debugDepth
; ++i
)
680 const Ast::FileID
* fileID
= Ast::FileID::build_fresh_inMemory( );
681 int interactive_inputNo
= fileID
->inMemoryIndex( );
682 std::ostringstream inputBuf
;
685 interactionFormats
.formatPrompt( os_
, interactive_inputNo
);
687 std::getline( is_
, line
);
690 interactionFormats
.formatBye( os_
, interactive_inputNo
);
691 Kernel::theInteractionDone
= true;
694 if( line
.length( ) > 1 && line
[ line
.length( ) - 1] == ' ' )
696 inputBuf
<< line
.substr( 0, line
.length( ) - 1 ) << '\n' ;
704 std::string line
= inputBuf
.str( );
705 if( line
.length( ) > 1 && line
[0] == ':' )
707 line
= "#db.[" + line
.substr(1) + "]";
710 const_cast< Ast::FileID
* >( fileID
)->setMem( strdup( line
.c_str( ) ) );
711 std::istringstream
inLine( line
+ "\n" );
712 Ast::theShapesScanner
.queueStream( & inLine
, fileID
);
713 Ast::theShapesScanner
.start( );
717 interactive_history
.push_back( Ast::theInteractiveInput
);
718 Ast::CodeBracket
* extension
= new Ast::CodeBracket( bracket_
->loc( ), Ast::theInteractiveInput
, bracket_
);
720 Ast::StateIDSet freeStates
;
721 extension
->analyze( Ast::theProgram
, parentAnalysisEnv_
, & freeStates
);
723 if( ! Ast::theAnalysisErrorsList
.empty( ) )
726 typedef typeof Ast::theAnalysisErrorsList ListType
;
727 for( ListType::const_iterator i
= Ast::theAnalysisErrorsList
.begin( ); i
!= Ast::theAnalysisErrorsList
.end( ); ++i
)
730 typedef const Exceptions::StaticInconsistency ErrorType
;
731 ErrorType
* err
= dynamic_cast< ErrorType
* >( *i
);
734 std::cerr
<< err
->loc( ) << ": " ;
735 err
->display( std::cerr
);
739 std::cerr
<< "(Bad exception type)" << ": " ;
740 (*i
)->display( std::cerr
);
742 Ast::theAnalysisErrorsList
.clear( );
748 // evalState->env_ = env_; /* Not needed since extension->eval handles this. */
749 evalState
->dyn_
= dyn_
;
750 /* For the continuation, we make a copy of ourselves. */
751 evalState
->cont_
= Kernel::ContRef( new Kernel::InteractionContinuation( parentAnalysisEnv_
, bracket_
, env_
, resume_
, dyn_
, breakExpr_
,
753 is_
, os_
, outputName_
, splitMode_
,
755 extension
->eval( evalState
, env_
); /* Note that this is a special kind of eval that extends the given environment. */
757 catch( const Exceptions::CatchableError
& ball
)
759 Kernel::ContRef cont
= evalState
->dyn_
->getEscapeContinuation( Lang::CONTINUATION_ID_ERROR
, ball
.getLoc( ) );
760 cont
->takeValue( ball
.clone( evalState
->cont_
),
766 catch( const Exceptions::StaticInconsistency
& ball
)
769 os_
<< ball
.loc( ) << ": " ;
772 catch( const Exceptions::Exception
& ball
)
781 Kernel::InteractionContinuation::up( ) const
783 return Kernel::ContRef( NullPtr
< Kernel::Continuation
>( ) );
786 RefCountPtr
< const char >
787 Kernel::InteractionContinuation::description( ) const
789 if( resume_
!= NullPtr
< Kernel::Continuation
>( ) )
791 return strrefdup( "interaction with resume" );
795 return strrefdup( "interaction" );
800 Kernel::InteractionContinuation::gcMark( Kernel::GCMarkedSet
& marked
)
804 Kernel::InteractionContinuation::showValue( const RefCountPtr
< const Lang::Value
> & resultUntyped
) const
808 typedef const Lang::Void ResType
;
809 RefCountPtr
< ResType
> result
= Helpers::try_cast_CoreArgument
< ResType
>( resultUntyped
);
813 catch( const NonLocalExit::NotThisType
& ball
)
815 /* Wrong type; never mind!.. but see below!
820 typedef const Lang::Drawable2D ResType
;
821 RefCountPtr
< ResType
> result
= Helpers::try_cast_CoreArgument
< ResType
>( resultUntyped
);
822 Kernel::WarmCatalog catalog
;
823 catalog
.tackOnPage( dyn_
, result
, Ast::THE_UNKNOWN_LOCATION
);
824 Kernel::WarmCatalog::ShipoutList documents
;
825 catalog
.shipout( splitMode_
!= SPLIT_NO
, & documents
);
827 std::string filename
;
832 noSplitOpen( & oFile
, outputName_
);
833 filename
= outputName_
;
838 filename
= splitOpen( & oFile
, outputName_
, "-", result_inputNo_
);
843 filename
= splitOpen( & oFile
, outputName_
, "/", result_inputNo_
);
847 documents
.front( ).writeFile( oFile
, Kernel::the_PDF_version
);
849 interactionFormats
.formatFile( os_
, result_inputNo_
) ;
850 os_
<< filename
<< std::endl
;
851 previewOptions
.preview( filename
);
852 if( previewOptions
.xpdfAction
== Interaction::PreviewOptions::XPDF_RAISE
&& splitMode_
== SPLIT_NO
)
854 /* It is disturbing to raise the window more than the first time. */
855 previewOptions
.xpdfAction
= Interaction::PreviewOptions::XPDF_RELOAD
;
859 catch( const NonLocalExit::NotThisType
& ball
)
861 /* Wrong type; never mind!.. but see below!
865 /* This is the default action taken in case non of the types above matched. */
866 interactionFormats
.formatShow( os_
, result_inputNo_
) ;
867 resultUntyped
->show( os_
);
871 Kernel::ExitInteractionContinuation::ExitInteractionContinuation( bool * done
, int * exitCode
, const Ast::SourceLocation
& traceLoc
)
872 : Kernel::Continuation( traceLoc
), done_( done
), exitCode_( exitCode
)
875 Kernel::ExitInteractionContinuation::~ExitInteractionContinuation( )
879 Kernel::ExitInteractionContinuation::takeValue( const RefCountPtr
< const Lang::Value
> & val
, Kernel::EvalState
* evalState
, bool dummy
) const
883 typedef const Lang::Symbol ArgType
;
884 RefCountPtr
< ArgType
> key
= Helpers::try_cast_CoreArgument
< ArgType
>( val
);
886 static Lang::Symbol
CODE_OK( "OK" );
887 static Lang::Symbol
CODE_GENERIC_ERROR( "GenericError" );
888 static Lang::Symbol
CODE_USER_DETECTED_ERROR( "UserDetectedError" );
889 if( *key
== CODE_OK
)
891 *exitCode_
= Interaction::EXIT_OK
;
893 else if( *key
== CODE_GENERIC_ERROR
)
895 *exitCode_
= Interaction::EXIT_GENERIC_ERROR
;
897 else if( *key
== CODE_USER_DETECTED_ERROR
)
899 *exitCode_
= Interaction::EXIT_USER_DETECTED_ERROR
;
903 std::ostringstream oss
;
904 oss
<< "Valid exit codes symbols are { "
905 << CODE_OK
.name( ).getPtr( ) << ", "
906 << CODE_GENERIC_ERROR
.name( ).getPtr( ) << ", "
907 << CODE_USER_DETECTED_ERROR
.name( ).getPtr( )
909 throw Exceptions::OutOfRange( traceLoc_
, strrefdup( oss
) );
915 catch( const NonLocalExit::NotThisType
& ball
)
917 /* Wrong type; never mind!.. but see below!
923 typedef const Lang::Integer ArgType
;
924 *exitCode_
= Helpers::try_cast_CoreArgument
< ArgType
>( val
)->val_
;
925 if( -99 <= *exitCode_
|| *exitCode_
<= 99 )
927 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." );
932 catch( const NonLocalExit::NotThisType
& ball
)
934 /* Wrong type; never mind!.. but see below!
938 throw Exceptions::ContinuationTypeMismatch( this, val
->getTypeName( ), Helpers::typeSetString( Lang::Symbol::staticTypeName( ), Lang::Integer::staticTypeName( ) ) );
942 Kernel::ExitInteractionContinuation::up( ) const
944 return Kernel::ContRef( NullPtr
< Kernel::Continuation
>( ) );
947 RefCountPtr
< const char >
948 Kernel::ExitInteractionContinuation::description( ) const
950 return strrefdup( "exit (non-forcing)" );
954 Kernel::ExitInteractionContinuation::gcMark( Kernel::GCMarkedSet
& marked
)
964 class Mutator_resume
: public Lang::CoreFunction
967 Mutator_resume( const char * title
)
968 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), false ) )
970 formals_
->appendEvaluatedCoreFormal( "result", Kernel::THE_VOID_VARIABLE
);
973 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
975 args
.applyDefaults( );
978 StateType
* state
= Helpers::mutator_cast_self
< StateType
>( args
.getMutatorSelf( ) );
979 if( state
->resume_
== NullPtr
< typeof *(state
->resume_
) >( ) )
981 throw Exceptions::CoreRequirement( "The top level debug state has no continuation to resume.", title_
, callLoc
);
984 if( args
.getHandle( 0 ) == Kernel::THE_VOID_VARIABLE
&& state
->breakExpr_
!= 0 )
986 /* 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.
987 * 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.
988 * 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
989 * minimum. Hence, using the <ignoreCount_> is preferred.
991 if( state
->breakExpr_
->breakpoint_
!= 0 &&
992 state
->breakExpr_
->breakpoint_
->enabled_
)
994 ++(state
->breakExpr_
->breakpoint_
->ignoreCount_
);
996 evalState
->cont_
= state
->resume_
;
997 evalState
->env_
= state
->env_
->getParent( );
998 evalState
->dyn_
= state
->dyn_
;
999 evalState
->expr_
= state
->breakExpr_
;
1003 /* Invoke the escape continuation exactly as in ContinueDynamicECFunction::call.
1005 evalState
->cont_
= state
->resume_
;
1006 evalState
->expr_
= 0;
1007 state
->resume_
->takeHandle( args
.getHandle( 0 ),
1014 class Mutator_top_repl
: public Lang::CoreFunction
1017 Mutator_top_repl( const char * title
)
1018 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), false ) )
1020 formals_
->appendEvaluatedCoreFormal( "result", Kernel::THE_VOID_VARIABLE
);
1023 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1025 args
.applyDefaults( );
1027 // typedef T StateType;
1028 // StateType * state = Helpers::mutator_cast_self< StateType >( args.getMutatorSelf( ) );
1030 /* Invoke the escape continuation exactly as in ContinueDynamicECFunction::call.
1032 Kernel::ContRef cont
= evalState
->dyn_
->getEscapeContinuation( Lang::CONTINUATION_TOP_REPL_ID
, callLoc
);
1033 evalState
->cont_
= cont
;
1034 evalState
->expr_
= 0;
1035 cont
->takeHandle( args
.getHandle( 0 ),
1041 class Mutator_cont
: public Lang::CoreFunction
1044 typedef enum { UP
, EXIT_DEBUG
} Kind
;
1048 Mutator_cont( const char * title
, Kind kind
)
1049 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), false ) ),
1052 formals_
->appendEvaluatedCoreFormal( "count", Helpers::newValHandle( new Lang::Integer( 1 ) ) );
1055 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1057 args
.applyDefaults( );
1059 /* While activating an already existing interactive continuation allows an old WarmDebugger to be reused as is,
1060 * changing the resume continuation within the current interactive context requires the current WarmDebugger to
1061 * be modified. Hence, to not modify any other state than that that calls this method, the UP mode can not be
1062 * used to reach continuations beyond the next interactive continuation.
1065 /* Note that we don't start counting in state->resume_, but search an interactive continuation from evalState->cont_.
1066 * The reason is that this provides a unified way of obtaining an interactive continuation _below_ the new resume continuation.
1067 * In most cases, this will be exactly what one expects, but in rare cases this behavior may seem strange.
1071 typedef const Lang::Integer ArgType
;
1072 size_t argsi_count
= argsi
;
1073 int count
= Helpers::down_cast_CoreArgument
< ArgType
>( title_
, args
, argsi_count
, callLoc
)->val_
;
1076 throw Exceptions::CoreOutOfRange( title_
, args
, argsi_count
, "The count must be positive." );
1079 Kernel::ContRef tmp
= evalState
->cont_
;
1080 RefCountPtr
< Kernel::InteractionContinuation
> bottom_interactive
= tmp
.down_cast
< Kernel::InteractionContinuation
>( );
1081 while( bottom_interactive
== NullPtr
< typeof *bottom_interactive
>( ) )
1083 if( tmp
== NullPtr
< Kernel::Continuation
>( ) )
1085 throw Exceptions::CoreOutOfRange( title_
, args
, argsi_count
, "There is no interactive continuation in the backtrace to start counting from." );
1088 bottom_interactive
= tmp
.down_cast
< Kernel::InteractionContinuation
>( );
1090 tmp
= bottom_interactive
->resume( );
1094 if( tmp
== NullPtr
< Kernel::Continuation
>( ) )
1096 throw Exceptions::CoreOutOfRange( title_
, args
, argsi_count
, "The count exceeds the current depth." );
1098 RefCountPtr
< Kernel::InteractionContinuation
> inter
= tmp
.down_cast
< Kernel::InteractionContinuation
>( );
1099 if( inter
!= NullPtr
< typeof *inter
>( ) )
1103 throw Exceptions::CoreOutOfRange( title_
, args
, argsi_count
, "The count exceeds depth down to the next interactive continuations." );
1105 bottom_interactive
= inter
;
1108 /* The continuation will be reused, which corresponds to one decrement of <count>. */
1111 tmp
= bottom_interactive
->resume( );
1123 if( tmp
== NullPtr
< Kernel::Continuation
>( ) )
1125 throw Exceptions::CoreOutOfRange( title_
, args
, argsi_count
, "The count exceeds the current depth." );
1128 /* If tmp is an interactive continuation, we reuse it, otherwise we set up a new one.
1130 if( tmp
.down_cast
< Kernel::InteractionContinuation
>( ) != NullPtr
< Kernel::InteractionContinuation
>( ) )
1132 evalState
->cont_
= tmp
;
1138 throw Exceptions::InternalError( "Mutator_cont: Expected kind_ to be UP when unable to reuse continuation." );
1140 typedef T StateType
;
1141 StateType
* state
= Helpers::mutator_cast_self
< StateType
>( args
.getMutatorSelf( ) );
1142 RefCountPtr
< Kernel::InteractionContinuation
> inter
= bottom_interactive
->cloneWithNewContinuation( tmp
, state
);
1143 evalState
->cont_
= inter
;
1145 evalState
->expr_
= Kernel::theVoidExpression
;
1150 class Mutator_step
: public Lang::CoreFunction
1152 Kernel::DebugStepInfo::StepMode mode_
;
1154 Mutator_step( const char * title
, Kernel::DebugStepInfo::StepMode mode
)
1155 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) ),
1158 formals_
->appendEvaluatedCoreFormal( "count", Helpers::newValHandle( new Lang::Integer( 1 ) ) );
1161 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1163 args
.applyDefaults( );
1165 typedef T StateType
;
1166 StateType
* state
= Helpers::mutator_cast_self
< StateType
>( args
.getMutatorSelf( ) );
1167 if( state
->breakExpr_
== 0 )
1169 throw Exceptions::CoreRequirement( "Currently not at any source location, so source stepping is not possible.", title_
, callLoc
);
1173 typedef const Lang::Integer ArgType
;
1174 int count
= Helpers::down_cast_CoreArgument
< ArgType
>( title_
, args
, argsi
, callLoc
)->val_
;
1177 throw Exceptions::CoreOutOfRange( title_
, args
, argsi
, "The count must be at least 1." );
1180 Kernel::theDebugStepInfo
.active_
= true;
1181 Kernel::theDebugStepInfo
.mode_
= mode_
;
1182 Kernel::theDebugStepInfo
.refLoc_
= state
->breakExpr_
->loc( );
1183 Kernel::theDebugStepInfo
.count_
= static_cast< size_t >( count
) + ( ( mode_
== Kernel::DebugStepInfo::EXPR
) ? 1 : 0 );
1185 /* The rest is more or less the same as in Mutator_resume. */
1186 if( state
->breakExpr_
->breakpoint_
!= 0 &&
1187 state
->breakExpr_
->breakpoint_
->enabled_
)
1189 ++(state
->breakExpr_
->breakpoint_
->ignoreCount_
);
1191 evalState
->cont_
= state
->resume_
;
1192 evalState
->env_
= state
->env_
->getParent( );
1193 evalState
->dyn_
= state
->dyn_
;
1194 evalState
->expr_
= state
->breakExpr_
;
1199 class Mutator_step_to_temporary
: public Lang::CoreFunction
1202 typedef enum { CHILD
, SIBLING
} Destination
;
1204 Destination destination_
;
1206 Mutator_step_to_temporary( const char * title
, Destination destination
)
1207 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) ),
1208 destination_( destination
)
1211 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1213 args
.applyDefaults( );
1215 typedef T StateType
;
1216 StateType
* state
= Helpers::mutator_cast_self
< StateType
>( args
.getMutatorSelf( ) );
1217 if( state
->breakExpr_
== 0 )
1219 throw Exceptions::CoreRequirement( "Currently not at any source location, so source stepping is not possible.", title_
, callLoc
);
1222 /* Now, depending on destination_, temporary breakpoints are set.
1223 * 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
1224 * 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.
1226 size_t count
= 0; /* Count number of expression where we set a temporary breakpoint. */
1228 switch( destination_
)
1232 Ast::Node::ChildrenType
& exprs
= state
->breakExpr_
->children( );
1233 for( Ast::Node::ChildrenType::iterator i
= exprs
.begin( ); i
!= exprs
.end( ); ++i
)
1235 Ast::Expression
* expr
= dynamic_cast< Ast::Expression
* >( *i
);
1241 if( expr
->breakpoint_
== 0 )
1243 expr
->breakpoint_
= new Kernel::BreakpointInfo( );
1244 expr
->breakpoint_
->createdForTemporaryUse_
= true;
1245 Kernel::theBreakpoints
.insert( expr
);
1247 expr
->breakpoint_
->persistentEnabled_
= expr
->breakpoint_
->enabled_
;
1248 expr
->breakpoint_
->enabled_
= true;
1249 Kernel::theTemporaryBreakpoints
.insert( expr
);
1255 Ast::Node
* parent
= state
->breakExpr_
->parent( );
1258 throw Exceptions::CoreRequirement( "Unable to locate siblings since there is no parent here.", title_
, callLoc
);
1260 Ast::Node::ChildrenType
& exprs
= parent
->children( );
1261 for( Ast::Node::ChildrenType::iterator i
= exprs
.begin( ); i
!= exprs
.end( ); ++i
)
1263 Ast::Expression
* expr
= dynamic_cast< Ast::Expression
* >( *i
);
1264 if( expr
== 0 || expr
== state
->breakExpr_
)
1269 if( expr
->breakpoint_
== 0 )
1271 expr
->breakpoint_
= new Kernel::BreakpointInfo( );
1272 expr
->breakpoint_
->createdForTemporaryUse_
= true;
1273 Kernel::theBreakpoints
.insert( expr
);
1275 expr
->breakpoint_
->persistentEnabled_
= expr
->breakpoint_
->enabled_
;
1276 expr
->breakpoint_
->enabled_
= true;
1277 Kernel::theTemporaryBreakpoints
.insert( expr
);
1285 throw Exceptions::CoreRequirement( "No temporary breakpoints were set. Not resuming evaluation.", title_
, callLoc
);
1288 /* The rest is more or less the same as in Mutator_resume. */
1289 if( state
->breakExpr_
->breakpoint_
!= 0 &&
1290 state
->breakExpr_
->breakpoint_
->enabled_
)
1292 ++(state
->breakExpr_
->breakpoint_
->ignoreCount_
);
1294 evalState
->cont_
= state
->resume_
;
1295 evalState
->env_
= state
->env_
->getParent( );
1296 evalState
->dyn_
= state
->dyn_
;
1297 evalState
->expr_
= state
->breakExpr_
;
1302 class Mutator_backtrace
: public Lang::CoreFunction
1305 Mutator_backtrace( const char * title
)
1306 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) )
1310 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1312 args
.applyDefaults( );
1314 typedef T StateType
;
1315 StateType
* state
= Helpers::mutator_cast_self
< StateType
>( args
.getMutatorSelf( ) );
1317 std::ostringstream oss
;
1319 typedef std::list
< std::pair
< const Kernel::Continuation
*, RefCountPtr
< const char > > > ListType
;
1321 size_t debugDepth
= 0;
1322 trace
.push_front( ListType::value_type( 0, strrefdup( "==( bottom resume )==" ) ) );
1323 const Kernel::Continuation
* tmp
= state
->resume_
.getPtr( );
1324 while( tmp
!= NullPtr
< Kernel::Continuation
>( ) )
1326 trace
.push_front( ListType::value_type( tmp
, tmp
->description( ) ) );
1327 const Kernel::InteractionContinuation
* inter
= dynamic_cast< const Kernel::InteractionContinuation
* >( tmp
);
1330 tmp
= inter
->resume( ).getPtr( );
1333 trace
.push_front( ListType::value_type( 0, strrefdup( "--( next resume )--" ) ) );
1339 tmp
= tmp
->up( ).getPtr( );
1342 trace
.push_front( ListType::value_type( 0, strrefdup( "==( top )==" ) ) );
1344 oss
<< std::endl
; /* Ensure we start on a new line. */
1345 ListType::const_iterator i
= trace
.begin( );
1346 for( ; i
!= trace
.end( ); ++i
)
1350 oss
<< i
->second
<< std::endl
;
1354 oss
<< " " << i
->first
->traceLoc( ) << "\t" << i
->second
<< std::endl
;
1359 Kernel::ContRef cont
= evalState
->cont_
;
1360 cont
->takeValue( Kernel::ValueRef( new Lang::String( strrefdup( oss
) ) ),
1366 class Mutator_printEnv
: public Lang::CoreFunction
1369 Mutator_printEnv( const char * title
)
1370 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) )
1374 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1376 args
.applyDefaults( );
1378 typedef T StateType
;
1379 StateType
* state
= Helpers::mutator_cast_self
< StateType
>( args
.getMutatorSelf( ) );
1381 std::ostringstream oss
;
1382 oss
<< std::endl
; /* Ensure we start on a new line. */
1383 state
->env_
->print( oss
);
1385 Kernel::ContRef cont
= evalState
->cont_
;
1386 cont
->takeValue( Kernel::ValueRef( new Lang::String( strrefdup( oss
) ) ),
1392 class Mutator_printDyn
: public Lang::CoreFunction
1395 Mutator_printDyn( const char * title
)
1396 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) )
1400 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1402 args
.applyDefaults( );
1404 typedef T StateType
;
1405 StateType
* state
= Helpers::mutator_cast_self
< StateType
>( args
.getMutatorSelf( ) );
1407 std::ostringstream oss
;
1408 oss
<< std::endl
; /* Ensure we start on a new line. */
1409 state
->dyn_
->print( oss
);
1411 Kernel::ContRef cont
= evalState
->cont_
;
1412 cont
->takeValue( Kernel::ValueRef( new Lang::String( strrefdup( oss
) ) ),
1418 class Mutator_printBreakpoints
: public Lang::CoreFunction
1421 Mutator_printBreakpoints( const char * title
)
1422 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) )
1426 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1428 args
.applyDefaults( );
1430 // typedef T StateType;
1431 // StateType * state = Helpers::mutator_cast_self< StateType >( args.getMutatorSelf( ) );
1433 std::ostringstream oss
;
1434 oss
<< std::endl
; /* Ensure we start on a new line. */
1435 typedef typeof Kernel::theBreakpoints ListType
;
1437 for( ListType::const_iterator i
= Kernel::theBreakpoints
.begin( ); i
!= Kernel::theBreakpoints
.end( ); ++i
, ++index
)
1439 oss
<< std::setw(3) << index
<< ( ( (*i
)->breakpoint_
->enabled_
) ? " (on )" : " (off)" ) ;
1440 if( (*i
)->breakpoint_
->ignoreCount_
> 0 )
1442 oss
<< " (ignore " << (*i
)->breakpoint_
->ignoreCount_
<< " times)" ;
1444 oss
<< ": " << (*i
)->loc( ) << std::endl
;
1447 Kernel::ContRef cont
= evalState
->cont_
;
1448 cont
->takeValue( Kernel::ValueRef( new Lang::String( strrefdup( oss
) ) ),
1454 class Mutator_clearBreak
: public Lang::CoreFunction
1457 Mutator_clearBreak( const char * title
)
1458 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) )
1460 formals_
->appendEvaluatedCoreFormal( "index", Helpers::newValHandle( new Lang::Integer( 0 ) ) );
1463 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1465 args
.applyDefaults( );
1467 typedef T StateType
;
1468 StateType
* state
= Helpers::mutator_cast_self
< StateType
>( args
.getMutatorSelf( ) );
1471 typedef const Lang::Integer ArgType
;
1472 int index
= Helpers::down_cast_CoreArgument
< ArgType
>( title_
, args
, argsi
, callLoc
)->val_
;
1475 if( state
->breakExpr_
== 0 )
1477 throw Exceptions::CoreOutOfRange( title_
, args
, argsi
, "Currently not at any source location, so the breakpoint index 0 is invalid." );
1480 if( index
< 0 || static_cast< int >( Kernel::theBreakpoints
.size( ) ) < index
)
1482 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." );
1486 Ast::Expression
* expr
= state
->breakExpr_
;
1487 if( expr
->breakpoint_
!= 0 )
1489 delete expr
->breakpoint_
;
1490 expr
->breakpoint_
= 0;
1491 Kernel::theBreakpoints
.erase( expr
);
1496 typedef typeof Kernel::theBreakpoints SetType
;
1497 SetType::iterator i
= Kernel::theBreakpoints
.begin( );
1498 for( int tmp
= 1; tmp
< index
; ++tmp
, ++i
)
1500 delete (*i
)->breakpoint_
;
1501 (*i
)->breakpoint_
= 0;
1502 Kernel::theBreakpoints
.erase( *i
);
1505 Kernel::ContRef cont
= evalState
->cont_
;
1506 cont
->takeValue( Lang::THE_VOID
,
1512 class Mutator_clearAllBreak
: public Lang::CoreFunction
1515 Mutator_clearAllBreak( const char * title
)
1516 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) )
1520 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1522 args
.applyDefaults( );
1524 typedef T StateType
;
1525 /* The state is not used at the moment. */
1526 // StateType * state = Helpers::mutator_cast_self< StateType >( args.getMutatorSelf( ) );
1528 typedef typeof Kernel::theBreakpoints SetType
;
1529 for( SetType::iterator i
= Kernel::theBreakpoints
.begin( ); i
!= Kernel::theBreakpoints
.end( ); ++i
)
1531 delete (*i
)->breakpoint_
;
1532 (*i
)->breakpoint_
= 0;
1534 Kernel::theBreakpoints
.clear( );
1536 Kernel::ContRef cont
= evalState
->cont_
;
1537 cont
->takeValue( Lang::THE_VOID
,
1543 class Mutator_ignoreBreak
: public Lang::CoreFunction
1546 Mutator_ignoreBreak( const char * title
)
1547 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) )
1549 formals_
->appendEvaluatedCoreFormal( "index", Helpers::newValHandle( new Lang::Integer( 0 ) ) );
1550 formals_
->appendEvaluatedCoreFormal( "count", Helpers::newValHandle( new Lang::Integer( 1 ) ) );
1553 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1555 args
.applyDefaults( );
1557 typedef T StateType
;
1558 StateType
* state
= Helpers::mutator_cast_self
< StateType
>( args
.getMutatorSelf( ) );
1561 typedef const Lang::Integer ArgType
;
1562 int index
= Helpers::down_cast_CoreArgument
< ArgType
>( title_
, args
, argsi
, callLoc
)->val_
;
1565 if( state
->breakExpr_
== 0 )
1567 throw Exceptions::CoreOutOfRange( title_
, args
, argsi
, "Currently not at any source location, so the breakpoint index 0 is invalid." );
1570 else if( index
< 0 || static_cast< int >( Kernel::theBreakpoints
.size( ) ) < index
)
1572 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." );
1575 int count
= Helpers::down_cast_CoreArgument
< ArgType
>( title_
, args
, argsi
, callLoc
)->val_
;
1578 throw Exceptions::CoreOutOfRange( title_
, args
, argsi
, "The count must be non-negative." );
1582 Ast::Expression
* expr
= state
->breakExpr_
;
1583 if( expr
->breakpoint_
== 0 )
1585 expr
->breakpoint_
= new Kernel::BreakpointInfo( );
1586 Kernel::theBreakpoints
.insert( expr
);
1588 expr
->breakpoint_
->ignoreCount_
= static_cast< size_t >( count
);
1592 typedef typeof Kernel::theBreakpoints SetType
;
1593 SetType::iterator i
= Kernel::theBreakpoints
.begin( );
1594 for( int tmp
= 1; tmp
< index
; ++tmp
, ++i
)
1596 (*i
)->breakpoint_
->ignoreCount_
= static_cast< size_t >( count
);
1599 Kernel::ContRef cont
= evalState
->cont_
;
1600 cont
->takeValue( Lang::THE_VOID
,
1607 class Mutator_setBreakLocation
: public Lang::CoreFunction
1610 Mutator_setBreakLocation( const char * title
)
1611 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) )
1613 formals_
->appendEvaluatedCoreFormal( "file", Kernel::THE_SLOT_VARIABLE
);
1614 formals_
->appendEvaluatedCoreFormal( "line", Kernel::THE_SLOT_VARIABLE
);
1615 formals_
->appendEvaluatedCoreFormal( "column", Helpers::newValHandle( new Lang::Integer( 0 ) ) );
1616 formals_
->appendEvaluatedCoreFormal( "enable", Kernel::THE_VOID_VARIABLE
);
1619 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1621 args
.applyDefaults( );
1623 typedef T StateType
;
1624 /* The state is not used at the moment. */
1625 // StateType * state = Helpers::mutator_cast_self< StateType >( args.getMutatorSelf( ) );
1628 struct stat theStat
;
1629 std::string fileArg
= Helpers::down_cast_CoreArgument
< const Lang::String
>( title_
, args
, argsi
, callLoc
)->val_
.getPtr( );
1631 int line
= Helpers::down_cast_CoreArgument
< const Lang::Integer
>( title_
, args
, argsi
, callLoc
)->val_
;
1634 throw Exceptions::CoreOutOfRange( title_
, args
, argsi
, "The line number must be positive." );
1637 int column
= Helpers::down_cast_CoreArgument
< const Lang::Integer
>( title_
, args
, argsi
, callLoc
)->val_
;
1640 throw Exceptions::CoreOutOfRange( title_
, args
, argsi
, "The column number must be non-negative." );
1643 RefCountPtr
< const Lang::Boolean
> breakPtr
= Helpers::down_cast_CoreArgument
< const Lang::Boolean
>( title_
, args
, argsi
, callLoc
, true );
1645 const Ast::FileID
* fileID
= 0;
1646 if( ! Ast::FileID::is_inMemory( fileArg
, & fileID
) )
1650 std::string filename
= Ast::theShapesScanner
.searchFile( fileArg
, & theStat
);
1651 fileID
= Ast::FileID::build_stat( theStat
, fileArg
);
1653 catch( const Exceptions::Exception
& ball
)
1655 throw Exceptions::CoreOutOfRange( title_
, args
, 0, "Failed to locate source file." );
1658 Ast::SourceLocation
loc( fileID
);
1659 loc
.firstLine
= line
;
1660 loc
.lastLine
= line
;
1661 if( Interaction::characterColumnInBytes
)
1663 loc
.firstColumn
= column
;
1664 loc
.lastColumn
= column
;
1668 /* Column is the UTF8 column, and needs to be converted to byte column. */
1671 int byteColumn
= fileID
->UTF8ColumnTobyteColumn( line
, column
);
1672 loc
.firstColumn
= byteColumn
;
1673 loc
.lastColumn
= byteColumn
;
1675 catch( const Exceptions::OutOfRange
& ball
)
1677 /* Without actually looking into ball we guess what the problem is... */
1678 throw Exceptions::CoreOutOfRange( title_
, args
, 1, "Line seems past end of file." );
1681 Ast::Expression
* expr
= loc
.findExpression( );
1684 throw Exceptions::CoreOutOfRange( title_
, args
, 0, "Failed to locate position within the source file." );
1686 if( expr
->breakpoint_
== 0 )
1688 expr
->breakpoint_
= new Kernel::BreakpointInfo( );
1689 Kernel::theBreakpoints
.insert( expr
);
1693 if( breakPtr
== NullPtr
< const Lang::Boolean
>( ) )
1695 newEnabled
= ! expr
->breakpoint_
->enabled_
;
1699 newEnabled
= breakPtr
->val_
;
1702 expr
->breakpoint_
->enabled_
= newEnabled
;
1704 Kernel::ContRef cont
= evalState
->cont_
;
1705 cont
->takeValue( Lang::THE_VOID
,
1711 class Mutator_setBreakFunctionBody
: public Lang::CoreFunction
1714 Mutator_setBreakFunctionBody( const char * title
)
1715 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) )
1717 formals_
->appendEvaluatedCoreFormal( "function", Kernel::THE_SLOT_VARIABLE
);
1718 formals_
->appendEvaluatedCoreFormal( "enable", Kernel::THE_VOID_VARIABLE
);
1721 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1723 args
.applyDefaults( );
1725 typedef T StateType
;
1726 /* The state is not used at the moment. */
1727 // StateType * state = Helpers::mutator_cast_self< StateType >( args.getMutatorSelf( ) );
1730 typedef const Lang::UserFunction ArgType
;
1731 RefCountPtr
< ArgType
> fun
= Helpers::down_cast_CoreArgument
< ArgType
>( title_
, args
, argsi
, callLoc
);
1733 RefCountPtr
< const Lang::Boolean
> breakPtr
= Helpers::down_cast_CoreArgument
< const Lang::Boolean
>( title_
, args
, argsi
, callLoc
, true );
1735 Ast::Expression
* expr
= const_cast< Lang::UserFunction
* >( fun
.getPtr( ) )->body( );
1736 if( expr
->breakpoint_
== 0 )
1738 expr
->breakpoint_
= new Kernel::BreakpointInfo( );
1739 Kernel::theBreakpoints
.insert( expr
);
1743 if( breakPtr
== NullPtr
< const Lang::Boolean
>( ) )
1745 newEnabled
= ! expr
->breakpoint_
->enabled_
;
1749 newEnabled
= breakPtr
->val_
;
1752 expr
->breakpoint_
->enabled_
= newEnabled
;
1754 Kernel::ContRef cont
= evalState
->cont_
;
1755 cont
->takeValue( Lang::THE_VOID
,
1763 Kernel::WarmDebugger::WarmDebugger( Kernel::Environment
* env
, Kernel::PassedDyn dyn
, Kernel::ContRef resume
, Ast::Expression
* breakExpr
)
1764 : env_( env
), dyn_( dyn
), resume_( resume
), breakExpr_( breakExpr
)
1767 Kernel::WarmDebugger::~WarmDebugger( )
1771 Debugger_register_mutators( Lang::SystemFinalClass
* dstClass
)
1773 dstClass
->registerMutator( new Kernel::Mutator_resume
< Kernel::WarmDebugger
>( "resume" ), "r" );
1774 dstClass
->registerMutator( new Kernel::Mutator_top_repl
< Kernel::WarmDebugger
>( "top_repl" ) );
1775 dstClass
->registerMutator( new Kernel::Mutator_backtrace
< Kernel::WarmDebugger
>( "backtrace" ), "t" );
1776 dstClass
->registerMutator( new Kernel::Mutator_printEnv
< Kernel::WarmDebugger
>( "env" ), "e" );
1777 dstClass
->registerMutator( new Kernel::Mutator_printDyn
< Kernel::WarmDebugger
>( "dyn" ), "d" );
1778 dstClass
->registerMutator( new Kernel::Mutator_printBreakpoints
< Kernel::WarmDebugger
>( "breakList" ), "bl" );
1779 dstClass
->registerMutator( new Kernel::Mutator_setBreakLocation
< Kernel::WarmDebugger
>( "breakAt" ), "ba" );
1780 dstClass
->registerMutator( new Kernel::Mutator_setBreakFunctionBody
< Kernel::WarmDebugger
>( "breakIn" ), "bi" );
1781 dstClass
->registerMutator( new Kernel::Mutator_ignoreBreak
< Kernel::WarmDebugger
>( "breakIgnore" ), "bg" );
1782 dstClass
->registerMutator( new Kernel::Mutator_clearBreak
< Kernel::WarmDebugger
>( "breakClear" ), "bc" );
1783 dstClass
->registerMutator( new Kernel::Mutator_clearAllBreak
< Kernel::WarmDebugger
>( "breakClearAll" ), "bC" );
1784 dstClass
->registerMutator( new Kernel::Mutator_step
< Kernel::WarmDebugger
>( "stepe", Kernel::DebugStepInfo::EXPR
), "se" );
1785 dstClass
->registerMutator( new Kernel::Mutator_step
< Kernel::WarmDebugger
>( "step", Kernel::DebugStepInfo::STEP
), "s" );
1786 dstClass
->registerMutator( new Kernel::Mutator_step_to_temporary
< Kernel::WarmDebugger
>( "stepc", Kernel::Mutator_step_to_temporary
< Kernel::WarmDebugger
>::CHILD
), "sc" );
1787 dstClass
->registerMutator( new Kernel::Mutator_step_to_temporary
< Kernel::WarmDebugger
>( "steps", Kernel::Mutator_step_to_temporary
< Kernel::WarmDebugger
>::SIBLING
), "ss" );
1788 dstClass
->registerMutator( new Kernel::Mutator_cont
< Kernel::WarmDebugger
>( "contUp", Kernel::Mutator_cont
< Kernel::WarmDebugger
>::UP
), "cu" );
1789 dstClass
->registerMutator( new Kernel::Mutator_cont
< Kernel::WarmDebugger
>( "contExit", Kernel::Mutator_cont
< Kernel::WarmDebugger
>::EXIT_DEBUG
), "ce" );
1792 RefCountPtr
< const Lang::Class
> Kernel::WarmDebugger::TypeID( new Lang::SystemFinalClass( strrefdup( "#Debugger" ), Debugger_register_mutators
) );
1793 TYPEINFOIMPL_STATE( WarmDebugger
);
1796 Kernel::WarmDebugger::tackOnImpl( Kernel::EvalState
* evalState
, const RefCountPtr
< const Lang::Value
> & piece
,const Ast::SourceLocation
& callLoc
)
1798 throw Exceptions::MiscellaneousRequirement( strrefdup( "The debugger only interacts through named mutators; there is no tack-on mutator." ) );
1802 Kernel::WarmDebugger::freezeImpl( Kernel::EvalState
* evalState
, const Ast::SourceLocation
& callLoc
)
1804 throw Exceptions::MiscellaneousRequirement( strrefdup( "The debugger cannot be frozen." ) );
1808 Kernel::WarmDebugger::peekImpl( Kernel::EvalState
* evalState
, const Ast::SourceLocation
& callLoc
)
1810 throw Exceptions::MiscellaneousRequirement( strrefdup( "The debugger cannot be peeked." ) );
1814 Kernel::WarmDebugger::gcMark( Kernel::GCMarkedSet
& marked
)
1818 Kernel::BreakpointInfo::BreakpointInfo( )
1819 : enabled_( false ), createdForTemporaryUse_( false ), ignoreCount_( 0 )
1822 Kernel::BreakpointInfo::~BreakpointInfo( )