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