Update procedures
[shapes.git] / source / eval_interactive.cc
blob229c0949b4808b4e7acdf533a845f66fb006070b
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, 2014 Henrik Tidefelt
19 #include "main.h"
20 #include "astvar.h"
21 #include "breakpoints.h"
22 #include "shapescore.h"
24 #include <typeinfo>
26 using namespace Shapes;
27 using namespace SimplePDF;
29 namespace Shapes
31 namespace Ast
33 class VoidExpression : public Expression
35 public:
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;
43 namespace Kernel
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_;
55 int result_inputNo_;
56 std::istream & is_;
57 std::ostream & os_;
58 std::string outputName_;
59 SplitMode splitMode_;
60 public:
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. */
73 private:
74 void showValue( const RefCountPtr< const Lang::Value > & resultUntyped ) const;
77 class ExitInteractionContinuation : public Kernel::Continuation
79 bool * done_;
80 int * exitCode_;
81 public:
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 );
90 class DebugStepInfo
92 public:
93 typedef enum { EXPR, STEP } StepMode;
95 bool active_;
96 StepMode mode_;
97 Ast::SourceLocation refLoc_; /* Note: Not a const reference. Will be reassigned. Make sure not to initialize const SourceLocation & references with this value! */
98 size_t count_;
99 DebugStepInfo( )
100 : active_( false ), mode_( EXPR ), refLoc_( Ast::THE_UNKNOWN_LOCATION, bool( ) ), count_( 1 )
102 bool stop( const Ast::SourceLocation & loc )
104 switch( mode_ )
106 case EXPR:
107 /* Stop at everything. No need to update refLoc_ . */
108 break;
109 case STEP:
111 if( refLoc_.contains( loc ) )
113 return false;
115 refLoc_ = loc;
117 break;
119 --count_;
120 if( count_ == 0 )
122 active_ = false;
123 return true;
125 return false;
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?! */
139 namespace Lang
141 const char * CONTINUATION_TOP_REPL_ID = "top_repl";
145 void
146 interactiveEvaluation( std::istream & in, std::ostream & out, const std::string & outputName, SplitMode splitMode,
147 bool evalTrace, bool evalBackTrace, bool cleanupMemory,
148 RefCountPtr< std::ifstream > & labelDBFile, const std::string & labelDBName )
150 if( ! Interaction::blankMode ){
151 /* Clean up outout from earlier sessions. */
152 switch( splitMode )
154 case SPLIT_NO:
155 break;
156 case SPLIT_FLAT:
158 rmSplitFiles( outputName, "-" );
160 break;
161 case SPLIT_DIR:
163 mkSplitDir( outputName );
164 rmSplitFiles( outputName, "/" );
166 break;
170 RefCountPtr< const Kernel::GraphicsState > graphicsState( new Kernel::GraphicsState( true ) );
171 Kernel::PassedDyn baseDyn( new Kernel::DynamicEnvironment( graphicsState ) );
175 /* Evaluate preamble. */
176 shapesparse( );
177 initCore( labelDBFile, labelDBName );
179 bool done = false;
180 Kernel::ValueRef resultUntyped = NullPtr< const Lang::Value >( );
181 Kernel::EvalState evalState( Ast::theProgram,
182 Kernel::theGlobalEnvironment,
183 baseDyn,
184 Kernel::ContRef( new Kernel::StoreValueContinuation( & resultUntyped,
185 Kernel::ContRef( new Kernel::ExitContinuation( & done, Ast::theProgram->loc( ) ) ),
186 Ast::theProgram->loc( ) ) ) );
187 while( ! done )
189 Ast::Expression * expr = evalState.expr_;
190 expr->eval( & evalState );
193 catch( const Exceptions::StaticInconsistency & ball )
195 std::cout.flush( );
196 std::cerr << ball.loc( ) << ": " ;
197 ball.display( std::cerr );
198 std::cerr << "There were errors in the preamble. Aborting interactive evaluation." ;
199 abortProcedure( ball.exitCode( ) );
201 catch( const Exceptions::Exception & ball )
203 std::cout.flush( );
204 ball.display( std::cerr );
205 std::cerr << "There were errors in the preamble. Aborting interactive evaluation." ;
206 abortProcedure( ball.exitCode( ) );
209 Ast::theShapesScanner.setInteractive( true ); /* Do this after reading the preamble! */
211 /* Find the prelude environment... */
212 Kernel::Environment * preludeEnv = 0;
213 for( std::list< Kernel::Environment * >::iterator e = Kernel::theEnvironmentList.begin( ); e != Kernel::theEnvironmentList.end( ); ++e )
217 if( (*e)->getParent( ) == Kernel::theGlobalEnvironment )
219 preludeEnv = *e;
220 break;
223 catch( const Exceptions::MiscellaneousRequirement & ball )
225 /* That was the global environment, which doesn't have a parent. Never mind. */
228 if( preludeEnv == 0 )
230 std::cerr << "Internal error: Failed to locate prelude environment." << std::endl ;
231 exit( Interaction::EXIT_INTERNAL_ERROR );
233 Ast::AnalysisEnvironment * preludeAnalysisEnvironment = preludeEnv->newAnalysisEnvironment( Ast::theGlobalAnalysisEnvironment );
235 static Ast::SourceLocation loc( Ast::FileID::build_internal( "{ interactive }" ) );
236 Ast::CodeBracket * initialBracket( new Ast::CodeBracket( loc, new std::list< Ast::Node * >( ) ) );
238 Ast::StateIDSet freeStates;
239 initialBracket->analyze( Ast::theProgram, preludeAnalysisEnvironment, & freeStates );
241 Kernel::Environment * bracketEnv = initialBracket->newEnvironment( preludeEnv, "Interaction" );
242 bracketEnv->initDefine( Lang::THE_NAMESPACE_Shapes_Debug, "db", new Kernel::WarmDebugger( bracketEnv, baseDyn, Kernel::ContRef( NullPtr< Kernel::Continuation >( ) ), 0 ) );
244 int exitCode = Interaction::EXIT_OK;
246 RefCountPtr< Kernel::InteractionContinuation > interactionCont
247 ( new Kernel::InteractionContinuation( preludeAnalysisEnvironment, initialBracket, bracketEnv, Kernel::ContRef( NullPtr< Kernel::Continuation >( ) ), baseDyn, 0, Kernel::NO_INPUT_INPUT_NO,
248 in, out, outputName, splitMode,
249 initialBracket->loc( ) ) );
250 Kernel::PassedDyn interactionDyn( new Kernel::DynamicEnvironment( Kernel::PassedDyn( new Kernel::DynamicEnvironment( baseDyn, "bye", Kernel::ContRef( new Kernel::ExitInteractionContinuation( & Kernel::theInteractionDone, & exitCode, initialBracket->loc( ) ) ) ) ),
251 Lang::CONTINUATION_TOP_REPL_ID, interactionCont ) );
252 interactionCont->setDyn( interactionDyn );
254 Kernel::EvalState evalState( Kernel::theVoidExpression, /* This will invoke the continuation first thing. */
255 Kernel::theGlobalEnvironment, /* Dummy value */
256 baseDyn, /* Dummy value */
257 interactionCont );
259 while( ! Kernel::theInteractionDone )
261 Ast::Expression * expr = evalState.expr_;
262 if( Kernel::theDebugStepInfo.active_ && Kernel::theDebugStepInfo.stop( expr->loc( ) ) )
264 out << "Reached " << expr->loc( ) << "." << std::endl ;
265 evalState.cont_ = Kernel::ContRef( new Kernel::InteractionContinuation( evalState, Kernel::NO_INPUT_INPUT_NO, in, out, outputName, splitMode ) );
266 evalState.expr_ = Kernel::theVoidExpression;
267 Kernel::theDebugStepInfo.active_ = false;
268 continue;
270 if( expr->breakpoint_ != 0 && expr->breakpoint_->enabled_ )
272 if( expr->breakpoint_->ignoreCount_ > 0 )
274 /* Don't break this time, but re-enable breaking in the future. */
275 --(expr->breakpoint_->ignoreCount_);
277 else
279 out << "Stopping at breakpoint " << expr->loc( ) << "." << std::endl ;
280 typedef typeof Kernel::theTemporaryBreakpoints SetType;
281 for( SetType::iterator i = Kernel::theTemporaryBreakpoints.begin( ); i != Kernel::theTemporaryBreakpoints.end( ); ++i )
283 if( (*i)->breakpoint_->createdForTemporaryUse_ )
285 delete (*i)->breakpoint_;
286 (*i)->breakpoint_ = 0;
287 Kernel::theBreakpoints.erase( *i );
289 else
291 (*i)->breakpoint_->enabled_ = (*i)->breakpoint_->persistentEnabled_;
294 Kernel::theTemporaryBreakpoints.clear( );
295 evalState.cont_ = Kernel::ContRef( new Kernel::InteractionContinuation( evalState, Kernel::NO_INPUT_INPUT_NO, in, out, outputName, splitMode ) );
296 evalState.expr_ = Kernel::theVoidExpression;
297 Kernel::theDebugStepInfo.active_ = false;
298 continue;
306 expr->eval( & evalState );
308 catch( const Exceptions::CatchableError & ball )
310 Kernel::ContRef cont = evalState.dyn_->getEscapeContinuation( Lang::CONTINUATION_ID_ERROR, ball.getLoc( ) );
311 cont->takeValue( ball.clone( evalState.cont_ ),
312 & evalState );
314 continue;
316 catch( const Exceptions::StaticInconsistency & ball )
318 out.flush( );
319 out << ball.loc( ) << ": " ;
320 ball.display( out );
322 catch( const Exceptions::Exception & ball )
324 out.flush( );
325 if( Interaction::debugBacktrace )
327 evalState.cont_->backTrace( out );
332 const Exceptions::RuntimeError & rerr = dynamic_cast< const Exceptions::RuntimeError & >( ball );
333 if( rerr.getLoc( ).isUnknown( ) )
335 throw std::bad_cast( ); /* It's not a bad cast, but the cast value is just as little useful as a bad cast. */
337 out << rerr.getLoc( ) << Exceptions::Exception::locsep ;
339 catch( std::bad_cast & bad_cast_ball )
341 out << evalState.cont_->traceLoc( ) << Exceptions::Exception::locsep ;
343 ball.display( out );
345 if( Kernel::interactive_debug )
347 Kernel::InteractionContinuation * iCont = dynamic_cast< Kernel::InteractionContinuation * >( evalState.cont_.getPtr( ) );
348 if( iCont != 0 && iCont->reusable( evalState ) )
350 /* We don't create a new interactive continuation if the active continuation is already an interactive continuation.
351 * For instance, failing to set a breakpoint is not something that's interesting to debug in itself.
353 out << "Reusing interactive continuation." << std::endl ;
355 else if( evalState.expr_ != 0 )
357 evalState.cont_ = Kernel::ContRef( new Kernel::InteractionContinuation( evalState, Kernel::NO_INPUT_INPUT_NO, in, out, outputName, splitMode ) );
359 else
361 /* We interpret this situation as a failure to explicitly apply a continuation.
362 * See ContinueDynamicECFunction::call .
364 evalState.cont_ = Kernel::ContRef( new Kernel::InteractionContinuation
365 ( preludeAnalysisEnvironment, initialBracket, bracketEnv, evalState.cont_,
366 Kernel::PassedDyn( new Kernel::DynamicEnvironment( baseDyn, "resume", evalState.cont_ ) ),
368 Kernel::NO_INPUT_INPUT_NO,
369 in, out, outputName, splitMode,
370 initialBracket->loc( ) ) );
373 else
375 evalState.cont_ = interactionCont;
377 Kernel::theDebugStepInfo.active_ = false;
378 evalState.expr_ = Kernel::theVoidExpression;
381 /* Someone ended the input stream or invoked the exit continuation.
382 * For now, we circumvent the normal termination procedures in <main> by exiting here,
383 * which is similar to stopping the program by pressing ctrl-c, which is probably what
384 * most people will do anyway.
386 exit( exitCode );
390 Interaction::InteractionFormats::InteractionFormats( )
391 : prompt_( "[%!#!!3R] " ),
392 show_( "%!#!!3R ⇒ " ),
393 file_( "#File: " ),
394 bye_( "<<EOF>>\n" )
397 void
398 Interaction::InteractionFormats::setPrompt( const char * format )
400 prompt_ = format;
403 void
404 Interaction::InteractionFormats::setShow( const char * format )
406 show_ = format;
409 void
410 Interaction::InteractionFormats::setFile( const char * format )
412 file_ = format;
415 void
416 Interaction::InteractionFormats::setBye( const char * format )
418 bye_ = format;
421 void
422 Interaction::InteractionFormats::formatPrompt( std::ostream & os, size_t inputNo ) const
424 writePrompt( os, prompt_, inputNo );
427 void
428 Interaction::InteractionFormats::formatShow( std::ostream & os, size_t inputNo ) const
430 writePrompt( os, show_, inputNo );
433 void
434 Interaction::InteractionFormats::formatFile( std::ostream & os, size_t inputNo ) const
436 writePrompt( os, file_, inputNo );
439 void
440 Interaction::InteractionFormats::formatBye( std::ostream & os, size_t inputNo ) const
442 writePrompt( os, bye_, inputNo );
445 void
446 Interaction::InteractionFormats::writePrompt( std::ostream & os, const char * format, size_t inputNo ) const
448 for( const char * src = format; *src != '\0'; ++src )
450 if( *src == '%' )
452 ++src;
453 const char sep = *src;
454 ++src;
455 std::ostringstream noStr;
456 while( *src != sep )
458 if( *src == '\0' )
460 std::cerr << "Bad interactive prompt format string (expected second '" << sep << "'): " << format << std::endl ;
461 exit( Interaction::EXIT_INVOCATION_ERROR );
463 if( *src == '\\' )
465 ++src;
466 writeEscape( noStr, *src );
468 else
470 noStr << *src ;
472 ++src;
474 ++src;
475 noStr << inputNo ;
476 while( *src != sep )
478 if( *src == '\0' )
480 std::cerr << "Bad interactive prompt format string (expected third '" << sep << "'): " << format << std::endl ;
481 exit( Interaction::EXIT_INVOCATION_ERROR );
483 if( *src == '\\' )
485 ++src;
486 writeEscape( noStr, *src );
488 else
490 noStr << *src ;
492 ++src;
494 ++src;
495 char * endp;
496 int width = strtol( src, & endp, 10 );
497 if( endp == src )
499 width = -1;
501 else if( width < 0 || width > 10 )
503 std::cerr << "Bad interactive prompt format string (the width " << width << " is out of the range [0,10]): " << format << std::endl ;
504 exit( Interaction::EXIT_INVOCATION_ERROR );
507 src = endp;
508 switch( *src )
510 case 'L':
511 os.setf(std::ios::left);
512 break;
513 case 'R':
514 os.setf(std::ios::right);
515 break;
516 default:
517 std::cerr << "Bad interactive prompt format string (expected 'L' or 'R' after '%'): " << format << std::endl ;
518 exit( Interaction::EXIT_INVOCATION_ERROR );
520 if( width >= 0 )
522 os << std::setw(width) ;
524 os << noStr.str( ) ;
526 else if( *src == '\\' )
528 ++src;
529 writeEscape( os, *src );
531 else
533 os << *src ;
538 void
539 Interaction::InteractionFormats::writeEscape( std::ostream & os, char c ) const
541 switch( c )
543 case '\\':
544 os << '\\';
545 break;
546 case '%':
547 os << '%';
548 break;
549 case 'a':
550 os << '\a';
551 break;
552 case 'n':
553 os << '\n';
554 break;
555 case 't':
556 os << '\t';
557 break;
558 default:
559 os << '\\' << c ;
563 Ast::VoidExpression::VoidExpression( const Ast::SourceLocation & loc )
564 : Ast::Expression( loc )
567 Ast::VoidExpression::~VoidExpression( )
570 void
571 Ast::VoidExpression::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
573 /* Nothing to do! */
576 void
577 Ast::VoidExpression::eval( Kernel::EvalState * evalState ) const
579 Kernel::ContRef cont = evalState->cont_;
580 cont->takeValue( Lang::THE_VOID,
581 evalState );
584 Kernel::InteractionContinuation::InteractionContinuation( Ast::AnalysisEnvironment * parentAnalysisEnv, Ast::CodeBracket * bracket, Kernel::Environment * env, Kernel::ContRef resume, const Kernel::PassedDyn & dyn, Ast::Expression * breakExpr, int result_inputNo, std::istream & is, std::ostream & os, const std::string & outputName, SplitMode splitMode, const Ast::SourceLocation & traceLoc )
585 : Kernel::Continuation( traceLoc ), parentAnalysisEnv_( parentAnalysisEnv ), bracket_( bracket ), env_( env ), resume_( resume ), dyn_( dyn ), breakExpr_( breakExpr ), result_inputNo_( result_inputNo ), is_( is ), os_( os ), outputName_( outputName ), splitMode_( splitMode )
588 Ast::SourceLocation debug_loc( Ast::FileID::build_internal( "{ debug }" ) );
590 Kernel::InteractionContinuation::InteractionContinuation( Kernel::EvalState & evalState, int result_inputNo, std::istream & is, std::ostream & os, const std::string & outputName, SplitMode splitMode )
591 : Kernel::Continuation( evalState.expr_->loc( ) ),
592 parentAnalysisEnv_( evalState.expr_->getEnv( ) ),
593 bracket_( new Ast::CodeBracket( debug_loc, new std::list< Ast::Node * >( ) ) ),
594 env_( bracket_->newEnvironment( evalState.env_, "Debug" ) ),
595 resume_( evalState.cont_ ),
596 dyn_( new Kernel::DynamicEnvironment( evalState.dyn_, "resume", resume_ ) ),
597 breakExpr_( evalState.expr_ ),
598 result_inputNo_( result_inputNo ),
599 is_( is ), os_( os ), outputName_( outputName ), splitMode_( splitMode )
602 Ast::StateIDSet freeStates;
603 bracket_->analyze( evalState.expr_, parentAnalysisEnv_, & freeStates );
605 env_->initDefine( Lang::THE_NAMESPACE_Shapes_Debug, "db", new Kernel::WarmDebugger( env_, dyn_, resume_, breakExpr_ ) );
606 env_->initDefineHandle( Ast::PlacedIdentifier( Lang::THE_NAMESPACE_Shapes_Debug, "expr" ), Kernel::VariableHandle( new Kernel::Variable( new Kernel::Thunk( evalState.env_, evalState.dyn_, evalState.expr_ ) ) ) );
609 Kernel::InteractionContinuation::~InteractionContinuation( )
612 RefCountPtr< Kernel::InteractionContinuation >
613 Kernel::InteractionContinuation::cloneWithNewContinuation( Kernel::ContRef resume, Kernel::WarmDebugger * state )
615 state->env_ = env_;
616 state->dyn_ = Kernel::PassedDyn( new Kernel::DynamicEnvironment( dyn_, "resume", resume ) );
617 state->breakExpr_ = breakExpr_;
618 state->resume_ = resume;
619 return RefCountPtr< Kernel::InteractionContinuation >
620 ( new Kernel::InteractionContinuation( parentAnalysisEnv_, bracket_, state->env_, resume,
621 state->dyn_,
622 state->breakExpr_,
623 NO_INPUT_INPUT_NO,
624 is_, os_, outputName_, splitMode_,
625 traceLoc_ ) );
628 void
629 Kernel::InteractionContinuation::setDyn( const Kernel::PassedDyn & dyn )
631 dyn_ = dyn;
634 bool
635 Kernel::InteractionContinuation::reusable( Kernel::EvalState & evalState ) const
637 return env_ == evalState.env_ && dyn_ == evalState.dyn_;
640 void
641 Kernel::InteractionContinuation::takeValue( const RefCountPtr< const Lang::Value > & val, Kernel::EvalState * evalState, bool dummy ) const
643 Kernel::theDebugStepInfo.active_ = false;
644 showValue( val );
646 size_t debugDepth = 0;
648 Kernel::ContRef tmp = evalState->cont_;
649 while( tmp != NullPtr< Kernel::Continuation >( ) )
651 RefCountPtr< Kernel::InteractionContinuation > inter = tmp.down_cast< Kernel::InteractionContinuation >( );
652 if( inter != NullPtr< Kernel::InteractionContinuation >( ) )
654 tmp = inter->resume_;
655 if( tmp != NullPtr< Kernel::Continuation >( ) )
657 ++debugDepth;
660 else
662 tmp = tmp->up( );
667 while( true )
669 /* As long as we fail to return, we ask for new input... */
670 if( debugDepth > 0 )
672 os_ << "[" ;
673 for( size_t i = 0; i < debugDepth; ++i )
675 if( i > 0 )
677 os_ << "," ;
679 os_ << "debug" ;
681 os_ << "]" ;
683 const Ast::FileID * fileID = Ast::FileID::build_fresh_inMemory( );
684 int interactive_inputNo = fileID->inMemoryIndex( );
685 std::ostringstream inputBuf;
686 while( true )
688 interactionFormats.formatPrompt( os_, interactive_inputNo );
689 std::string line;
690 std::getline( is_, line );
691 if( is_.eof( ) )
693 interactionFormats.formatBye( os_, interactive_inputNo );
694 Kernel::theInteractionDone = true;
695 return;
697 if( line.length( ) > 1 && line[ line.length( ) - 1] == ' ' )
699 inputBuf << line.substr( 0, line.length( ) - 1 ) << '\n' ;
701 else
703 inputBuf << line ;
704 break;
707 std::string line = inputBuf.str( );
708 if( line.length( ) > 1 && line[0] == ':' )
710 line = "#db.[" + line.substr(1) + "]";
713 const_cast< Ast::FileID * >( fileID )->setMem( strdup( line.c_str( ) ) );
714 std::istringstream inLine( line + "\n" );
715 Ast::theShapesScanner.queueStream( & inLine, fileID );
716 Ast::theShapesScanner.start( );
719 shapesparse( );
720 interactive_history.push_back( Ast::theInteractiveInput );
721 Ast::CodeBracket * extension = new Ast::CodeBracket( bracket_->loc( ), Ast::theInteractiveInput, bracket_ );
723 Ast::StateIDSet freeStates;
724 extension->analyze( Ast::theProgram, parentAnalysisEnv_, & freeStates );
726 if( ! Ast::theAnalysisErrorsList.empty( ) )
728 std::cout.flush( );
729 typedef typeof Ast::theAnalysisErrorsList ListType;
730 for( ListType::const_iterator i = Ast::theAnalysisErrorsList.begin( ); i != Ast::theAnalysisErrorsList.end( ); ++i )
733 typedef const Exceptions::StaticInconsistency ErrorType;
734 ErrorType * err = dynamic_cast< ErrorType * >( *i );
735 if( err != 0 )
737 std::cerr << err->loc( ) << ": " ;
738 err->display( std::cerr );
739 continue;
742 std::cerr << "(Bad exception type)" << ": " ;
743 (*i)->display( std::cerr );
745 Ast::theAnalysisErrorsList.clear( );
747 else
751 // evalState->env_ = env_; /* Not needed since extension->eval handles this. */
752 evalState->dyn_ = dyn_;
753 /* For the continuation, we make a copy of ourselves. */
754 evalState->cont_ = Kernel::ContRef( new Kernel::InteractionContinuation( parentAnalysisEnv_, bracket_, env_, resume_, dyn_, breakExpr_,
755 interactive_inputNo,
756 is_, os_, outputName_, splitMode_,
757 traceLoc_ ) );
758 extension->eval( evalState, env_ ); /* Note that this is a special kind of eval that extends the given environment. */
760 catch( const Exceptions::CatchableError & ball )
762 Kernel::ContRef cont = evalState->dyn_->getEscapeContinuation( Lang::CONTINUATION_ID_ERROR, ball.getLoc( ) );
763 cont->takeValue( ball.clone( evalState->cont_ ),
764 evalState );
766 return;
769 catch( const Exceptions::StaticInconsistency & ball )
771 os_.flush( );
772 os_ << ball.loc( ) << ": " ;
773 ball.display( os_ );
775 catch( const Exceptions::Exception & ball )
777 os_.flush( );
778 ball.display( os_ );
783 Kernel::ContRef
784 Kernel::InteractionContinuation::up( ) const
786 return Kernel::ContRef( NullPtr< Kernel::Continuation >( ) );
789 RefCountPtr< const char >
790 Kernel::InteractionContinuation::description( ) const
792 if( resume_ != NullPtr< Kernel::Continuation >( ) )
794 return strrefdup( "interaction with resume" );
796 else
798 return strrefdup( "interaction" );
802 void
803 Kernel::InteractionContinuation::gcMark( Kernel::GCMarkedSet & marked )
806 void
807 Kernel::InteractionContinuation::showValue( const RefCountPtr< const Lang::Value > & resultUntyped ) const
811 typedef const Lang::Void ResType;
812 RefCountPtr< ResType > result = Helpers::try_cast_CoreArgument< ResType >( resultUntyped );
813 /* Just be quiet. */
814 return;
816 catch( const NonLocalExit::NotThisType & ball )
818 /* Wrong type; never mind!.. but see below!
823 if( Interaction::blankMode ){
824 /* Skip special handling of Lang::Drawable2D when running the compiler in blank mode. */
825 throw NonLocalExit::NotThisType( );
827 typedef const Lang::Drawable2D ResType;
828 RefCountPtr< ResType > result = Helpers::try_cast_CoreArgument< ResType >( resultUntyped );
829 Kernel::WarmCatalog catalog;
830 catalog.tackOnPage( dyn_, result, Ast::THE_UNKNOWN_LOCATION );
831 Kernel::WarmCatalog::ShipoutList documents;
832 catalog.shipout( splitMode_ != SPLIT_NO, & documents );
833 std::ofstream oFile;
834 std::string filename;
835 switch( splitMode_ )
837 case SPLIT_NO:
839 noSplitOpen( & oFile, outputName_ );
840 filename = outputName_;
842 break;
843 case SPLIT_FLAT:
845 filename = splitOpen( & oFile, outputName_, "-", result_inputNo_ );
847 break;
848 case SPLIT_DIR:
850 filename = splitOpen( & oFile, outputName_, "/", result_inputNo_ );
852 break;
854 documents.front( ).writeFile( oFile, Kernel::the_PDF_version );
855 oFile.close( );
856 interactionFormats.formatFile( os_, result_inputNo_ ) ;
857 os_ << filename << std::endl ;
858 previewOptions.preview( filename );
859 if( previewOptions.xpdfAction == Interaction::PreviewOptions::XPDF_RAISE && splitMode_ == SPLIT_NO )
861 /* It is disturbing to raise the window more than the first time. */
862 previewOptions.xpdfAction = Interaction::PreviewOptions::XPDF_RELOAD;
864 return;
866 catch( const NonLocalExit::NotThisType & ball )
868 /* Wrong type; never mind!.. but see below!
872 /* This is the default action taken in case non of the types above matched. */
873 interactionFormats.formatShow( os_, result_inputNo_ ) ;
874 resultUntyped->show( os_ );
875 os_ << std::endl ;
878 Kernel::ExitInteractionContinuation::ExitInteractionContinuation( bool * done, int * exitCode, const Ast::SourceLocation & traceLoc )
879 : Kernel::Continuation( traceLoc ), done_( done ), exitCode_( exitCode )
882 Kernel::ExitInteractionContinuation::~ExitInteractionContinuation( )
885 void
886 Kernel::ExitInteractionContinuation::takeValue( const RefCountPtr< const Lang::Value > & val, Kernel::EvalState * evalState, bool dummy ) const
890 typedef const Lang::Symbol ArgType;
891 RefCountPtr< ArgType > key = Helpers::try_cast_CoreArgument< ArgType >( val );
893 static Lang::Symbol CODE_OK( "OK" );
894 static Lang::Symbol CODE_GENERIC_ERROR( "GenericError" );
895 static Lang::Symbol CODE_USER_DETECTED_ERROR( "UserDetectedError" );
896 if( *key == CODE_OK )
898 *exitCode_ = Interaction::EXIT_OK;
900 else if( *key == CODE_GENERIC_ERROR )
902 *exitCode_ = Interaction::EXIT_GENERIC_ERROR;
904 else if( *key == CODE_USER_DETECTED_ERROR )
906 *exitCode_ = Interaction::EXIT_USER_DETECTED_ERROR;
908 else
910 std::ostringstream oss;
911 oss << "Valid exit codes symbols are { "
912 << CODE_OK.name( ).getPtr( ) << ", "
913 << CODE_GENERIC_ERROR.name( ).getPtr( ) << ", "
914 << CODE_USER_DETECTED_ERROR.name( ).getPtr( )
915 << " }." ;
916 throw Exceptions::OutOfRange( traceLoc_, strrefdup( oss ) );
919 *done_ = true;
920 return;
922 catch( const NonLocalExit::NotThisType & ball )
924 /* Wrong type; never mind!.. but see below!
930 typedef const Lang::Integer ArgType;
931 *exitCode_ = Helpers::try_cast_CoreArgument< ArgType >( val )->val_;
932 if( -99 <= *exitCode_ || *exitCode_ <= 99 )
934 throw Exceptions::OutOfRange( traceLoc_, "Literal integer exit codes must be in the range [ -99, 99 ]. Documented values in the reserved range are accessed via symbols." );
936 *done_ = true;
937 return;
939 catch( const NonLocalExit::NotThisType & ball )
941 /* Wrong type; never mind!.. but see below!
945 throw Exceptions::ContinuationTypeMismatch( this, val->getTypeName( ), Helpers::typeSetString( Lang::Symbol::staticTypeName( ), Lang::Integer::staticTypeName( ) ) );
948 Kernel::ContRef
949 Kernel::ExitInteractionContinuation::up( ) const
951 return Kernel::ContRef( NullPtr< Kernel::Continuation >( ) );
954 RefCountPtr< const char >
955 Kernel::ExitInteractionContinuation::description( ) const
957 return strrefdup( "exit (non-forcing)" );
960 void
961 Kernel::ExitInteractionContinuation::gcMark( Kernel::GCMarkedSet & marked )
965 namespace Shapes
967 namespace Kernel
970 template< class T >
971 class Mutator_resume : public Lang::CoreMutator
973 public:
974 Mutator_resume( const char * name )
975 : CoreMutator( name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), false ) )
977 formals_->appendEvaluatedCoreFormal( "result", Kernel::THE_VOID_VARIABLE );
979 virtual void
980 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
982 args.applyDefaults( callLoc );
984 typedef T StateType;
985 StateType * state = Helpers::mutator_cast_self< StateType >( args.getMutatorSelf( ) );
986 if( state->resume_ == NullPtr< typeof *(state->resume_) >( ) )
988 throw Exceptions::CoreRequirement( "The top level debug state has no continuation to resume.", new Interaction::MutatorLocation( state, name_ ), callLoc );
991 if( args.getHandle( 0 ) == Kernel::THE_VOID_VARIABLE && state->breakExpr_ != 0 )
993 /* The user did not provide an argument and there is a default expression to resume with, which should be set to where evaluation was interrupted.
994 * Since the reason the evaluation was interrupted may be the presence of a breakpoint, we must avoid ending up breaking at the same expression again.
995 * Calling the <eval> method from here might solve the problem, but the number of places where this method is called should really be kept to a
996 * minimum. Hence, using the <ignoreCount_> is preferred.
998 if( state->breakExpr_->breakpoint_ != 0 &&
999 state->breakExpr_->breakpoint_->enabled_ )
1001 ++(state->breakExpr_->breakpoint_->ignoreCount_);
1003 evalState->cont_ = state->resume_;
1004 evalState->env_ = state->env_->getParent( );
1005 evalState->dyn_ = state->dyn_;
1006 evalState->expr_ = state->breakExpr_;
1008 else
1010 /* Invoke the escape continuation exactly as in ContinueDynamicECFunction::call.
1012 evalState->cont_ = state->resume_;
1013 evalState->expr_ = 0;
1014 state->resume_->takeHandle( args.getHandle( 0 ),
1015 evalState );
1020 template< class T >
1021 class Mutator_top_repl : public Lang::CoreMutator
1023 public:
1024 Mutator_top_repl( const char * name )
1025 : CoreMutator( name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), false ) )
1027 formals_->appendEvaluatedCoreFormal( "result", Kernel::THE_VOID_VARIABLE );
1029 virtual void
1030 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1032 args.applyDefaults( callLoc );
1034 // typedef T StateType;
1035 // StateType * state = Helpers::mutator_cast_self< StateType >( args.getMutatorSelf( ) );
1037 /* Invoke the escape continuation exactly as in ContinueDynamicECFunction::call.
1039 Kernel::ContRef cont = evalState->dyn_->getEscapeContinuation( Lang::CONTINUATION_TOP_REPL_ID, callLoc );
1040 evalState->cont_ = cont;
1041 evalState->expr_ = 0;
1042 cont->takeHandle( args.getHandle( 0 ),
1043 evalState );
1047 template< class T >
1048 class Mutator_cont : public Lang::CoreMutator
1050 public:
1051 typedef enum { UP, EXIT_DEBUG } Kind;
1052 private:
1053 Kind kind_;
1054 public:
1055 Mutator_cont( const char * name, Kind kind )
1056 : CoreMutator( name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), false ) ),
1057 kind_( kind )
1059 formals_->appendEvaluatedCoreFormal( "count", Helpers::newValHandle( new Lang::Integer( 1 ) ) );
1061 virtual void
1062 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1064 args.applyDefaults( callLoc );
1066 /* While activating an already existing interactive continuation allows an old WarmDebugger to be reused as is,
1067 * changing the resume continuation within the current interactive context requires the current WarmDebugger to
1068 * be modified. Hence, to not modify any other state than that that calls this method, the UP mode can not be
1069 * used to reach continuations beyond the next interactive continuation.
1072 /* Note that we don't start counting in state->resume_, but search an interactive continuation from evalState->cont_.
1073 * The reason is that this provides a unified way of obtaining an interactive continuation _below_ the new resume continuation.
1074 * In most cases, this will be exactly what one expects, but in rare cases this behavior may seem strange.
1077 typedef T StateType;
1078 StateType * state = Helpers::mutator_cast_self< StateType >( args.getMutatorSelf( ) );
1080 size_t argsi = 0;
1081 typedef const Lang::Integer ArgType;
1082 size_t argsi_count = argsi;
1083 int count = Helpers::down_cast_MutatorArgument< ArgType >( state, name_, args, argsi_count, callLoc )->val_;
1084 if( count <= 0 )
1086 throw Exceptions::CoreOutOfRange( new Interaction::MutatorLocation( state, name_ ), args, argsi_count, "The count must be positive." );
1089 Kernel::ContRef tmp = evalState->cont_;
1090 RefCountPtr< Kernel::InteractionContinuation > bottom_interactive = tmp.down_cast< Kernel::InteractionContinuation >( );
1091 while( bottom_interactive == NullPtr< typeof *bottom_interactive >( ) )
1093 if( tmp == NullPtr< Kernel::Continuation >( ) )
1095 throw Exceptions::CoreOutOfRange( new Interaction::MutatorLocation( state, name_ ), args, argsi_count, "There is no interactive continuation in the backtrace to start counting from." );
1097 tmp = tmp->up( );
1098 bottom_interactive = tmp.down_cast< Kernel::InteractionContinuation >( );
1100 tmp = bottom_interactive->resume( );
1102 while( count > 0 )
1104 if( tmp == NullPtr< Kernel::Continuation >( ) )
1106 throw Exceptions::CoreOutOfRange( new Interaction::MutatorLocation( state, name_ ), args, argsi_count, "The count exceeds the current depth." );
1108 RefCountPtr< Kernel::InteractionContinuation > inter = tmp.down_cast< Kernel::InteractionContinuation >( );
1109 if( inter != NullPtr< typeof *inter >( ) )
1111 if( kind_ == UP )
1113 throw Exceptions::CoreOutOfRange( new Interaction::MutatorLocation( state, name_ ), args, argsi_count, "The count exceeds depth down to the next interactive continuations." );
1115 bottom_interactive = inter;
1116 if( count == 1 )
1118 /* The continuation will be reused, which corresponds to one decrement of <count>. */
1119 break;
1121 tmp = bottom_interactive->resume( );
1122 --count;
1124 else
1126 tmp = tmp->up( );
1127 if( kind_ == UP )
1129 --count;
1133 if( tmp == NullPtr< Kernel::Continuation >( ) )
1135 throw Exceptions::CoreOutOfRange( new Interaction::MutatorLocation( state, name_ ), args, argsi_count, "The count exceeds the current depth." );
1138 /* If tmp is an interactive continuation, we reuse it, otherwise we set up a new one.
1140 if( tmp.down_cast< Kernel::InteractionContinuation >( ) != NullPtr< Kernel::InteractionContinuation >( ) )
1142 evalState->cont_ = tmp;
1144 else
1146 if( kind_ != UP )
1148 throw Exceptions::InternalError( "Mutator_cont: Expected kind_ to be UP when unable to reuse continuation." );
1150 RefCountPtr< Kernel::InteractionContinuation > inter = bottom_interactive->cloneWithNewContinuation( tmp, state );
1151 evalState->cont_ = inter;
1153 evalState->expr_ = Kernel::theVoidExpression;
1157 template< class T >
1158 class Mutator_step : public Lang::CoreMutator
1160 Kernel::DebugStepInfo::StepMode mode_;
1161 public:
1162 Mutator_step( const char * name, Kernel::DebugStepInfo::StepMode mode )
1163 : CoreMutator( name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), true ) ),
1164 mode_( mode )
1166 formals_->appendEvaluatedCoreFormal( "count", Helpers::newValHandle( new Lang::Integer( 1 ) ) );
1168 virtual void
1169 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1171 args.applyDefaults( callLoc );
1173 typedef T StateType;
1174 StateType * state = Helpers::mutator_cast_self< StateType >( args.getMutatorSelf( ) );
1175 if( state->breakExpr_ == 0 )
1177 throw Exceptions::CoreRequirement( "Currently not at any source location, so source stepping is not possible.", new Interaction::MutatorLocation( state, name_ ), callLoc );
1180 size_t argsi = 0;
1181 typedef const Lang::Integer ArgType;
1182 int count = Helpers::down_cast_MutatorArgument< ArgType >( state, name_, args, argsi, callLoc )->val_;
1183 if( count < 1 )
1185 throw Exceptions::CoreOutOfRange( new Interaction::MutatorLocation( state, name_ ), args, argsi, "The count must be at least 1." );
1188 Kernel::theDebugStepInfo.active_ = true;
1189 Kernel::theDebugStepInfo.mode_ = mode_;
1190 Kernel::theDebugStepInfo.refLoc_ = state->breakExpr_->loc( );
1191 Kernel::theDebugStepInfo.count_ = static_cast< size_t >( count ) + ( ( mode_ == Kernel::DebugStepInfo::EXPR ) ? 1 : 0 );
1193 /* The rest is more or less the same as in Mutator_resume. */
1194 if( state->breakExpr_->breakpoint_ != 0 &&
1195 state->breakExpr_->breakpoint_->enabled_ )
1197 ++(state->breakExpr_->breakpoint_->ignoreCount_);
1199 evalState->cont_ = state->resume_;
1200 evalState->env_ = state->env_->getParent( );
1201 evalState->dyn_ = state->dyn_;
1202 evalState->expr_ = state->breakExpr_;
1206 template< class T >
1207 class Mutator_step_to_temporary : public Lang::CoreMutator
1209 public:
1210 typedef enum { CHILD, SIBLING } Destination;
1211 private:
1212 Destination destination_;
1213 public:
1214 Mutator_step_to_temporary( const char * name, Destination destination )
1215 : CoreMutator( name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), true ) ),
1216 destination_( destination )
1218 virtual void
1219 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1221 args.applyDefaults( callLoc );
1223 typedef T StateType;
1224 StateType * state = Helpers::mutator_cast_self< StateType >( args.getMutatorSelf( ) );
1225 if( state->breakExpr_ == 0 )
1227 throw Exceptions::CoreRequirement( "Currently not at any source location, so source stepping is not possible.", new Interaction::MutatorLocation( state, name_ ), callLoc );
1230 /* Now, depending on destination_, temporary breakpoints are set.
1231 * We don't touch the ignore count here, which may or may not be what the user expects, but gives the user a way to avoid stopping in expressions
1232 * of little/no interest to inspect. Obvious alternatives are to clear the ignore count for temporary breakpoints, or to just clear the ignore count temporarily.
1234 size_t count = 0; /* Count number of expression where we set a temporary breakpoint. */
1236 switch( destination_ )
1238 case CHILD:
1240 Ast::Node::ChildrenType & exprs = state->breakExpr_->children( );
1241 for( Ast::Node::ChildrenType::iterator i = exprs.begin( ); i != exprs.end( ); ++i )
1243 Ast::Expression * expr = dynamic_cast< Ast::Expression * >( *i );
1244 if( expr == 0 )
1246 continue;
1248 ++count;
1249 if( expr->breakpoint_ == 0 )
1251 expr->breakpoint_ = new Kernel::BreakpointInfo( );
1252 expr->breakpoint_->createdForTemporaryUse_ = true;
1253 Kernel::theBreakpoints.insert( expr );
1255 expr->breakpoint_->persistentEnabled_ = expr->breakpoint_->enabled_;
1256 expr->breakpoint_->enabled_ = true;
1257 Kernel::theTemporaryBreakpoints.insert( expr );
1260 break;
1261 case SIBLING:
1263 Ast::Node * parent = state->breakExpr_->parent( );
1264 if( parent == 0 )
1266 throw Exceptions::CoreRequirement( "Unable to locate siblings since there is no parent here.", new Interaction::MutatorLocation( state, name_ ), callLoc );
1268 Ast::Node::ChildrenType & exprs = parent->children( );
1269 for( Ast::Node::ChildrenType::iterator i = exprs.begin( ); i != exprs.end( ); ++i )
1271 Ast::Expression * expr = dynamic_cast< Ast::Expression * >( *i );
1272 if( expr == 0 || expr == state->breakExpr_ )
1274 continue;
1276 ++count;
1277 if( expr->breakpoint_ == 0 )
1279 expr->breakpoint_ = new Kernel::BreakpointInfo( );
1280 expr->breakpoint_->createdForTemporaryUse_ = true;
1281 Kernel::theBreakpoints.insert( expr );
1283 expr->breakpoint_->persistentEnabled_ = expr->breakpoint_->enabled_;
1284 expr->breakpoint_->enabled_ = true;
1285 Kernel::theTemporaryBreakpoints.insert( expr );
1288 break;
1291 if( count == 0 )
1293 throw Exceptions::CoreRequirement( "No temporary breakpoints were set. Not resuming evaluation.", new Interaction::MutatorLocation( state, name_ ), callLoc );
1296 /* The rest is more or less the same as in Mutator_resume. */
1297 if( state->breakExpr_->breakpoint_ != 0 &&
1298 state->breakExpr_->breakpoint_->enabled_ )
1300 ++(state->breakExpr_->breakpoint_->ignoreCount_);
1302 evalState->cont_ = state->resume_;
1303 evalState->env_ = state->env_->getParent( );
1304 evalState->dyn_ = state->dyn_;
1305 evalState->expr_ = state->breakExpr_;
1309 template< class T >
1310 class Mutator_backtrace : public Lang::CoreMutator
1312 public:
1313 Mutator_backtrace( const char * name )
1314 : CoreMutator( name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), true ) )
1317 virtual void
1318 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1320 args.applyDefaults( callLoc );
1322 typedef T StateType;
1323 StateType * state = Helpers::mutator_cast_self< StateType >( args.getMutatorSelf( ) );
1325 std::ostringstream oss;
1327 typedef std::list< std::pair< const Kernel::Continuation *, RefCountPtr< const char > > > ListType;
1328 ListType trace;
1329 size_t debugDepth = 0;
1330 trace.push_front( ListType::value_type( 0, strrefdup( "==( bottom resume )==" ) ) );
1331 const Kernel::Continuation * tmp = state->resume_.getPtr( );
1332 while( tmp != NullPtr< Kernel::Continuation >( ) )
1334 trace.push_front( ListType::value_type( tmp, tmp->description( ) ) );
1335 const Kernel::InteractionContinuation * inter = dynamic_cast< const Kernel::InteractionContinuation * >( tmp );
1336 if( inter != 0 )
1338 tmp = inter->resume( ).getPtr( );
1339 if( tmp != 0 )
1341 trace.push_front( ListType::value_type( 0, strrefdup( "--( next resume )--" ) ) );
1342 ++debugDepth;
1345 else
1347 tmp = tmp->up( ).getPtr( );
1350 trace.push_front( ListType::value_type( 0, strrefdup( "==( top )==" ) ) );
1352 oss << std::endl ; /* Ensure we start on a new line. */
1353 ListType::const_iterator i = trace.begin( );
1354 for( ; i != trace.end( ); ++i )
1356 if( i->first == 0 )
1358 oss << i->second << std::endl ;
1360 else
1362 oss << " " << i->first->traceLoc( ) << "\t" << i->second << std::endl ;
1367 Kernel::ContRef cont = evalState->cont_;
1368 cont->takeValue( Kernel::ValueRef( new Lang::String( strrefdup( oss ) ) ),
1369 evalState );
1373 template< class T >
1374 class Mutator_printEnv : public Lang::CoreMutator
1376 public:
1377 Mutator_printEnv( const char * name )
1378 : CoreMutator( name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), true ) )
1381 virtual void
1382 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1384 args.applyDefaults( callLoc );
1386 typedef T StateType;
1387 StateType * state = Helpers::mutator_cast_self< StateType >( args.getMutatorSelf( ) );
1389 std::ostringstream oss;
1390 oss << std::endl ; /* Ensure we start on a new line. */
1391 state->env_->print( oss );
1393 Kernel::ContRef cont = evalState->cont_;
1394 cont->takeValue( Kernel::ValueRef( new Lang::String( strrefdup( oss ) ) ),
1395 evalState );
1399 template< class T >
1400 class Mutator_printDyn : public Lang::CoreMutator
1402 public:
1403 Mutator_printDyn( const char * name )
1404 : CoreMutator( name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), true ) )
1407 virtual void
1408 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1410 args.applyDefaults( callLoc );
1412 typedef T StateType;
1413 StateType * state = Helpers::mutator_cast_self< StateType >( args.getMutatorSelf( ) );
1415 std::ostringstream oss;
1416 oss << std::endl ; /* Ensure we start on a new line. */
1417 state->dyn_->print( oss );
1419 Kernel::ContRef cont = evalState->cont_;
1420 cont->takeValue( Kernel::ValueRef( new Lang::String( strrefdup( oss ) ) ),
1421 evalState );
1425 template< class T >
1426 class Mutator_printBreakpoints : public Lang::CoreMutator
1428 public:
1429 Mutator_printBreakpoints( const char * name )
1430 : CoreMutator( name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), true ) )
1433 virtual void
1434 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1436 args.applyDefaults( callLoc );
1438 // typedef T StateType;
1439 // StateType * state = Helpers::mutator_cast_self< StateType >( args.getMutatorSelf( ) );
1441 std::ostringstream oss;
1442 oss << std::endl ; /* Ensure we start on a new line. */
1443 typedef typeof Kernel::theBreakpoints ListType;
1444 size_t index = 1;
1445 for( ListType::const_iterator i = Kernel::theBreakpoints.begin( ); i != Kernel::theBreakpoints.end( ); ++i, ++index )
1447 oss << std::setw(3) << index << ( ( (*i)->breakpoint_->enabled_ ) ? " (on )" : " (off)" ) ;
1448 if( (*i)->breakpoint_->ignoreCount_ > 0 )
1450 oss << " (ignore " << (*i)->breakpoint_->ignoreCount_ << " times)" ;
1452 oss << ": " << (*i)->loc( ) << std::endl ;
1455 Kernel::ContRef cont = evalState->cont_;
1456 cont->takeValue( Kernel::ValueRef( new Lang::String( strrefdup( oss ) ) ),
1457 evalState );
1461 template< class T >
1462 class Mutator_clearBreak : public Lang::CoreMutator
1464 public:
1465 Mutator_clearBreak( const char * name )
1466 : CoreMutator( name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), true ) )
1468 formals_->appendEvaluatedCoreFormal( "index", Helpers::newValHandle( new Lang::Integer( 0 ) ) );
1470 virtual void
1471 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1473 args.applyDefaults( callLoc );
1475 typedef T StateType;
1476 StateType * state = Helpers::mutator_cast_self< StateType >( args.getMutatorSelf( ) );
1478 size_t argsi = 0;
1479 typedef const Lang::Integer ArgType;
1480 int index = Helpers::down_cast_MutatorArgument< ArgType >( state, name_, args, argsi, callLoc )->val_;
1481 if( index == 0 )
1483 if( state->breakExpr_ == 0 )
1485 throw Exceptions::CoreOutOfRange( new Interaction::MutatorLocation( state, name_ ), args, argsi, "Currently not at any source location, so the breakpoint index 0 is invalid." );
1488 if( index < 0 || static_cast< int >( Kernel::theBreakpoints.size( ) ) < index )
1490 throw Exceptions::CoreOutOfRange( new Interaction::MutatorLocation( state, name_ ), args, argsi, "The index must be either zero (meaning the current breakpoint) or a positive number not greater than the number of breakpoints." );
1492 if( index == 0 )
1494 Ast::Expression * expr = state->breakExpr_;
1495 if( expr->breakpoint_ != 0 )
1497 delete expr->breakpoint_;
1498 expr->breakpoint_ = 0;
1499 Kernel::theBreakpoints.erase( expr );
1502 else
1504 typedef typeof Kernel::theBreakpoints SetType;
1505 SetType::iterator i = Kernel::theBreakpoints.begin( );
1506 for( int tmp = 1; tmp < index; ++tmp, ++i )
1508 delete (*i)->breakpoint_;
1509 (*i)->breakpoint_ = 0;
1510 Kernel::theBreakpoints.erase( *i );
1513 Kernel::ContRef cont = evalState->cont_;
1514 cont->takeValue( Lang::THE_VOID,
1515 evalState );
1519 template< class T >
1520 class Mutator_clearAllBreak : public Lang::CoreMutator
1522 public:
1523 Mutator_clearAllBreak( const char * name )
1524 : CoreMutator( name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), true ) )
1527 virtual void
1528 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1530 args.applyDefaults( callLoc );
1532 /* The state is not used at the moment. */
1533 // typedef T StateType;
1534 // StateType * state = Helpers::mutator_cast_self< StateType >( args.getMutatorSelf( ) );
1536 typedef typeof Kernel::theBreakpoints SetType;
1537 for( SetType::iterator i = Kernel::theBreakpoints.begin( ); i != Kernel::theBreakpoints.end( ); ++i )
1539 delete (*i)->breakpoint_;
1540 (*i)->breakpoint_ = 0;
1542 Kernel::theBreakpoints.clear( );
1544 Kernel::ContRef cont = evalState->cont_;
1545 cont->takeValue( Lang::THE_VOID,
1546 evalState );
1550 template< class T >
1551 class Mutator_ignoreBreak : public Lang::CoreMutator
1553 public:
1554 Mutator_ignoreBreak( const char * name )
1555 : CoreMutator( name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), true ) )
1557 formals_->appendEvaluatedCoreFormal( "index", Helpers::newValHandle( new Lang::Integer( 0 ) ) );
1558 formals_->appendEvaluatedCoreFormal( "count", Helpers::newValHandle( new Lang::Integer( 1 ) ) );
1560 virtual void
1561 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1563 args.applyDefaults( callLoc );
1565 typedef T StateType;
1566 StateType * state = Helpers::mutator_cast_self< StateType >( args.getMutatorSelf( ) );
1568 size_t argsi = 0;
1569 typedef const Lang::Integer ArgType;
1570 int index = Helpers::down_cast_MutatorArgument< ArgType >( state, name_, args, argsi, callLoc )->val_;
1571 if( index == 0 )
1573 if( state->breakExpr_ == 0 )
1575 throw Exceptions::CoreOutOfRange( new Interaction::MutatorLocation( state, name_ ), args, argsi, "Currently not at any source location, so the breakpoint index 0 is invalid." );
1578 else if( index < 0 || static_cast< int >( Kernel::theBreakpoints.size( ) ) < index )
1580 throw Exceptions::CoreOutOfRange( new Interaction::MutatorLocation( state, name_ ), args, argsi, "The index must be either zero (meaning the current breakpoint) or a positive number not greater than the number of breakpoints." );
1582 ++argsi;
1583 int count = Helpers::down_cast_MutatorArgument< ArgType >( state, name_, args, argsi, callLoc )->val_;
1584 if( count < 0 )
1586 throw Exceptions::CoreOutOfRange( new Interaction::MutatorLocation( state, name_ ), args, argsi, "The count must be non-negative." );
1588 if( index == 0 )
1590 Ast::Expression * expr = state->breakExpr_;
1591 if( expr->breakpoint_ == 0 )
1593 expr->breakpoint_ = new Kernel::BreakpointInfo( );
1594 Kernel::theBreakpoints.insert( expr );
1596 expr->breakpoint_->ignoreCount_ = static_cast< size_t >( count );
1598 else
1600 typedef typeof Kernel::theBreakpoints SetType;
1601 SetType::iterator i = Kernel::theBreakpoints.begin( );
1602 for( int tmp = 1; tmp < index; ++tmp, ++i )
1604 (*i)->breakpoint_->ignoreCount_ = static_cast< size_t >( count );
1607 Kernel::ContRef cont = evalState->cont_;
1608 cont->takeValue( Lang::THE_VOID,
1609 evalState );
1614 template< class T >
1615 class Mutator_setBreakLocation : public Lang::CoreMutator
1617 public:
1618 Mutator_setBreakLocation( const char * name )
1619 : CoreMutator( name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), true ) )
1621 formals_->appendEvaluatedCoreFormal( "file", Kernel::THE_SLOT_VARIABLE );
1622 formals_->appendEvaluatedCoreFormal( "line", Kernel::THE_SLOT_VARIABLE );
1623 formals_->appendEvaluatedCoreFormal( "column", Helpers::newValHandle( new Lang::Integer( 0 ) ) );
1624 formals_->appendEvaluatedCoreFormal( "enable", Kernel::THE_VOID_VARIABLE );
1626 virtual void
1627 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1629 args.applyDefaults( callLoc );
1631 /* The state is only used for error handling at the moment. */
1632 typedef T StateType;
1633 StateType * state = Helpers::mutator_cast_self< StateType >( args.getMutatorSelf( ) );
1635 size_t argsi = 0;
1636 struct stat theStat;
1637 std::string fileArg = Helpers::down_cast_MutatorArgument< const Lang::String >( state, name_, args, argsi, callLoc )->val_.getPtr( );
1638 ++argsi;
1639 int line = Helpers::down_cast_MutatorArgument< const Lang::Integer >( state, name_, args, argsi, callLoc )->val_;
1640 if( line < 1 )
1642 throw Exceptions::CoreOutOfRange( new Interaction::MutatorLocation( state, name_ ), args, argsi, "The line number must be positive." );
1644 ++argsi;
1645 int column = Helpers::down_cast_MutatorArgument< const Lang::Integer >( state, name_, args, argsi, callLoc )->val_;
1646 if( column < 0 )
1648 throw Exceptions::CoreOutOfRange( new Interaction::MutatorLocation( state, name_ ), args, argsi, "The column number must be non-negative." );
1650 ++argsi;
1651 RefCountPtr< const Lang::Boolean > breakPtr = Helpers::down_cast_MutatorArgument< const Lang::Boolean >( state, name_, args, argsi, callLoc, true );
1653 const Ast::FileID * fileID = 0;
1654 if( ! Ast::FileID::is_inMemory( fileArg, & fileID ) )
1658 std::string filename = Ast::theShapesScanner.searchFile( fileArg, & theStat );
1659 fileID = Ast::FileID::build_stat( theStat, fileArg );
1661 catch( const Exceptions::Exception & ball )
1663 throw Exceptions::CoreOutOfRange( new Interaction::MutatorLocation( state, name_ ), args, 0, "Failed to locate source file." );
1666 Ast::SourceLocation loc( fileID ); /* Warning: Automatic storage of Ast::SourceLocation, don't create references to this! */
1667 loc.firstLine = line;
1668 loc.lastLine = line;
1669 if( Interaction::characterColumnInBytes )
1671 loc.firstColumn = column;
1672 loc.lastColumn = column;
1674 else
1676 /* Column is the UTF8 column, and needs to be converted to byte column. */
1679 int byteColumn = fileID->UTF8ColumnTobyteColumn( line, column );
1680 loc.firstColumn = byteColumn;
1681 loc.lastColumn = byteColumn;
1683 catch( const Exceptions::OutOfRange & ball )
1685 /* Without actually looking into ball we guess what the problem is... */
1686 throw Exceptions::CoreOutOfRange( new Interaction::MutatorLocation( state, name_ ), args, 1, "Line seems past end of file." );
1689 Ast::Expression * expr = loc.findExpression( );
1690 if( expr == 0 )
1692 throw Exceptions::CoreOutOfRange( new Interaction::MutatorLocation( state, name_ ), args, 0, "Failed to locate position within the source file." );
1694 if( expr->breakpoint_ == 0 )
1696 expr->breakpoint_ = new Kernel::BreakpointInfo( );
1697 Kernel::theBreakpoints.insert( expr );
1700 bool newEnabled;
1701 if( breakPtr == NullPtr< const Lang::Boolean >( ) )
1703 newEnabled = ! expr->breakpoint_->enabled_;
1705 else
1707 newEnabled = breakPtr->val_;
1710 expr->breakpoint_->enabled_ = newEnabled;
1712 Kernel::ContRef cont = evalState->cont_;
1713 cont->takeValue( Lang::THE_VOID,
1714 evalState );
1718 template< class T >
1719 class Mutator_setBreakFunctionBody : public Lang::CoreMutator
1721 public:
1722 Mutator_setBreakFunctionBody( const char * name )
1723 : CoreMutator( name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), true ) )
1725 formals_->appendEvaluatedCoreFormal( "function", Kernel::THE_SLOT_VARIABLE );
1726 formals_->appendEvaluatedCoreFormal( "enable", Kernel::THE_VOID_VARIABLE );
1728 virtual void
1729 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1731 args.applyDefaults( callLoc );
1733 /* The state is only used for error handling at the moment. */
1734 typedef T StateType;
1735 StateType * state = Helpers::mutator_cast_self< StateType >( args.getMutatorSelf( ) );
1737 size_t argsi = 0;
1738 typedef const Lang::UserFunction ArgType;
1739 RefCountPtr< ArgType > fun = Helpers::down_cast_MutatorArgument< ArgType >( state, name_, args, argsi, callLoc );
1740 ++argsi;
1741 RefCountPtr< const Lang::Boolean > breakPtr = Helpers::down_cast_MutatorArgument< const Lang::Boolean >( state, name_, args, argsi, callLoc, true );
1743 Ast::Expression * expr = const_cast< Lang::UserFunction * >( fun.getPtr( ) )->body( );
1744 if( expr->breakpoint_ == 0 )
1746 expr->breakpoint_ = new Kernel::BreakpointInfo( );
1747 Kernel::theBreakpoints.insert( expr );
1750 bool newEnabled;
1751 if( breakPtr == NullPtr< const Lang::Boolean >( ) )
1753 newEnabled = ! expr->breakpoint_->enabled_;
1755 else
1757 newEnabled = breakPtr->val_;
1760 expr->breakpoint_->enabled_ = newEnabled;
1762 Kernel::ContRef cont = evalState->cont_;
1763 cont->takeValue( Lang::THE_VOID,
1764 evalState );
1771 Kernel::WarmDebugger::WarmDebugger( Kernel::Environment * env, Kernel::PassedDyn dyn, Kernel::ContRef resume, Ast::Expression * breakExpr )
1772 : env_( env ), dyn_( dyn ), resume_( resume ), breakExpr_( breakExpr )
1775 Kernel::WarmDebugger::~WarmDebugger( )
1778 void
1779 Debugger_register_mutators( Lang::SystemFinalClass * dstClass )
1781 dstClass->registerMutator( new Kernel::Mutator_resume< Kernel::WarmDebugger >( "resume" ), "r" );
1782 dstClass->registerMutator( new Kernel::Mutator_top_repl< Kernel::WarmDebugger >( "top_repl" ) );
1783 dstClass->registerMutator( new Kernel::Mutator_backtrace< Kernel::WarmDebugger >( "backtrace" ), "t" );
1784 dstClass->registerMutator( new Kernel::Mutator_printEnv< Kernel::WarmDebugger >( "env" ), "e" );
1785 dstClass->registerMutator( new Kernel::Mutator_printDyn< Kernel::WarmDebugger >( "dyn" ), "d" );
1786 dstClass->registerMutator( new Kernel::Mutator_printBreakpoints< Kernel::WarmDebugger >( "breakList" ), "bl" );
1787 dstClass->registerMutator( new Kernel::Mutator_setBreakLocation< Kernel::WarmDebugger >( "breakAt" ), "ba" );
1788 dstClass->registerMutator( new Kernel::Mutator_setBreakFunctionBody< Kernel::WarmDebugger >( "breakIn" ), "bi" );
1789 dstClass->registerMutator( new Kernel::Mutator_ignoreBreak< Kernel::WarmDebugger >( "breakIgnore" ), "bg" );
1790 dstClass->registerMutator( new Kernel::Mutator_clearBreak< Kernel::WarmDebugger >( "breakClear" ), "bc" );
1791 dstClass->registerMutator( new Kernel::Mutator_clearAllBreak< Kernel::WarmDebugger >( "breakClearAll" ), "bC" );
1792 dstClass->registerMutator( new Kernel::Mutator_step< Kernel::WarmDebugger >( "stepe", Kernel::DebugStepInfo::EXPR ), "se" );
1793 dstClass->registerMutator( new Kernel::Mutator_step< Kernel::WarmDebugger >( "step", Kernel::DebugStepInfo::STEP ), "s" );
1794 dstClass->registerMutator( new Kernel::Mutator_step_to_temporary< Kernel::WarmDebugger >( "stepc", Kernel::Mutator_step_to_temporary< Kernel::WarmDebugger >::CHILD ), "sc" );
1795 dstClass->registerMutator( new Kernel::Mutator_step_to_temporary< Kernel::WarmDebugger >( "steps", Kernel::Mutator_step_to_temporary< Kernel::WarmDebugger >::SIBLING ), "ss" );
1796 dstClass->registerMutator( new Kernel::Mutator_cont< Kernel::WarmDebugger >( "contUp", Kernel::Mutator_cont< Kernel::WarmDebugger >::UP ), "cu" );
1797 dstClass->registerMutator( new Kernel::Mutator_cont< Kernel::WarmDebugger >( "contExit", Kernel::Mutator_cont< Kernel::WarmDebugger >::EXIT_DEBUG ), "ce" );
1800 RefCountPtr< const Lang::Class > Kernel::WarmDebugger::TypeID( new Lang::SystemFinalClass( strrefdup( "#Debugger" ), Debugger_register_mutators ) );
1801 TYPEINFOIMPL_STATE( WarmDebugger );
1803 void
1804 Kernel::WarmDebugger::tackOnImpl( Kernel::EvalState * evalState, const RefCountPtr< const Lang::Value > & piece,const Ast::SourceLocation & callLoc )
1806 throw Exceptions::MiscellaneousRequirement( strrefdup( "The debugger only interacts through named mutators; there is no tack-on mutator." ) );
1809 void
1810 Kernel::WarmDebugger::freezeImpl( Kernel::EvalState * evalState, const Ast::SourceLocation & callLoc )
1812 throw Exceptions::MiscellaneousRequirement( strrefdup( "The debugger cannot be frozen." ) );
1815 void
1816 Kernel::WarmDebugger::peekImpl( Kernel::EvalState * evalState, const Ast::SourceLocation & callLoc )
1818 throw Exceptions::MiscellaneousRequirement( strrefdup( "The debugger cannot be peeked." ) );
1821 void
1822 Kernel::WarmDebugger::gcMark( Kernel::GCMarkedSet & marked )
1826 Kernel::BreakpointInfo::BreakpointInfo( )
1827 : enabled_( false ), createdForTemporaryUse_( false ), ignoreCount_( 0 )
1830 Kernel::BreakpointInfo::~BreakpointInfo( )