Updating the changelog in the VERSION file, and version_sync.
[shapes.git] / source / eval_interactive.cc
blob01095e8caf8645ed58a22b1d09fea694ace8c7f0
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
6 * any later version.
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
19 #include "main.h"
20 #include "astvar.h"
21 #include "breakpoints.h"
22 #include "shapescore.h"
24 using namespace Shapes;
25 using namespace SimplePDF;
27 namespace Shapes
29 namespace Ast
31 class VoidExpression : public Expression
33 public:
34 VoidExpression( const Ast::SourceLocation & loc );
35 virtual ~VoidExpression( );
36 virtual void analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst );
37 virtual void eval( Kernel::EvalState * evalState ) const;
41 namespace Kernel
43 bool theInteractionDone = false;
45 class InteractionContinuation : public Kernel::Continuation
47 Ast::AnalysisEnvironment * parentAnalysisEnv_;
48 mutable Ast::CodeBracket * bracket_;
49 mutable Kernel::Environment * env_;
50 Kernel::ContRef resume_;
51 Kernel::PassedDyn dyn_;
52 Ast::Expression * breakExpr_;
53 int result_inputNo_;
54 std::istream & is_;
55 std::ostream & os_;
56 std::string outputName_;
57 SplitMode splitMode_;
58 public:
59 InteractionContinuation( Ast::AnalysisEnvironment * parentAnalysisEnv, Ast::CodeBracket * bracket, Kernel::Environment * env, Kernel::ContRef resume, const Kernel::PassedDyn & dyn, Ast::Expression * breakExpr, int result_inputNo, std::istream & is, std::ostream & os, const std::string & outputName, SplitMode splitMode, const Ast::SourceLocation & traceLoc );
60 InteractionContinuation( Kernel::EvalState & evalState, int result_inputNo, std::istream & is, std::ostream & os, const std::string & outputName, SplitMode splitMode ); // set up new dynamic and lexical environment for debugging an error at evalState
61 ~InteractionContinuation( );
62 RefCountPtr< Kernel::InteractionContinuation > cloneWithNewContinuation( Kernel::ContRef resume, Kernel::WarmDebugger * state );
63 void setDyn( const Kernel::PassedDyn & dyn );
64 bool reusable( Kernel::EvalState & evalState ) const;
65 virtual void takeValue( const RefCountPtr< const Lang::Value > & val, Kernel::EvalState * evalState, bool dummy ) const;
66 virtual Kernel::ContRef up( ) const;
67 virtual RefCountPtr< const char > description( ) const;
68 virtual void gcMark( Kernel::GCMarkedSet & marked );
70 Kernel::ContRef resume( ) const { return resume_; } /* For debug backtraces and to skip continuations. */
71 private:
72 void showValue( const RefCountPtr< const Lang::Value > & resultUntyped ) const;
75 class ExitInteractionContinuation : public Kernel::Continuation
77 bool * done_;
78 int * exitCode_;
79 public:
80 ExitInteractionContinuation( bool * done, int * exitCode, const Ast::SourceLocation & traceLoc );
81 ~ExitInteractionContinuation( );
82 virtual void takeValue( const RefCountPtr< const Lang::Value > & val, Kernel::EvalState * evalState, bool dummy ) const;
83 virtual Kernel::ContRef up( ) const;
84 virtual RefCountPtr< const char > description( ) const;
85 virtual void gcMark( Kernel::GCMarkedSet & marked );
88 class DebugStepInfo
90 public:
91 typedef enum { EXPR, STEP } StepMode;
93 bool active_;
94 StepMode mode_;
95 Ast::SourceLocation refLoc_;
96 size_t count_;
97 DebugStepInfo( )
98 : active_( false ), mode_( EXPR ), refLoc_( Ast::THE_UNKNOWN_LOCATION ), count_( 1 )
99 { }
100 bool stop( const Ast::SourceLocation & loc )
102 switch( mode_ )
104 case EXPR:
105 /* Stop at everything. No need to update refLoc_ . */
106 break;
107 case STEP:
109 if( refLoc_.contains( loc ) )
111 return false;
113 refLoc_ = loc;
115 break;
117 --count_;
118 if( count_ == 0 )
120 active_ = false;
121 return true;
123 return false;
127 const int NO_INPUT_INPUT_NO = std::numeric_limits< int >::max( );
128 bool interactive_debug = true;
129 typedef typeof Ast::theInteractiveInput InputType;
130 std::vector< InputType > interactive_history;
131 std::set< Ast::Expression * > theBreakpoints; /* This set shall contain all expressions that have a Kernel::BreakpointInfo, incloding also those thare are not enabled. */
132 std::set< Ast::Expression * > theTemporaryBreakpoints; /* This set shall be a subset of theBreakpoints, and contain the breakpoints that should be reset when evaluation is interrupted. */
133 DebugStepInfo theDebugStepInfo;
134 Ast::VoidExpression * theVoidExpression = new Ast::VoidExpression( Ast::THE_UNKNOWN_LOCATION ); /* Order of initializaiton of globals?! */
137 namespace Lang
139 const char * CONTINUATION_TOP_REPL_ID = "top_repl";
143 void
144 interactiveEvaluation( std::istream & in, std::ostream & out, const std::string & outputName, SplitMode splitMode,
145 bool evalTrace, bool evalBackTrace, bool cleanupMemory,
146 RefCountPtr< std::ifstream > & labelDBFile, const std::string & labelDBName )
148 /* Clean up outout from earlier sessions. */
149 switch( splitMode )
151 case SPLIT_NO:
152 break;
153 case SPLIT_FLAT:
155 rmSplitFiles( outputName, "-" );
157 break;
158 case SPLIT_DIR:
160 mkSplitDir( outputName );
161 rmSplitFiles( outputName, "/" );
163 break;
166 RefCountPtr< const Kernel::GraphicsState > graphicsState( new Kernel::GraphicsState( true ) );
167 Kernel::PassedDyn baseDyn( new Kernel::DynamicEnvironment( graphicsState ) );
171 /* Evaluate preamble. */
172 shapesparse( );
173 initCore( labelDBFile, labelDBName );
175 bool done = false;
176 Kernel::ValueRef resultUntyped = NullPtr< const Lang::Value >( );
177 Kernel::EvalState evalState( Ast::theProgram,
178 Kernel::theGlobalEnvironment,
179 baseDyn,
180 Kernel::ContRef( new Kernel::StoreValueContinuation( & resultUntyped,
181 Kernel::ContRef( new Kernel::ExitContinuation( & done, Ast::theProgram->loc( ) ) ),
182 Ast::theProgram->loc( ) ) ) );
183 while( ! done )
185 Ast::Expression * expr = evalState.expr_;
186 expr->eval( & evalState );
189 catch( const Exceptions::StaticInconsistency & ball )
191 std::cout.flush( );
192 std::cerr << ball.loc( ) << ": " ;
193 ball.display( std::cerr );
194 std::cerr << "There were errors in the preamble. Aborting interactive evaluation." ;
195 abortProcedure( ball.exitCode( ) );
197 catch( const Exceptions::Exception & ball )
199 std::cout.flush( );
200 ball.display( std::cerr );
201 std::cerr << "There were errors in the preamble. Aborting interactive evaluation." ;
202 abortProcedure( ball.exitCode( ) );
205 Ast::theShapesScanner.setInteractive( true ); /* Do this after reading the preamble! */
207 /* Find the prelude environment... */
208 Kernel::Environment * preludeEnv = 0;
209 for( std::list< Kernel::Environment * >::iterator e = Kernel::theEnvironmentList.begin( ); e != Kernel::theEnvironmentList.end( ); ++e )
213 if( (*e)->getParent( ) == Kernel::theGlobalEnvironment )
215 preludeEnv = *e;
216 break;
219 catch( const Exceptions::MiscellaneousRequirement & ball )
221 /* That was the global environment, which doesn't have a parent. Never mind. */
224 if( preludeEnv == 0 )
226 std::cerr << "Internal error: Failed to locate prelude environment." << std::endl ;
227 exit( Interaction::EXIT_INTERNAL_ERROR );
229 Ast::AnalysisEnvironment * preludeAnalysisEnvironment = preludeEnv->newAnalysisEnvironment( Ast::theGlobalAnalysisEnvironment );
231 Ast::CodeBracket * initialBracket( new Ast::CodeBracket( Ast::SourceLocation( Ast::FileID::build_internal( "{ interactive }" ) ), new std::list< Ast::Node * >( ) ) );
233 Ast::StateIDSet freeStates;
234 initialBracket->analyze( Ast::theProgram, preludeAnalysisEnvironment, & freeStates );
236 Kernel::Environment * bracketEnv = initialBracket->newEnvironment( preludeEnv, "Interaction" );
237 bracketEnv->initDefine( "db", new Kernel::WarmDebugger( bracketEnv, baseDyn, Kernel::ContRef( NullPtr< Kernel::Continuation >( ) ), 0 ) );
239 int exitCode = Interaction::EXIT_OK;
241 RefCountPtr< Kernel::InteractionContinuation > interactionCont
242 ( new Kernel::InteractionContinuation( preludeAnalysisEnvironment, initialBracket, bracketEnv, Kernel::ContRef( NullPtr< Kernel::Continuation >( ) ), baseDyn, 0, Kernel::NO_INPUT_INPUT_NO,
243 in, out, outputName, splitMode,
244 initialBracket->loc( ) ) );
245 Kernel::PassedDyn interactionDyn( new Kernel::DynamicEnvironment( Kernel::PassedDyn( new Kernel::DynamicEnvironment( baseDyn, "bye", Kernel::ContRef( new Kernel::ExitInteractionContinuation( & Kernel::theInteractionDone, & exitCode, initialBracket->loc( ) ) ) ) ),
246 Lang::CONTINUATION_TOP_REPL_ID, interactionCont ) );
247 interactionCont->setDyn( interactionDyn );
249 Kernel::EvalState evalState( Kernel::theVoidExpression, /* This will invoke the continuation first thing. */
250 Kernel::theGlobalEnvironment, /* Dummy value */
251 baseDyn, /* Dummy value */
252 interactionCont );
254 while( ! Kernel::theInteractionDone )
256 Ast::Expression * expr = evalState.expr_;
257 if( Kernel::theDebugStepInfo.active_ && Kernel::theDebugStepInfo.stop( expr->loc( ) ) )
259 out << "Reached " << expr->loc( ) << "." << std::endl ;
260 evalState.cont_ = Kernel::ContRef( new Kernel::InteractionContinuation( evalState, Kernel::NO_INPUT_INPUT_NO, in, out, outputName, splitMode ) );
261 evalState.expr_ = Kernel::theVoidExpression;
262 Kernel::theDebugStepInfo.active_ = false;
263 continue;
265 if( expr->breakpoint_ != 0 && expr->breakpoint_->enabled_ )
267 if( expr->breakpoint_->ignoreCount_ > 0 )
269 /* Don't break this time, but re-enable breaking in the future. */
270 --(expr->breakpoint_->ignoreCount_);
272 else
274 out << "Stopping at breakpoint " << expr->loc( ) << "." << std::endl ;
275 typedef typeof Kernel::theTemporaryBreakpoints SetType;
276 for( SetType::iterator i = Kernel::theTemporaryBreakpoints.begin( ); i != Kernel::theTemporaryBreakpoints.end( ); ++i )
278 if( (*i)->breakpoint_->createdForTemporaryUse_ )
280 delete (*i)->breakpoint_;
281 (*i)->breakpoint_ = 0;
282 Kernel::theBreakpoints.erase( *i );
284 else
286 (*i)->breakpoint_->enabled_ = (*i)->breakpoint_->persistentEnabled_;
289 Kernel::theTemporaryBreakpoints.clear( );
290 evalState.cont_ = Kernel::ContRef( new Kernel::InteractionContinuation( evalState, Kernel::NO_INPUT_INPUT_NO, in, out, outputName, splitMode ) );
291 evalState.expr_ = Kernel::theVoidExpression;
292 Kernel::theDebugStepInfo.active_ = false;
293 continue;
301 expr->eval( & evalState );
303 catch( const Exceptions::CatchableError & ball )
305 Kernel::ContRef cont = evalState.dyn_->getEscapeContinuation( Lang::CONTINUATION_ID_ERROR, ball.getLoc( ) );
306 cont->takeValue( ball.clone( evalState.cont_ ),
307 & evalState );
309 continue;
311 catch( const Exceptions::StaticInconsistency & ball )
313 out.flush( );
314 out << ball.loc( ) << ": " ;
315 ball.display( out );
317 catch( const Exceptions::Exception & ball )
319 out.flush( );
320 if( Interaction::debugBacktrace )
322 evalState.cont_->backTrace( out );
325 const Exceptions::RuntimeError & rerr = dynamic_cast< const Exceptions::RuntimeError & >( ball );
326 if( & rerr != 0 && ! rerr.getLoc( ).isUnknown( ) )
328 out << rerr.getLoc( ) << Exceptions::Exception::locsep ;
330 else
332 out << evalState.cont_->traceLoc( ) << Exceptions::Exception::locsep ;
334 ball.display( out );
336 if( Kernel::interactive_debug )
338 Kernel::InteractionContinuation * iCont = dynamic_cast< Kernel::InteractionContinuation * >( evalState.cont_.getPtr( ) );
339 if( iCont != 0 && iCont->reusable( evalState ) )
341 /* We don't create a new interactive continuation if the active continuation is already an interactive continuation.
342 * For instance, failing to set a breakpoint is not something that's interesting to debug in itself.
344 out << "Reusing interactive continuation." << std::endl ;
346 else if( evalState.expr_ != 0 )
348 evalState.cont_ = Kernel::ContRef( new Kernel::InteractionContinuation( evalState, Kernel::NO_INPUT_INPUT_NO, in, out, outputName, splitMode ) );
350 else
352 /* We interpret this situation as a failure to explicitly apply a continuation.
353 * See ContinueDynamicECFunction::call .
355 evalState.cont_ = Kernel::ContRef( new Kernel::InteractionContinuation
356 ( preludeAnalysisEnvironment, initialBracket, bracketEnv, evalState.cont_,
357 Kernel::PassedDyn( new Kernel::DynamicEnvironment( baseDyn, "resume", evalState.cont_ ) ),
359 Kernel::NO_INPUT_INPUT_NO,
360 in, out, outputName, splitMode,
361 initialBracket->loc( ) ) );
364 else
366 evalState.cont_ = interactionCont;
368 Kernel::theDebugStepInfo.active_ = false;
369 evalState.expr_ = Kernel::theVoidExpression;
372 /* Someone ended the input stream or invoked the exit continuation.
373 * For now, we circumvent the normal termination procedures in <main> by exiting here,
374 * which is similar to stopping the program by pressing ctrl-c, which is probably what
375 * most people will do anyway.
377 exit( exitCode );
381 Interaction::InteractionFormats::InteractionFormats( )
382 : prompt_( "[%!#!!3R] " ),
383 show_( "%!#!!3R ⇒ " ),
384 file_( "#File: " ),
385 bye_( "<<EOF>>\n" )
388 void
389 Interaction::InteractionFormats::setPrompt( const char * format )
391 prompt_ = format;
394 void
395 Interaction::InteractionFormats::setShow( const char * format )
397 show_ = format;
400 void
401 Interaction::InteractionFormats::setFile( const char * format )
403 file_ = format;
406 void
407 Interaction::InteractionFormats::setBye( const char * format )
409 bye_ = format;
412 void
413 Interaction::InteractionFormats::formatPrompt( std::ostream & os, size_t inputNo ) const
415 writePrompt( os, prompt_, inputNo );
418 void
419 Interaction::InteractionFormats::formatShow( std::ostream & os, size_t inputNo ) const
421 writePrompt( os, show_, inputNo );
424 void
425 Interaction::InteractionFormats::formatFile( std::ostream & os, size_t inputNo ) const
427 writePrompt( os, file_, inputNo );
430 void
431 Interaction::InteractionFormats::formatBye( std::ostream & os, size_t inputNo ) const
433 writePrompt( os, bye_, inputNo );
436 void
437 Interaction::InteractionFormats::writePrompt( std::ostream & os, const char * format, size_t inputNo ) const
439 for( const char * src = format; *src != '\0'; ++src )
441 if( *src == '%' )
443 ++src;
444 const char sep = *src;
445 ++src;
446 std::ostringstream noStr;
447 while( *src != sep )
449 if( *src == '\0' )
451 std::cerr << "Bad interactive prompt format string (expected second '" << sep << "'): " << format << std::endl ;
452 exit( Interaction::EXIT_INVOCATION_ERROR );
454 if( *src == '\\' )
456 ++src;
457 writeEscape( noStr, *src );
459 else
461 noStr << *src ;
463 ++src;
465 ++src;
466 noStr << inputNo ;
467 while( *src != sep )
469 if( *src == '\0' )
471 std::cerr << "Bad interactive prompt format string (expected third '" << sep << "'): " << format << std::endl ;
472 exit( Interaction::EXIT_INVOCATION_ERROR );
474 if( *src == '\\' )
476 ++src;
477 writeEscape( noStr, *src );
479 else
481 noStr << *src ;
483 ++src;
485 ++src;
486 char * endp;
487 int width = strtol( src, & endp, 10 );
488 if( endp == src )
490 width = -1;
492 else if( width < 0 || width > 10 )
494 std::cerr << "Bad interactive prompt format string (the width " << width << " is out of the range [0,10]): " << format << std::endl ;
495 exit( Interaction::EXIT_INVOCATION_ERROR );
498 src = endp;
499 switch( *src )
501 case 'L':
502 os.setf(std::ios::left);
503 break;
504 case 'R':
505 os.setf(std::ios::right);
506 break;
507 default:
508 std::cerr << "Bad interactive prompt format string (expected 'L' or 'R' after '%'): " << format << std::endl ;
509 exit( Interaction::EXIT_INVOCATION_ERROR );
511 if( width >= 0 )
513 os << std::setw(width) ;
515 os << noStr.str( ) ;
517 else if( *src == '\\' )
519 ++src;
520 writeEscape( os, *src );
522 else
524 os << *src ;
529 void
530 Interaction::InteractionFormats::writeEscape( std::ostream & os, char c ) const
532 switch( c )
534 case '\\':
535 os << '\\';
536 break;
537 case '%':
538 os << '%';
539 break;
540 case 'a':
541 os << '\a';
542 break;
543 case 'n':
544 os << '\n';
545 break;
546 case 't':
547 os << '\t';
548 break;
549 default:
550 os << '\\' << c ;
554 Ast::VoidExpression::VoidExpression( const Ast::SourceLocation & loc )
555 : Ast::Expression( loc )
558 Ast::VoidExpression::~VoidExpression( )
561 void
562 Ast::VoidExpression::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
564 /* Nothing to do! */
567 void
568 Ast::VoidExpression::eval( Kernel::EvalState * evalState ) const
570 Kernel::ContRef cont = evalState->cont_;
571 cont->takeValue( Lang::THE_VOID,
572 evalState );
575 Kernel::InteractionContinuation::InteractionContinuation( Ast::AnalysisEnvironment * parentAnalysisEnv, Ast::CodeBracket * bracket, Kernel::Environment * env, Kernel::ContRef resume, const Kernel::PassedDyn & dyn, Ast::Expression * breakExpr, int result_inputNo, std::istream & is, std::ostream & os, const std::string & outputName, SplitMode splitMode, const Ast::SourceLocation & traceLoc )
576 : Kernel::Continuation( traceLoc ), parentAnalysisEnv_( parentAnalysisEnv ), bracket_( bracket ), env_( env ), resume_( resume ), dyn_( dyn ), breakExpr_( breakExpr ), result_inputNo_( result_inputNo ), is_( is ), os_( os ), outputName_( outputName ), splitMode_( splitMode )
579 Ast::SourceLocation debug_loc( Ast::FileID::build_internal( "{ debug }" ) );
581 Kernel::InteractionContinuation::InteractionContinuation( Kernel::EvalState & evalState, int result_inputNo, std::istream & is, std::ostream & os, const std::string & outputName, SplitMode splitMode )
582 : Kernel::Continuation( evalState.expr_->loc( ) ),
583 parentAnalysisEnv_( evalState.expr_->getEnv( ) ),
584 bracket_( new Ast::CodeBracket( debug_loc, new std::list< Ast::Node * >( ) ) ),
585 env_( bracket_->newEnvironment( evalState.env_, "Debug" ) ),
586 resume_( evalState.cont_ ),
587 dyn_( new Kernel::DynamicEnvironment( evalState.dyn_, "resume", resume_ ) ),
588 breakExpr_( evalState.expr_ ),
589 result_inputNo_( result_inputNo ),
590 is_( is ), os_( os ), outputName_( outputName ), splitMode_( splitMode )
593 Ast::StateIDSet freeStates;
594 bracket_->analyze( evalState.expr_, parentAnalysisEnv_, & freeStates );
596 env_->initDefine( "db", new Kernel::WarmDebugger( env_, dyn_, resume_, breakExpr_ ) );
597 env_->initDefineHandle( "expr", Kernel::VariableHandle( new Kernel::Variable( new Kernel::Thunk( evalState.env_, evalState.dyn_, evalState.expr_ ) ) ) );
600 Kernel::InteractionContinuation::~InteractionContinuation( )
603 RefCountPtr< Kernel::InteractionContinuation >
604 Kernel::InteractionContinuation::cloneWithNewContinuation( Kernel::ContRef resume, Kernel::WarmDebugger * state )
606 state->env_ = env_;
607 state->dyn_ = Kernel::PassedDyn( new Kernel::DynamicEnvironment( dyn_, "resume", resume ) );
608 state->breakExpr_ = breakExpr_;
609 state->resume_ = resume;
610 return RefCountPtr< Kernel::InteractionContinuation >
611 ( new Kernel::InteractionContinuation( parentAnalysisEnv_, bracket_, state->env_, resume,
612 state->dyn_,
613 state->breakExpr_,
614 NO_INPUT_INPUT_NO,
615 is_, os_, outputName_, splitMode_,
616 traceLoc_ ) );
619 void
620 Kernel::InteractionContinuation::setDyn( const Kernel::PassedDyn & dyn )
622 dyn_ = dyn;
625 bool
626 Kernel::InteractionContinuation::reusable( Kernel::EvalState & evalState ) const
628 return env_ == evalState.env_ && dyn_ == evalState.dyn_;
631 void
632 Kernel::InteractionContinuation::takeValue( const RefCountPtr< const Lang::Value > & val, Kernel::EvalState * evalState, bool dummy ) const
634 Kernel::theDebugStepInfo.active_ = false;
635 showValue( val );
637 size_t debugDepth = 0;
639 Kernel::ContRef tmp = evalState->cont_;
640 while( tmp != NullPtr< Kernel::Continuation >( ) )
642 RefCountPtr< Kernel::InteractionContinuation > inter = tmp.down_cast< Kernel::InteractionContinuation >( );
643 if( inter != NullPtr< Kernel::InteractionContinuation >( ) )
645 tmp = inter->resume_;
646 if( tmp != NullPtr< Kernel::Continuation >( ) )
648 ++debugDepth;
651 else
653 tmp = tmp->up( );
658 while( true )
660 /* As long as we fail to return, we ask for new input... */
661 if( debugDepth > 0 )
663 os_ << "[" ;
664 for( size_t i = 0; i < debugDepth; ++i )
666 if( i > 0 )
668 os_ << "," ;
670 os_ << "debug" ;
672 os_ << "]" ;
674 const Ast::FileID * fileID = Ast::FileID::build_fresh_inMemory( );
675 int interactive_inputNo = fileID->inMemoryIndex( );
676 std::ostringstream inputBuf;
677 while( true )
679 interactionFormats.formatPrompt( os_, interactive_inputNo );
680 std::string line;
681 std::getline( is_, line );
682 if( is_.eof( ) )
684 interactionFormats.formatBye( os_, interactive_inputNo );
685 Kernel::theInteractionDone = true;
686 return;
688 if( line.length( ) > 1 && line[ line.length( ) - 1] == ' ' )
690 inputBuf << line.substr( 0, line.length( ) - 1 ) << '\n' ;
692 else
694 inputBuf << line ;
695 break;
698 std::string line = inputBuf.str( );
699 if( line.length( ) > 1 && line[0] == ':' )
701 line = "#db.[" + line.substr(1) + "]";
704 const_cast< Ast::FileID * >( fileID )->setMem( strdup( line.c_str( ) ) );
705 std::istringstream inLine( line + "\n" );
706 Ast::theShapesScanner.queueStream( & inLine, fileID );
707 Ast::theShapesScanner.start( );
710 shapesparse( );
711 interactive_history.push_back( Ast::theInteractiveInput );
712 Ast::CodeBracket * extension = new Ast::CodeBracket( bracket_->loc( ), Ast::theInteractiveInput, bracket_ );
714 Ast::StateIDSet freeStates;
715 extension->analyze( Ast::theProgram, parentAnalysisEnv_, & freeStates );
717 if( ! Ast::theAnalysisErrorsList.empty( ) )
719 std::cout.flush( );
720 typedef typeof Ast::theAnalysisErrorsList ListType;
721 for( ListType::const_iterator i = Ast::theAnalysisErrorsList.begin( ); i != Ast::theAnalysisErrorsList.end( ); ++i )
724 typedef const Exceptions::StaticInconsistency ErrorType;
725 ErrorType * err = dynamic_cast< ErrorType * >( *i );
726 if( err != 0 )
728 std::cerr << err->loc( ) << ": " ;
729 err->display( std::cerr );
730 continue;
733 std::cerr << "(Bad exception type)" << ": " ;
734 (*i)->display( std::cerr );
736 Ast::theAnalysisErrorsList.clear( );
738 else
742 // evalState->env_ = env_; /* Not needed since extension->eval handles this. */
743 evalState->dyn_ = dyn_;
744 /* For the continuation, we make a copy of ourselves. */
745 evalState->cont_ = Kernel::ContRef( new Kernel::InteractionContinuation( parentAnalysisEnv_, bracket_, env_, resume_, dyn_, breakExpr_,
746 interactive_inputNo,
747 is_, os_, outputName_, splitMode_,
748 traceLoc_ ) );
749 extension->eval( evalState, env_ ); /* Note that this is a special kind of eval that extends the given environment. */
751 catch( const Exceptions::CatchableError & ball )
753 Kernel::ContRef cont = evalState->dyn_->getEscapeContinuation( Lang::CONTINUATION_ID_ERROR, ball.getLoc( ) );
754 cont->takeValue( ball.clone( evalState->cont_ ),
755 evalState );
757 return;
760 catch( const Exceptions::StaticInconsistency & ball )
762 os_.flush( );
763 os_ << ball.loc( ) << ": " ;
764 ball.display( os_ );
766 catch( const Exceptions::Exception & ball )
768 os_.flush( );
769 ball.display( os_ );
774 Kernel::ContRef
775 Kernel::InteractionContinuation::up( ) const
777 return Kernel::ContRef( NullPtr< Kernel::Continuation >( ) );
780 RefCountPtr< const char >
781 Kernel::InteractionContinuation::description( ) const
783 if( resume_ != NullPtr< Kernel::Continuation >( ) )
785 return strrefdup( "interaction with resume" );
787 else
789 return strrefdup( "interaction" );
793 void
794 Kernel::InteractionContinuation::gcMark( Kernel::GCMarkedSet & marked )
797 void
798 Kernel::InteractionContinuation::showValue( const RefCountPtr< const Lang::Value > & resultUntyped ) const
802 typedef const Lang::Void ResType;
803 RefCountPtr< ResType > result = Helpers::try_cast_CoreArgument< ResType >( resultUntyped );
804 /* Just be quiet. */
805 return;
807 catch( const NonLocalExit::NotThisType & ball )
809 /* Wrong type; never mind!.. but see below!
814 typedef const Lang::Drawable2D ResType;
815 RefCountPtr< ResType > result = Helpers::try_cast_CoreArgument< ResType >( resultUntyped );
816 Kernel::WarmCatalog catalog;
817 catalog.tackOnPage( dyn_, result, Ast::THE_UNKNOWN_LOCATION );
818 Kernel::WarmCatalog::ShipoutList documents;
819 catalog.shipout( splitMode_ != SPLIT_NO, & documents );
820 std::ofstream oFile;
821 std::string filename;
822 switch( splitMode_ )
824 case SPLIT_NO:
826 noSplitOpen( & oFile, outputName_ );
827 filename = outputName_;
829 break;
830 case SPLIT_FLAT:
832 filename = splitOpen( & oFile, outputName_, "-", result_inputNo_ );
834 break;
835 case SPLIT_DIR:
837 filename = splitOpen( & oFile, outputName_, "/", result_inputNo_ );
839 break;
841 documents.front( ).writeFile( oFile, Kernel::the_PDF_version );
842 oFile.close( );
843 interactionFormats.formatFile( os_, result_inputNo_ ) ;
844 os_ << filename << std::endl ;
845 previewOptions.preview( filename );
846 if( previewOptions.xpdfAction == Interaction::PreviewOptions::XPDF_RAISE && splitMode_ == SPLIT_NO )
848 /* It is disturbing to raise the window more than the first time. */
849 previewOptions.xpdfAction = Interaction::PreviewOptions::XPDF_RELOAD;
851 return;
853 catch( const NonLocalExit::NotThisType & ball )
855 /* Wrong type; never mind!.. but see below!
859 /* This is the default action taken in case non of the types above matched. */
860 interactionFormats.formatShow( os_, result_inputNo_ ) ;
861 resultUntyped->show( os_ );
862 os_ << std::endl ;
865 Kernel::ExitInteractionContinuation::ExitInteractionContinuation( bool * done, int * exitCode, const Ast::SourceLocation & traceLoc )
866 : Kernel::Continuation( traceLoc ), done_( done ), exitCode_( exitCode )
869 Kernel::ExitInteractionContinuation::~ExitInteractionContinuation( )
872 void
873 Kernel::ExitInteractionContinuation::takeValue( const RefCountPtr< const Lang::Value > & val, Kernel::EvalState * evalState, bool dummy ) const
877 typedef const Lang::Symbol ArgType;
878 RefCountPtr< ArgType > key = Helpers::try_cast_CoreArgument< ArgType >( val );
880 static Lang::Symbol CODE_OK( "OK" );
881 static Lang::Symbol CODE_GENERIC_ERROR( "GenericError" );
882 static Lang::Symbol CODE_USER_DETECTED_ERROR( "UserDetectedError" );
883 if( *key == CODE_OK )
885 *exitCode_ = Interaction::EXIT_OK;
887 else if( *key == CODE_GENERIC_ERROR )
889 *exitCode_ = Interaction::EXIT_GENERIC_ERROR;
891 else if( *key == CODE_USER_DETECTED_ERROR )
893 *exitCode_ = Interaction::EXIT_USER_DETECTED_ERROR;
895 else
897 std::ostringstream oss;
898 oss << "Valid exit codes symbols are { "
899 << CODE_OK.name( ).getPtr( ) << ", "
900 << CODE_GENERIC_ERROR.name( ).getPtr( ) << ", "
901 << CODE_USER_DETECTED_ERROR.name( ).getPtr( )
902 << " }." ;
903 throw Exceptions::OutOfRange( traceLoc_, strrefdup( oss ) );
906 *done_ = true;
907 return;
909 catch( const NonLocalExit::NotThisType & ball )
911 /* Wrong type; never mind!.. but see below!
917 typedef const Lang::Integer ArgType;
918 *exitCode_ = Helpers::try_cast_CoreArgument< ArgType >( val )->val_;
919 if( -99 <= *exitCode_ || *exitCode_ <= 99 )
921 throw Exceptions::OutOfRange( traceLoc_, "Literal integer exit codes must be in the range [ -99, 99 ]. Documented values in the reserved range are accessed via symbols." );
923 *done_ = true;
924 return;
926 catch( const NonLocalExit::NotThisType & ball )
928 /* Wrong type; never mind!.. but see below!
932 throw Exceptions::ContinuationTypeMismatch( this, val->getTypeName( ), Helpers::typeSetString( Lang::Symbol::staticTypeName( ), Lang::Integer::staticTypeName( ) ) );
935 Kernel::ContRef
936 Kernel::ExitInteractionContinuation::up( ) const
938 return Kernel::ContRef( NullPtr< Kernel::Continuation >( ) );
941 RefCountPtr< const char >
942 Kernel::ExitInteractionContinuation::description( ) const
944 return strrefdup( "exit (non-forcing)" );
947 void
948 Kernel::ExitInteractionContinuation::gcMark( Kernel::GCMarkedSet & marked )
952 namespace Shapes
954 namespace Kernel
957 template< class T >
958 class Mutator_resume : public Lang::CoreFunction
960 public:
961 Mutator_resume( const char * title )
962 : CoreFunction( title, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title ), false ) )
964 formals_->appendEvaluatedCoreFormal( "result", Kernel::THE_VOID_VARIABLE );
966 virtual void
967 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
969 args.applyDefaults( );
971 typedef T StateType;
972 StateType * state = Helpers::mutator_cast_self< StateType >( args.getMutatorSelf( ) );
973 if( state->resume_ == NullPtr< typeof *(state->resume_) >( ) )
975 throw Exceptions::CoreRequirement( "The top level debug state has no continuation to resume.", title_, callLoc );
978 if( args.getHandle( 0 ) == Kernel::THE_VOID_VARIABLE && state->breakExpr_ != 0 )
980 /* The user did not provide an argument and there is a default expression to resume with, which should be set to where evaluation was interrupted.
981 * Since the reason the evaluation was interrupted may be the presence of a breakpoint, we must avoid ending up breaking at the same expression again.
982 * Calling the <eval> method from here might solve the problem, but the number of places where this method is called should really be kept to a
983 * minimum. Hence, using the <ignoreCount_> is preferred.
985 if( state->breakExpr_->breakpoint_ != 0 &&
986 state->breakExpr_->breakpoint_->enabled_ )
988 ++(state->breakExpr_->breakpoint_->ignoreCount_);
990 evalState->cont_ = state->resume_;
991 evalState->env_ = state->env_->getParent( );
992 evalState->dyn_ = state->dyn_;
993 evalState->expr_ = state->breakExpr_;
995 else
997 /* Invoke the escape continuation exactly as in ContinueDynamicECFunction::call.
999 evalState->cont_ = state->resume_;
1000 evalState->expr_ = 0;
1001 state->resume_->takeHandle( args.getHandle( 0 ),
1002 evalState );
1007 template< class T >
1008 class Mutator_top_repl : public Lang::CoreFunction
1010 public:
1011 Mutator_top_repl( const char * title )
1012 : CoreFunction( title, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title ), false ) )
1014 formals_->appendEvaluatedCoreFormal( "result", Kernel::THE_VOID_VARIABLE );
1016 virtual void
1017 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1019 args.applyDefaults( );
1021 // typedef T StateType;
1022 // StateType * state = Helpers::mutator_cast_self< StateType >( args.getMutatorSelf( ) );
1024 /* Invoke the escape continuation exactly as in ContinueDynamicECFunction::call.
1026 Kernel::ContRef cont = evalState->dyn_->getEscapeContinuation( Lang::CONTINUATION_TOP_REPL_ID, callLoc );
1027 evalState->cont_ = cont;
1028 evalState->expr_ = 0;
1029 cont->takeHandle( args.getHandle( 0 ),
1030 evalState );
1034 template< class T >
1035 class Mutator_cont : public Lang::CoreFunction
1037 public:
1038 typedef enum { UP, EXIT_DEBUG } Kind;
1039 private:
1040 Kind kind_;
1041 public:
1042 Mutator_cont( const char * title, Kind kind )
1043 : CoreFunction( title, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title ), false ) ),
1044 kind_( kind )
1046 formals_->appendEvaluatedCoreFormal( "count", Helpers::newValHandle( new Lang::Integer( 1 ) ) );
1048 virtual void
1049 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1051 args.applyDefaults( );
1053 /* While activating an already existing interactive continuation allows an old WarmDebugger to be reused as is,
1054 * changing the resume continuation within the current interactive context requires the current WarmDebugger to
1055 * be modified. Hence, to not modify any other state than that that calls this method, the UP mode can not be
1056 * used to reach continuations beyond the next interactive continuation.
1059 /* Note that we don't start counting in state->resume_, but search an interactive continuation from evalState->cont_.
1060 * The reason is that this provides a unified way of obtaining an interactive continuation _below_ the new resume continuation.
1061 * In most cases, this will be exactly what one expects, but in rare cases this behavior may seem strange.
1064 size_t argsi = 0;
1065 typedef const Lang::Integer ArgType;
1066 size_t argsi_count = argsi;
1067 int count = Helpers::down_cast_CoreArgument< ArgType >( title_, args, argsi_count, callLoc )->val_;
1068 if( count <= 0 )
1070 throw Exceptions::CoreOutOfRange( title_, args, argsi_count, "The count must be positive." );
1073 Kernel::ContRef tmp = evalState->cont_;
1074 RefCountPtr< Kernel::InteractionContinuation > bottom_interactive = tmp.down_cast< Kernel::InteractionContinuation >( );
1075 while( bottom_interactive == NullPtr< typeof *bottom_interactive >( ) )
1077 if( tmp == NullPtr< Kernel::Continuation >( ) )
1079 throw Exceptions::CoreOutOfRange( title_, args, argsi_count, "There is no interactive continuation in the backtrace to start counting from." );
1081 tmp = tmp->up( );
1082 bottom_interactive = tmp.down_cast< Kernel::InteractionContinuation >( );
1084 tmp = bottom_interactive->resume( );
1086 while( count > 0 )
1088 if( tmp == NullPtr< Kernel::Continuation >( ) )
1090 throw Exceptions::CoreOutOfRange( title_, args, argsi_count, "The count exceeds the current depth." );
1092 RefCountPtr< Kernel::InteractionContinuation > inter = tmp.down_cast< Kernel::InteractionContinuation >( );
1093 if( inter != NullPtr< typeof *inter >( ) )
1095 if( kind_ == UP )
1097 throw Exceptions::CoreOutOfRange( title_, args, argsi_count, "The count exceeds depth down to the next interactive continuations." );
1099 bottom_interactive = inter;
1100 if( count == 1 )
1102 /* The continuation will be reused, which corresponds to one decrement of <count>. */
1103 break;
1105 tmp = bottom_interactive->resume( );
1106 --count;
1108 else
1110 tmp = tmp->up( );
1111 if( kind_ == UP )
1113 --count;
1117 if( tmp == NullPtr< Kernel::Continuation >( ) )
1119 throw Exceptions::CoreOutOfRange( title_, args, argsi_count, "The count exceeds the current depth." );
1122 /* If tmp is an interactive continuation, we reuse it, otherwise we set up a new one.
1124 if( tmp.down_cast< Kernel::InteractionContinuation >( ) != NullPtr< Kernel::InteractionContinuation >( ) )
1126 evalState->cont_ = tmp;
1128 else
1130 if( kind_ != UP )
1132 throw Exceptions::InternalError( "Mutator_cont: Expected kind_ to be UP when unable to reuse continuation." );
1134 typedef T StateType;
1135 StateType * state = Helpers::mutator_cast_self< StateType >( args.getMutatorSelf( ) );
1136 RefCountPtr< Kernel::InteractionContinuation > inter = bottom_interactive->cloneWithNewContinuation( tmp, state );
1137 evalState->cont_ = inter;
1139 evalState->expr_ = Kernel::theVoidExpression;
1143 template< class T >
1144 class Mutator_step : public Lang::CoreFunction
1146 Kernel::DebugStepInfo::StepMode mode_;
1147 public:
1148 Mutator_step( const char * title, Kernel::DebugStepInfo::StepMode mode )
1149 : CoreFunction( title, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title ), true ) ),
1150 mode_( mode )
1152 formals_->appendEvaluatedCoreFormal( "count", Helpers::newValHandle( new Lang::Integer( 1 ) ) );
1154 virtual void
1155 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1157 args.applyDefaults( );
1159 typedef T StateType;
1160 StateType * state = Helpers::mutator_cast_self< StateType >( args.getMutatorSelf( ) );
1161 if( state->breakExpr_ == 0 )
1163 throw Exceptions::CoreRequirement( "Currently not at any source location, so source stepping is not possible.", title_, callLoc );
1166 size_t argsi = 0;
1167 typedef const Lang::Integer ArgType;
1168 int count = Helpers::down_cast_CoreArgument< ArgType >( title_, args, argsi, callLoc )->val_;
1169 if( count < 1 )
1171 throw Exceptions::CoreOutOfRange( title_, args, argsi, "The count must be at least 1." );
1174 Kernel::theDebugStepInfo.active_ = true;
1175 Kernel::theDebugStepInfo.mode_ = mode_;
1176 Kernel::theDebugStepInfo.refLoc_ = state->breakExpr_->loc( );
1177 Kernel::theDebugStepInfo.count_ = static_cast< size_t >( count ) + ( ( mode_ == Kernel::DebugStepInfo::EXPR ) ? 1 : 0 );
1179 /* The rest is more or less the same as in Mutator_resume. */
1180 if( state->breakExpr_->breakpoint_ != 0 &&
1181 state->breakExpr_->breakpoint_->enabled_ )
1183 ++(state->breakExpr_->breakpoint_->ignoreCount_);
1185 evalState->cont_ = state->resume_;
1186 evalState->env_ = state->env_->getParent( );
1187 evalState->dyn_ = state->dyn_;
1188 evalState->expr_ = state->breakExpr_;
1192 template< class T >
1193 class Mutator_step_to_temporary : public Lang::CoreFunction
1195 public:
1196 typedef enum { CHILD, SIBLING } Destination;
1197 private:
1198 Destination destination_;
1199 public:
1200 Mutator_step_to_temporary( const char * title, Destination destination )
1201 : CoreFunction( title, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title ), true ) ),
1202 destination_( destination )
1204 virtual void
1205 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1207 args.applyDefaults( );
1209 typedef T StateType;
1210 StateType * state = Helpers::mutator_cast_self< StateType >( args.getMutatorSelf( ) );
1211 if( state->breakExpr_ == 0 )
1213 throw Exceptions::CoreRequirement( "Currently not at any source location, so source stepping is not possible.", title_, callLoc );
1216 /* Now, depending on destination_, temporary breakpoints are set.
1217 * We don't touch the ignore count here, which may or may not be what the user expects, but gives the user a way to avoid stopping in expressions
1218 * of little/no interest to inspect. Obvious alternatives are to clear the ignore count for temporary breakpoints, or to just clear the ignore count temporarily.
1220 size_t count = 0; /* Count number of expression where we set a temporary breakpoint. */
1222 switch( destination_ )
1224 case CHILD:
1226 Ast::Node::ChildrenType & exprs = state->breakExpr_->children( );
1227 for( Ast::Node::ChildrenType::iterator i = exprs.begin( ); i != exprs.end( ); ++i )
1229 Ast::Expression * expr = dynamic_cast< Ast::Expression * >( *i );
1230 if( expr == 0 )
1232 continue;
1234 ++count;
1235 if( expr->breakpoint_ == 0 )
1237 expr->breakpoint_ = new Kernel::BreakpointInfo( );
1238 expr->breakpoint_->createdForTemporaryUse_ = true;
1239 Kernel::theBreakpoints.insert( expr );
1241 expr->breakpoint_->persistentEnabled_ = expr->breakpoint_->enabled_;
1242 expr->breakpoint_->enabled_ = true;
1243 Kernel::theTemporaryBreakpoints.insert( expr );
1246 break;
1247 case SIBLING:
1249 Ast::Node * parent = state->breakExpr_->parent( );
1250 if( parent == 0 )
1252 throw Exceptions::CoreRequirement( "Unable to locate siblings since there is no parent here.", title_, callLoc );
1254 Ast::Node::ChildrenType & exprs = parent->children( );
1255 for( Ast::Node::ChildrenType::iterator i = exprs.begin( ); i != exprs.end( ); ++i )
1257 Ast::Expression * expr = dynamic_cast< Ast::Expression * >( *i );
1258 if( expr == 0 || expr == state->breakExpr_ )
1260 continue;
1262 ++count;
1263 if( expr->breakpoint_ == 0 )
1265 expr->breakpoint_ = new Kernel::BreakpointInfo( );
1266 expr->breakpoint_->createdForTemporaryUse_ = true;
1267 Kernel::theBreakpoints.insert( expr );
1269 expr->breakpoint_->persistentEnabled_ = expr->breakpoint_->enabled_;
1270 expr->breakpoint_->enabled_ = true;
1271 Kernel::theTemporaryBreakpoints.insert( expr );
1274 break;
1277 if( count == 0 )
1279 throw Exceptions::CoreRequirement( "No temporary breakpoints were set. Not resuming evaluation.", title_, callLoc );
1282 /* The rest is more or less the same as in Mutator_resume. */
1283 if( state->breakExpr_->breakpoint_ != 0 &&
1284 state->breakExpr_->breakpoint_->enabled_ )
1286 ++(state->breakExpr_->breakpoint_->ignoreCount_);
1288 evalState->cont_ = state->resume_;
1289 evalState->env_ = state->env_->getParent( );
1290 evalState->dyn_ = state->dyn_;
1291 evalState->expr_ = state->breakExpr_;
1295 template< class T >
1296 class Mutator_backtrace : public Lang::CoreFunction
1298 public:
1299 Mutator_backtrace( const char * title )
1300 : CoreFunction( title, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title ), true ) )
1303 virtual void
1304 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1306 args.applyDefaults( );
1308 typedef T StateType;
1309 StateType * state = Helpers::mutator_cast_self< StateType >( args.getMutatorSelf( ) );
1311 std::ostringstream oss;
1313 typedef std::list< std::pair< const Kernel::Continuation *, RefCountPtr< const char > > > ListType;
1314 ListType trace;
1315 size_t debugDepth = 0;
1316 trace.push_front( ListType::value_type( 0, strrefdup( "==( bottom resume )==" ) ) );
1317 const Kernel::Continuation * tmp = state->resume_.getPtr( );
1318 while( tmp != NullPtr< Kernel::Continuation >( ) )
1320 trace.push_front( ListType::value_type( tmp, tmp->description( ) ) );
1321 const Kernel::InteractionContinuation * inter = dynamic_cast< const Kernel::InteractionContinuation * >( tmp );
1322 if( inter != 0 )
1324 tmp = inter->resume( ).getPtr( );
1325 if( tmp != 0 )
1327 trace.push_front( ListType::value_type( 0, strrefdup( "--( next resume )--" ) ) );
1328 ++debugDepth;
1331 else
1333 tmp = tmp->up( ).getPtr( );
1336 trace.push_front( ListType::value_type( 0, strrefdup( "==( top )==" ) ) );
1338 oss << std::endl ; /* Ensure we start on a new line. */
1339 ListType::const_iterator i = trace.begin( );
1340 for( ; i != trace.end( ); ++i )
1342 if( i->first == 0 )
1344 oss << i->second << std::endl ;
1346 else
1348 oss << " " << i->first->traceLoc( ) << "\t" << i->second << std::endl ;
1353 Kernel::ContRef cont = evalState->cont_;
1354 cont->takeValue( Kernel::ValueRef( new Lang::String( strrefdup( oss ) ) ),
1355 evalState );
1359 template< class T >
1360 class Mutator_printEnv : public Lang::CoreFunction
1362 public:
1363 Mutator_printEnv( const char * title )
1364 : CoreFunction( title, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title ), true ) )
1367 virtual void
1368 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1370 args.applyDefaults( );
1372 typedef T StateType;
1373 StateType * state = Helpers::mutator_cast_self< StateType >( args.getMutatorSelf( ) );
1375 std::ostringstream oss;
1376 oss << std::endl ; /* Ensure we start on a new line. */
1377 state->env_->print( oss );
1379 Kernel::ContRef cont = evalState->cont_;
1380 cont->takeValue( Kernel::ValueRef( new Lang::String( strrefdup( oss ) ) ),
1381 evalState );
1385 template< class T >
1386 class Mutator_printDyn : public Lang::CoreFunction
1388 public:
1389 Mutator_printDyn( const char * title )
1390 : CoreFunction( title, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title ), true ) )
1393 virtual void
1394 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1396 args.applyDefaults( );
1398 typedef T StateType;
1399 StateType * state = Helpers::mutator_cast_self< StateType >( args.getMutatorSelf( ) );
1401 std::ostringstream oss;
1402 oss << std::endl ; /* Ensure we start on a new line. */
1403 state->dyn_->print( oss );
1405 Kernel::ContRef cont = evalState->cont_;
1406 cont->takeValue( Kernel::ValueRef( new Lang::String( strrefdup( oss ) ) ),
1407 evalState );
1411 template< class T >
1412 class Mutator_printBreakpoints : public Lang::CoreFunction
1414 public:
1415 Mutator_printBreakpoints( const char * title )
1416 : CoreFunction( title, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title ), true ) )
1419 virtual void
1420 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1422 args.applyDefaults( );
1424 // typedef T StateType;
1425 // StateType * state = Helpers::mutator_cast_self< StateType >( args.getMutatorSelf( ) );
1427 std::ostringstream oss;
1428 oss << std::endl ; /* Ensure we start on a new line. */
1429 typedef typeof Kernel::theBreakpoints ListType;
1430 size_t index = 1;
1431 for( ListType::const_iterator i = Kernel::theBreakpoints.begin( ); i != Kernel::theBreakpoints.end( ); ++i, ++index )
1433 oss << std::setw(3) << index << ( ( (*i)->breakpoint_->enabled_ ) ? " (on )" : " (off)" ) ;
1434 if( (*i)->breakpoint_->ignoreCount_ > 0 )
1436 oss << " (ignore " << (*i)->breakpoint_->ignoreCount_ << " times)" ;
1438 oss << ": " << (*i)->loc( ) << std::endl ;
1441 Kernel::ContRef cont = evalState->cont_;
1442 cont->takeValue( Kernel::ValueRef( new Lang::String( strrefdup( oss ) ) ),
1443 evalState );
1447 template< class T >
1448 class Mutator_clearBreak : public Lang::CoreFunction
1450 public:
1451 Mutator_clearBreak( const char * title )
1452 : CoreFunction( title, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title ), true ) )
1454 formals_->appendEvaluatedCoreFormal( "index", Helpers::newValHandle( new Lang::Integer( 0 ) ) );
1456 virtual void
1457 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1459 args.applyDefaults( );
1461 typedef T StateType;
1462 StateType * state = Helpers::mutator_cast_self< StateType >( args.getMutatorSelf( ) );
1464 size_t argsi = 0;
1465 typedef const Lang::Integer ArgType;
1466 int index = Helpers::down_cast_CoreArgument< ArgType >( title_, args, argsi, callLoc )->val_;
1467 if( index == 0 )
1469 if( state->breakExpr_ == 0 )
1471 throw Exceptions::CoreOutOfRange( title_, args, argsi, "Currently not at any source location, so the breakpoint index 0 is invalid." );
1474 if( index < 0 || static_cast< int >( Kernel::theBreakpoints.size( ) ) < index )
1476 throw Exceptions::CoreOutOfRange( title_, args, argsi, "The index must be either zero (meaning the current breakpoint) or a positive number not greater than the number of breakpoints." );
1478 if( index == 0 )
1480 Ast::Expression * expr = state->breakExpr_;
1481 if( expr->breakpoint_ != 0 )
1483 delete expr->breakpoint_;
1484 expr->breakpoint_ = 0;
1485 Kernel::theBreakpoints.erase( expr );
1488 else
1490 typedef typeof Kernel::theBreakpoints SetType;
1491 SetType::iterator i = Kernel::theBreakpoints.begin( );
1492 for( int tmp = 1; tmp < index; ++tmp, ++i )
1494 delete (*i)->breakpoint_;
1495 (*i)->breakpoint_ = 0;
1496 Kernel::theBreakpoints.erase( *i );
1499 Kernel::ContRef cont = evalState->cont_;
1500 cont->takeValue( Lang::THE_VOID,
1501 evalState );
1505 template< class T >
1506 class Mutator_clearAllBreak : public Lang::CoreFunction
1508 public:
1509 Mutator_clearAllBreak( const char * title )
1510 : CoreFunction( title, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title ), true ) )
1513 virtual void
1514 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1516 args.applyDefaults( );
1518 typedef T StateType;
1519 /* The state is not used at the moment. */
1520 // StateType * state = Helpers::mutator_cast_self< StateType >( args.getMutatorSelf( ) );
1522 typedef typeof Kernel::theBreakpoints SetType;
1523 for( SetType::iterator i = Kernel::theBreakpoints.begin( ); i != Kernel::theBreakpoints.end( ); ++i )
1525 delete (*i)->breakpoint_;
1526 (*i)->breakpoint_ = 0;
1528 Kernel::theBreakpoints.clear( );
1530 Kernel::ContRef cont = evalState->cont_;
1531 cont->takeValue( Lang::THE_VOID,
1532 evalState );
1536 template< class T >
1537 class Mutator_ignoreBreak : public Lang::CoreFunction
1539 public:
1540 Mutator_ignoreBreak( const char * title )
1541 : CoreFunction( title, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title ), true ) )
1543 formals_->appendEvaluatedCoreFormal( "index", Helpers::newValHandle( new Lang::Integer( 0 ) ) );
1544 formals_->appendEvaluatedCoreFormal( "count", Helpers::newValHandle( new Lang::Integer( 1 ) ) );
1546 virtual void
1547 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1549 args.applyDefaults( );
1551 typedef T StateType;
1552 StateType * state = Helpers::mutator_cast_self< StateType >( args.getMutatorSelf( ) );
1554 size_t argsi = 0;
1555 typedef const Lang::Integer ArgType;
1556 int index = Helpers::down_cast_CoreArgument< ArgType >( title_, args, argsi, callLoc )->val_;
1557 if( index == 0 )
1559 if( state->breakExpr_ == 0 )
1561 throw Exceptions::CoreOutOfRange( title_, args, argsi, "Currently not at any source location, so the breakpoint index 0 is invalid." );
1564 else if( index < 0 || static_cast< int >( Kernel::theBreakpoints.size( ) ) < index )
1566 throw Exceptions::CoreOutOfRange( title_, args, argsi, "The index must be either zero (meaning the current breakpoint) or a positive number not greater than the number of breakpoints." );
1568 ++argsi;
1569 int count = Helpers::down_cast_CoreArgument< ArgType >( title_, args, argsi, callLoc )->val_;
1570 if( count < 0 )
1572 throw Exceptions::CoreOutOfRange( title_, args, argsi, "The count must be non-negative." );
1574 if( index == 0 )
1576 Ast::Expression * expr = state->breakExpr_;
1577 if( expr->breakpoint_ == 0 )
1579 expr->breakpoint_ = new Kernel::BreakpointInfo( );
1580 Kernel::theBreakpoints.insert( expr );
1582 expr->breakpoint_->ignoreCount_ = static_cast< size_t >( count );
1584 else
1586 typedef typeof Kernel::theBreakpoints SetType;
1587 SetType::iterator i = Kernel::theBreakpoints.begin( );
1588 for( int tmp = 1; tmp < index; ++tmp, ++i )
1590 (*i)->breakpoint_->ignoreCount_ = static_cast< size_t >( count );
1593 Kernel::ContRef cont = evalState->cont_;
1594 cont->takeValue( Lang::THE_VOID,
1595 evalState );
1600 template< class T >
1601 class Mutator_setBreakLocation : public Lang::CoreFunction
1603 public:
1604 Mutator_setBreakLocation( const char * title )
1605 : CoreFunction( title, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title ), true ) )
1607 formals_->appendEvaluatedCoreFormal( "file", Kernel::THE_SLOT_VARIABLE );
1608 formals_->appendEvaluatedCoreFormal( "line", Kernel::THE_SLOT_VARIABLE );
1609 formals_->appendEvaluatedCoreFormal( "column", Helpers::newValHandle( new Lang::Integer( 0 ) ) );
1610 formals_->appendEvaluatedCoreFormal( "enable", Kernel::THE_VOID_VARIABLE );
1612 virtual void
1613 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1615 args.applyDefaults( );
1617 typedef T StateType;
1618 /* The state is not used at the moment. */
1619 // StateType * state = Helpers::mutator_cast_self< StateType >( args.getMutatorSelf( ) );
1621 size_t argsi = 0;
1622 struct stat theStat;
1623 std::string fileArg = Helpers::down_cast_CoreArgument< const Lang::String >( title_, args, argsi, callLoc )->val_.getPtr( );
1624 ++argsi;
1625 int line = Helpers::down_cast_CoreArgument< const Lang::Integer >( title_, args, argsi, callLoc )->val_;
1626 if( line < 1 )
1628 throw Exceptions::CoreOutOfRange( title_, args, argsi, "The line number must be positive." );
1630 ++argsi;
1631 int column = Helpers::down_cast_CoreArgument< const Lang::Integer >( title_, args, argsi, callLoc )->val_;
1632 if( column < 0 )
1634 throw Exceptions::CoreOutOfRange( title_, args, argsi, "The column number must be non-negative." );
1636 ++argsi;
1637 RefCountPtr< const Lang::Boolean > breakPtr = Helpers::down_cast_CoreArgument< const Lang::Boolean >( title_, args, argsi, callLoc, true );
1639 const Ast::FileID * fileID = 0;
1640 if( ! Ast::FileID::is_inMemory( fileArg, & fileID ) )
1644 std::string filename = Ast::theShapesScanner.searchFile( fileArg, & theStat );
1645 fileID = Ast::FileID::build_stat( theStat, fileArg );
1647 catch( const Exceptions::Exception & ball )
1649 throw Exceptions::CoreOutOfRange( title_, args, 0, "Failed to locate source file." );
1652 Ast::SourceLocation loc( fileID );
1653 loc.firstLine = line;
1654 loc.lastLine = line;
1655 if( Interaction::characterColumnInBytes )
1657 loc.firstColumn = column;
1658 loc.lastColumn = column;
1660 else
1662 /* Column is the UTF8 column, and needs to be converted to byte column. */
1665 int byteColumn = fileID->UTF8ColumnTobyteColumn( line, column );
1666 loc.firstColumn = byteColumn;
1667 loc.lastColumn = byteColumn;
1669 catch( const Exceptions::OutOfRange & ball )
1671 /* Without actually looking into ball we guess what the problem is... */
1672 throw Exceptions::CoreOutOfRange( title_, args, 1, "Line seems past end of file." );
1675 Ast::Expression * expr = loc.findExpression( );
1676 if( expr == 0 )
1678 throw Exceptions::CoreOutOfRange( title_, args, 0, "Failed to locate position within the source file." );
1680 if( expr->breakpoint_ == 0 )
1682 expr->breakpoint_ = new Kernel::BreakpointInfo( );
1683 Kernel::theBreakpoints.insert( expr );
1686 bool newEnabled;
1687 if( breakPtr == NullPtr< const Lang::Boolean >( ) )
1689 newEnabled = ! expr->breakpoint_->enabled_;
1691 else
1693 newEnabled = breakPtr->val_;
1696 expr->breakpoint_->enabled_ = newEnabled;
1698 Kernel::ContRef cont = evalState->cont_;
1699 cont->takeValue( Lang::THE_VOID,
1700 evalState );
1704 template< class T >
1705 class Mutator_setBreakFunctionBody : public Lang::CoreFunction
1707 public:
1708 Mutator_setBreakFunctionBody( const char * title )
1709 : CoreFunction( title, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title ), true ) )
1711 formals_->appendEvaluatedCoreFormal( "function", Kernel::THE_SLOT_VARIABLE );
1712 formals_->appendEvaluatedCoreFormal( "enable", Kernel::THE_VOID_VARIABLE );
1714 virtual void
1715 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1717 args.applyDefaults( );
1719 typedef T StateType;
1720 /* The state is not used at the moment. */
1721 // StateType * state = Helpers::mutator_cast_self< StateType >( args.getMutatorSelf( ) );
1723 size_t argsi = 0;
1724 typedef const Lang::UserFunction ArgType;
1725 RefCountPtr< ArgType > fun = Helpers::down_cast_CoreArgument< ArgType >( title_, args, argsi, callLoc );
1726 ++argsi;
1727 RefCountPtr< const Lang::Boolean > breakPtr = Helpers::down_cast_CoreArgument< const Lang::Boolean >( title_, args, argsi, callLoc, true );
1729 Ast::Expression * expr = const_cast< Lang::UserFunction * >( fun.getPtr( ) )->body( );
1730 if( expr->breakpoint_ == 0 )
1732 expr->breakpoint_ = new Kernel::BreakpointInfo( );
1733 Kernel::theBreakpoints.insert( expr );
1736 bool newEnabled;
1737 if( breakPtr == NullPtr< const Lang::Boolean >( ) )
1739 newEnabled = ! expr->breakpoint_->enabled_;
1741 else
1743 newEnabled = breakPtr->val_;
1746 expr->breakpoint_->enabled_ = newEnabled;
1748 Kernel::ContRef cont = evalState->cont_;
1749 cont->takeValue( Lang::THE_VOID,
1750 evalState );
1757 Kernel::WarmDebugger::WarmDebugger( Kernel::Environment * env, Kernel::PassedDyn dyn, Kernel::ContRef resume, Ast::Expression * breakExpr )
1758 : env_( env ), dyn_( dyn ), resume_( resume ), breakExpr_( breakExpr )
1761 Kernel::WarmDebugger::~WarmDebugger( )
1764 void
1765 Debugger_register_mutators( Lang::SystemFinalClass * dstClass )
1767 dstClass->registerMutator( new Kernel::Mutator_resume< Kernel::WarmDebugger >( "resume" ), "r" );
1768 dstClass->registerMutator( new Kernel::Mutator_top_repl< Kernel::WarmDebugger >( "top_repl" ) );
1769 dstClass->registerMutator( new Kernel::Mutator_backtrace< Kernel::WarmDebugger >( "backtrace" ), "t" );
1770 dstClass->registerMutator( new Kernel::Mutator_printEnv< Kernel::WarmDebugger >( "env" ), "e" );
1771 dstClass->registerMutator( new Kernel::Mutator_printDyn< Kernel::WarmDebugger >( "dyn" ), "d" );
1772 dstClass->registerMutator( new Kernel::Mutator_printBreakpoints< Kernel::WarmDebugger >( "breakList" ), "bl" );
1773 dstClass->registerMutator( new Kernel::Mutator_setBreakLocation< Kernel::WarmDebugger >( "breakAt" ), "ba" );
1774 dstClass->registerMutator( new Kernel::Mutator_setBreakFunctionBody< Kernel::WarmDebugger >( "breakIn" ), "bi" );
1775 dstClass->registerMutator( new Kernel::Mutator_ignoreBreak< Kernel::WarmDebugger >( "breakIgnore" ), "bg" );
1776 dstClass->registerMutator( new Kernel::Mutator_clearBreak< Kernel::WarmDebugger >( "breakClear" ), "bc" );
1777 dstClass->registerMutator( new Kernel::Mutator_clearAllBreak< Kernel::WarmDebugger >( "breakClearAll" ), "bC" );
1778 dstClass->registerMutator( new Kernel::Mutator_step< Kernel::WarmDebugger >( "stepe", Kernel::DebugStepInfo::EXPR ), "se" );
1779 dstClass->registerMutator( new Kernel::Mutator_step< Kernel::WarmDebugger >( "step", Kernel::DebugStepInfo::STEP ), "s" );
1780 dstClass->registerMutator( new Kernel::Mutator_step_to_temporary< Kernel::WarmDebugger >( "stepc", Kernel::Mutator_step_to_temporary< Kernel::WarmDebugger >::CHILD ), "sc" );
1781 dstClass->registerMutator( new Kernel::Mutator_step_to_temporary< Kernel::WarmDebugger >( "steps", Kernel::Mutator_step_to_temporary< Kernel::WarmDebugger >::SIBLING ), "ss" );
1782 dstClass->registerMutator( new Kernel::Mutator_cont< Kernel::WarmDebugger >( "contUp", Kernel::Mutator_cont< Kernel::WarmDebugger >::UP ), "cu" );
1783 dstClass->registerMutator( new Kernel::Mutator_cont< Kernel::WarmDebugger >( "contExit", Kernel::Mutator_cont< Kernel::WarmDebugger >::EXIT_DEBUG ), "ce" );
1786 RefCountPtr< const Lang::Class > Kernel::WarmDebugger::TypeID( new Lang::SystemFinalClass( strrefdup( "#Debugger" ), Debugger_register_mutators ) );
1787 TYPEINFOIMPL_STATE( WarmDebugger );
1789 void
1790 Kernel::WarmDebugger::tackOnImpl( Kernel::EvalState * evalState, const RefCountPtr< const Lang::Value > & piece,const Ast::SourceLocation & callLoc )
1792 throw Exceptions::MiscellaneousRequirement( strrefdup( "The debugger only interacts through named mutators; there is no tack-on mutator." ) );
1795 void
1796 Kernel::WarmDebugger::freezeImpl( Kernel::EvalState * evalState, const Ast::SourceLocation & callLoc )
1798 throw Exceptions::MiscellaneousRequirement( strrefdup( "The debugger cannot be frozen." ) );
1801 void
1802 Kernel::WarmDebugger::peekImpl( Kernel::EvalState * evalState, const Ast::SourceLocation & callLoc )
1804 throw Exceptions::MiscellaneousRequirement( strrefdup( "The debugger cannot be peeked." ) );
1807 void
1808 Kernel::WarmDebugger::gcMark( Kernel::GCMarkedSet & marked )
1812 Kernel::BreakpointInfo::BreakpointInfo( )
1813 : enabled_( false ), createdForTemporaryUse_( false ), ignoreCount_( 0 )
1816 Kernel::BreakpointInfo::~BreakpointInfo( )