Doc: Update namespace of extensions
[shapes.git] / source / astvar.cc
blobdf5030c7f7a03b3ca8f514198e2c7761b1de292e
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, 2014, 2015 Henrik Tidefelt
19 #include "astvar.h"
20 #include "shapesexceptions.h"
21 #include "globals.h"
22 #include "autoonoff.h"
23 #include "specialunits.h"
24 #include "astfun.h"
25 #include "continuations.h"
26 #include "containertypes.h"
27 #include "check.h"
29 #include <algorithm>
31 using namespace Shapes;
32 using namespace std;
35 Ast::SourceLocationMark::SourceLocationMark( const Ast::SourceLocation & loc )
36 : Ast::Node( loc )
37 { }
39 Ast::SourceLocationMark::~SourceLocationMark( )
40 { }
42 void
43 Ast::SourceLocationMark::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
44 { }
46 namespace Shapes
48 namespace Helpers
50 class IsSourceLocationMark
52 public:
53 bool operator () ( const Ast::Node * n ) const
55 return dynamic_cast< const Ast::SourceLocationMark * >( n ) != 0;
62 Ast::CodeBracket::CodeBracket( const Ast::SourceLocation & loc, std::list< Ast::Node * > * nodes, Ast::CodeBracket * extends )
63 : Ast::Expression( loc ), nodes_( nodes ), extends_( extends ),
64 argumentOrder_( ( extends == 0 ) ? ( new Ast::IdentifierTree( NULL, false ) ) : ( extends->argumentOrder_ ) ),
65 dynamicMap_( ( extends == 0 ) ? ( 0 ) : ( extends->dynamicMap_ ) ),
66 stateOrder_( ( extends == 0 ) ? ( new Ast::IdentifierTree( NULL, false ) ) : ( extends->stateOrder_ ) )
68 /* First, we remove any source location marks -- we don't need them anymore. */
69 nodes_->remove_if( Helpers::IsSourceLocationMark( ) );
71 /* Alias definitions will be extracted and applied in this function. */
72 PtrOwner_back_Access< std::list< const Ast::DefineAlias * > > aliasNodes;
74 for( std::list< Ast::Node * >::const_iterator i = nodes_->begin( );
75 i != nodes_->end( );
78 typedef Ast::BindNode T;
79 if( T * tmp = dynamic_cast< T * >( *i ) )
81 bindNodes_.push_back( tmp );
83 const Ast::PlacedIdentifier * id = tmp->id( );
84 if( dynamic_cast< const Ast::DefineVariable * >( tmp ) != NULL )
86 if( ! argumentOrder_->insert( *id, tmp->idLoc( ) ) ){
87 Ast::theAnalysisErrorsList.push_back( new Exceptions::IntroducingExisting( tmp->idLoc( ), *id ) );
89 ++i;
90 continue;
92 if( dynamic_cast< const Ast::IntroduceState * >( tmp ) != NULL )
94 if( ! stateOrder_->insert( *id, tmp->idLoc( ) ) ){
95 Ast::theAnalysisErrorsList.push_back( new Exceptions::IntroducingExisting( tmp->idLoc( ), *id ) );
97 ++i;
98 continue;
100 if( dynamic_cast< const Ast::DynamicVariableDecl * >( tmp ) != NULL )
102 if( dynamicMap_ == 0 )
104 setDynamicMap( new Ast::IdentifierTree( NULL, false ) ); /* Sending the new map to extends_ recursively is important for memory management. */
106 if( ! dynamicMap_->insert( *id, tmp->idLoc( ) ) ){
107 Ast::theAnalysisErrorsList.push_back( new Exceptions::IntroducingExisting( tmp->idLoc( ), *id ) );
109 ++i;
110 continue;
113 if( const Ast::DefineAlias * defineAliasNode = dynamic_cast< const Ast::DefineAlias * >( *i ) )
115 aliasNodes.push_back( defineAliasNode );
116 std::list< Ast::Node * >::const_iterator j = i;
117 ++i;
118 nodes_->erase( j );
119 continue;
121 ++i;
124 for( std::list< const Ast::DefineAlias * >::const_iterator i = aliasNodes.begin( );
125 i != aliasNodes.end( );
126 ++i )
128 bool resolved = false;
129 resolved = resolved || argumentOrder_->insertAlias( *((*i)->id( )), (*i)->expansion( ), (*i)->idLoc( ) );
130 resolved = resolved || stateOrder_->insertAlias( *((*i)->id( )), (*i)->expansion( ), (*i)->idLoc( ) );
131 if( dynamicMap_ != NULL ){
132 resolved = resolved || dynamicMap_->insertAlias( *((*i)->id( )), (*i)->expansion( ), (*i)->idLoc( ) );
134 if( ! resolved ){
135 Interaction::warn_or_push( new Exceptions::UndefinedNamespace( (*i)->expansionLoc( ), (*i)->expansion( ) ), & Ast::theAnalysisErrorsList );
140 void
141 Ast::CodeBracket::setDynamicMap( Ast::IdentifierTree * dynamicMap )
143 dynamicMap_ = dynamicMap;
144 if( extends_ != 0 )
146 extends_->setDynamicMap( dynamicMap );
150 Ast::CodeBracket::~CodeBracket( )
152 typedef list< Ast::Node * >::iterator I;
153 for( I i = nodes_->begin( ); i != nodes_->end( ); ++i )
155 delete *i;
157 delete nodes_;
159 if( extends_ == 0 )
161 /* If extends_ != 0, this object does not own the maps. */
162 delete argumentOrder_;
163 if( dynamicMap_ != 0 )
165 delete dynamicMap_;
167 delete stateOrder_;
171 void
172 Ast::CodeBracket::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * parentEnv, Ast::StateIDSet * freeStatesDst )
174 if( extends_ == 0 )
176 analysisEnv_ = new Ast::AnalysisEnvironment( Ast::theAnalysisEnvironmentList, parentEnv, argumentOrder_, stateOrder_ );
178 else
180 analysisEnv_ = extends_->analysisEnv_;
181 analysisEnv_->updateBindings( );
184 if( dynamicMap_ != 0 )
186 analysisEnv_->setupDynamicKeyVariables( dynamicMap_ );
190 Ast::StateIDSet allFreeStates;
191 Ast::StateIDSet introducedStates;
194 Ast::StateIDSet freeStates;
195 typedef list< Ast::Node * >::iterator I;
196 for( I i = nodes_->begin( ); i != nodes_->end( ); ++i )
198 freeStates.clear( );
199 (*i)->analyze( this, analysisEnv_, & freeStates );
200 if( ! freeStates.empty( ) )
202 typedef typeof freeStates SetType;
203 for( SetType::const_iterator j = freeStates.begin( ); j != freeStates.end( ); ++j )
205 allFreeStates.insert( *j );
208 else
210 Ast::Expression * expr = dynamic_cast< Ast::Expression * >( *i );
211 if( expr != 0 && ! expr->immediate_ )
213 I tmp = i;
214 ++tmp;
215 if( tmp != nodes_->end( ) )
217 Ast::theAnalysisErrorsList.push_back( new Exceptions::ExpectedImmediate( (*i)->loc( ) ) );
221 Ast::IntroduceState * introduceStateExpr = dynamic_cast< Ast::IntroduceState * >( *i );
222 if( introduceStateExpr != 0 )
224 introducedStates.insert( introduceStateExpr->getStateID( ) );
229 if( ! introducedStates.empty( ) )
231 Ast::StateIDSet diff;
232 std::set_difference( allFreeStates.begin( ), allFreeStates.end( ),
233 introducedStates.begin( ), introducedStates.end( ),
234 std::inserter( diff, diff.begin( ) ) );
235 allFreeStates.swap( diff );
237 if( ! allFreeStates.empty( ) )
239 typedef typeof allFreeStates SetType;
240 for( SetType::const_iterator j = allFreeStates.begin( ); j != allFreeStates.end( ); ++j )
242 freeStatesDst->insert( *j );
247 void
248 Ast::CodeBracket::eval( Kernel::EvalState * evalState ) const
250 if( nodes_->begin( ) == nodes_->end( ) )
252 Kernel::ContRef cont = evalState->cont_;
253 cont->takeValue( Lang::THE_VOID,
254 evalState );
255 return;
258 evalState->env_ = newEnvironment( evalState->env_ );
260 if( dynamicMap_ != 0 )
262 evalState->env_->setupDynamicKeyVariables( dynamicMap_ );
265 typedef typeof bindNodes_ ListType;
266 for( ListType::const_iterator i = bindNodes_.begin( ); i != bindNodes_.end( ); ++i ){
267 (*i)->initializeEnvironment( evalState->env_, evalState->dyn_ );
270 RefCountPtr< const Kernel::CodeBracketContInfo > info( new Kernel::CodeBracketContInfo( this, *evalState ) );
272 evalAt( info, nodes_->begin( ), evalState );
275 Kernel::Environment *
276 Ast::CodeBracket::newEnvironment( Kernel::Environment * parent, const char * debugName ) const
278 CHECK(
279 if( extends_ != 0 )
281 throw Exceptions::InternalError( "Ast::CodeBracket::newEnvironment( ): extends_ != 0" );
284 std::vector< Kernel::VariableHandle > * envValues = new std::vector< Kernel::VariableHandle >;
285 envValues->reserve( argumentOrder_->size( ) );
286 while( envValues->size( ) < argumentOrder_->size( ) )
288 envValues->push_back( NullPtr< Kernel::Variable >( ) );
291 std::vector< Kernel::StateHandle > * envStates = new std::vector< Kernel::StateHandle >;
292 envStates->reserve( stateOrder_->size( ) );
293 while( envStates->size( ) < stateOrder_->size( ) )
295 envStates->push_back( NullPtr< Kernel::State >( ) );
298 return new Kernel::Environment( Kernel::theEnvironmentList, parent, argumentOrder_, RefCountPtr< std::vector< Kernel::VariableHandle > >( envValues ), stateOrder_, RefCountPtr< std::vector< Kernel::StateHandle > >( envStates ), debugName );
301 void
302 Ast::CodeBracket::eval( Kernel::EvalState * evalState, Kernel::Environment * extendsEnv ) const
304 if( nodes_->begin( ) == nodes_->end( ) )
306 Kernel::ContRef cont = evalState->cont_;
307 cont->takeValue( Lang::THE_VOID,
308 evalState );
309 return;
312 evalState->env_ = extendsEnv;
313 if( dynamicMap_ != 0 )
315 evalState->env_->setupDynamicKeyVariables( dynamicMap_ );
317 evalState->env_->extendVectors( );
319 RefCountPtr< const Kernel::CodeBracketContInfo > info( new Kernel::CodeBracketContInfo( this, *evalState ) );
321 evalAt( info, nodes_->begin( ), evalState );
324 void
325 Ast::CodeBracket::evalAt( const RefCountPtr< const Kernel::CodeBracketContInfo > & info, const std::list< Ast::Node * >::const_iterator & pos, Kernel::EvalState * evalState ) const
327 Ast::Expression * e = dynamic_cast< Ast::Expression * >( *pos );
329 std::list< Ast::Node * >::const_iterator next = pos;
330 ++next;
331 if( next == nodes_->end( ) )
333 if( e != 0 &&
334 e->immediate_ )
336 evalState->cont_ = Kernel::ContRef( new Kernel::ForcingContinuation( info->cont_, (*pos)->loc( ) ) );
338 else
340 evalState->cont_ = info->cont_;
343 else
345 evalState->cont_ = Kernel::ContRef( new Kernel::CodeBracketContinuation( (*pos)->loc( ), info, next ) );
348 evalState->env_ = info->env_;
349 evalState->dyn_ = info->dyn_;
350 if( e != 0 )
352 evalState->expr_ = e;
353 return;
355 const Ast::BindNode * bn = dynamic_cast< const Ast::BindNode * >( *pos );
356 if( bn != 0 )
358 bn->evalHelper( evalState );
359 return;
361 throw Exceptions::InternalError( (*pos)->loc( ), "CodeBracket::evalAt: Node was neither Expression or BindNode." );
365 Kernel::CodeBracketContInfo::CodeBracketContInfo( const Ast::CodeBracket * bracketExpr, const Kernel::EvalState & evalState )
366 : bracketExpr_( bracketExpr ), env_( evalState.env_ ), dyn_( evalState.dyn_ ), cont_( evalState.cont_ )
369 Kernel::CodeBracketContInfo::~CodeBracketContInfo( )
372 void
373 Kernel::CodeBracketContInfo::gcMark( Kernel::GCMarkedSet & marked )
375 env_->gcMark( marked );
376 dyn_->gcMark( marked );
377 cont_->gcMark( marked );
380 Kernel::CodeBracketContinuation::CodeBracketContinuation( const Ast::SourceLocation & traceLoc, const RefCountPtr< const Kernel::CodeBracketContInfo > & info, const std::list< Ast::Node * >::const_iterator & pos )
381 : Kernel::Continuation( traceLoc ), info_( info ), pos_( pos )
384 Kernel::CodeBracketContinuation::~CodeBracketContinuation( )
387 void
388 Kernel::CodeBracketContinuation::takeValue( const RefCountPtr< const Lang::Value > & val, Kernel::EvalState * evalState, bool dummy ) const
390 if( val.down_cast< const Lang::Void >( ) == NullPtr< const Lang::Void >( ) )
392 throw Exceptions::NonVoidStatement( traceLoc_, val );
394 info_->bracketExpr_->evalAt( info_,
395 pos_,
396 evalState );
399 Kernel::ContRef
400 Kernel::CodeBracketContinuation::up( ) const
402 return info_->cont_;
405 RefCountPtr< const char >
406 Kernel::CodeBracketContinuation::description( ) const
408 return strrefdup( "code bracket" );
411 void
412 Kernel::CodeBracketContinuation::gcMark( Kernel::GCMarkedSet & marked )
414 const_cast< Kernel::CodeBracketContInfo * >( info_.getPtr( ) )->gcMark( marked );
418 Ast::LexiographicVariable::LexiographicVariable( const Ast::SourceLocation & loc, const Ast::Identifier * id, Kernel::Environment::LexicalKey ** idKey )
419 : Ast::Expression( loc ), id_( id ), idKey_( idKey )
421 immediate_ = true;
424 Ast::LexiographicVariable::~LexiographicVariable( )
426 delete id_;
427 if( *idKey_ != 0 )
429 delete *idKey_;
431 delete idKey_; /* This can be done only as long as this is not shared! */
434 void
435 Ast::LexiographicVariable::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
437 if( *idKey_ == 0 )
439 *idKey_ = new Kernel::Environment::LexicalKey( env->findLexicalVariableKey( loc_, *id_ ) );
441 scope_level_ = env->level( ) - (*idKey_)->up_;
444 void
445 Ast::LexiographicVariable::eval( Kernel::EvalState * evalState ) const
447 evalState->env_->lookup( **idKey_, evalState );
451 Ast::PrivateAliasVariable::PrivateAliasVariable( const Ast::SourceLocation & loc, const Ast::PlacedIdentifier & id, const RefCountPtr< const char > & privateName )
452 : Ast::Expression( loc ), id_( id ), privateName_( privateName ), aliasKey_( NULL )
454 immediate_ = true;
457 Ast::PrivateAliasVariable::~PrivateAliasVariable( )
459 /* Don't delete id_ -- it will be shared with the id_ of a DefineVariable. */
460 if( aliasKey_ != NULL ){
461 delete aliasKey_;
465 void
466 Ast::PrivateAliasVariable::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
468 aliasKey_ = new Kernel::Environment::LexicalKey( env->findPrivateAliasVariableKey( loc_, id_, privateName_.getPtr( ) ) );
471 void
472 Ast::PrivateAliasVariable::eval( Kernel::EvalState * evalState ) const
474 evalState->env_->lookup( *aliasKey_, evalState );
478 Ast::Force::Force( const Ast::SourceLocation & loc, Ast::Expression * expr )
479 : Ast::Expression( loc ), expr_( expr )
481 immediate_ = true;
484 Ast::Force::~Force( )
486 delete expr_;
489 void
490 Ast::Force::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
492 expr_->analyze( this, env, freeStatesDst );
495 void
496 Ast::Force::eval( Kernel::EvalState * evalState ) const
498 evalState->cont_ = Kernel::ContRef( new Kernel::ForcingContinuation( evalState->cont_, loc_ ) );
499 evalState->expr_ = expr_;
503 Ast::EvalOutsideExpr::EvalOutsideExpr( const Ast::SourceLocation & loc, Ast::Expression * expr )
504 : Ast::Expression( loc ), expr_( expr )
506 immediate_ = true;
509 Ast::EvalOutsideExpr::~EvalOutsideExpr( )
511 delete expr_;
514 void
515 Ast::EvalOutsideExpr::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
517 expr_->analyze( this, env->getParent( ), freeStatesDst );
520 void
521 Ast::EvalOutsideExpr::eval( Kernel::EvalState * evalState ) const
523 evalState->expr_ = expr_;
524 evalState->env_ = evalState->env_->getParent( );
528 Ast::MemberReferenceFunction::MemberReferenceFunction( const Ast::SourceLocation & loc, Ast::Expression * variable, const char * fieldID )
529 : Lang::Function( new Kernel::EvaluatedFormals( Ast::FileID::build_internal( "<>.<>" ), true ) ), loc_( loc ), variable_( variable ), fieldID_( fieldID )
532 Ast::MemberReferenceFunction::~MemberReferenceFunction( )
534 delete variable_;
535 delete fieldID_;
538 void
539 Ast::MemberReferenceFunction::push_exprs( Ast::ArgListExprs * args ) const
541 args->orderedExprs_->push_back( variable_ );
544 void
545 Ast::MemberReferenceFunction::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
547 /* The variable is analyzed as part of the arguments passed to this function, so nothing needs to be done here...
548 * unless we would be able to figure out the type of the argument, and then check if the field reference is valid.
552 void
553 Ast::MemberReferenceFunction::call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
555 Kernel::ContRef cont = evalState->cont_;
556 RefCountPtr< const Lang::Value > arg = args.getValue( 0 );
557 cont->takeHandle( arg->getField( fieldID_, arg ),
558 evalState );
563 Ast::MutatorReference::MutatorReference( const Ast::SourceLocation & mutatorLoc, Ast::StateReference * state, const char * mutatorID )
564 : Ast::Expression( mutatorLoc ), mutatorLoc_( mutatorLoc ), state_( state ), mutatorID_( mutatorID )
567 Ast::MutatorReference::~MutatorReference( )
569 /* At the time of implementing this bug-fix, state_ will allways be owned by the Ast::CallExpr that is also the owner of us.
570 * Hence, we do not consider ourselves owners. Perhaps one should have a flag indicating whether ownership is transferred
571 * when calling the constructor, but at the moment this seems like a waste of resources.
573 // delete state_;
574 delete mutatorID_;
577 void
578 Ast::MutatorReference::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
580 state_->analyze( this, env, freeStatesDst );
581 /* If the type of the state was known here, we should verify that there is a mutator corresponding to the message <mutatorID>.
585 void
586 Ast::MutatorReference::eval( Kernel::EvalState * evalState ) const
588 Kernel::ContRef cont = evalState->cont_;
589 cont->takeValue( state_->getHandle( evalState->env_, evalState->dyn_ )->getMutator( mutatorID_ ),
590 evalState );
595 Ast::SpecialLength::SpecialLength( const Ast::SourceLocation & loc, double val, int sort )
596 : Ast::Expression( loc ), val_( val ), sort_( sort )
599 Ast::SpecialLength::~SpecialLength( )
602 void
603 Ast::SpecialLength::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
605 /* Nothing to do! */
608 void
609 Ast::SpecialLength::eval( Kernel::EvalState * evalState ) const
611 Concrete::Length d;
612 double a0;
613 double a1;
615 evalState->dyn_->specialUnitService( & d, & a0, & a1 );
617 if( sort_ == Computation::SPECIALU_NOINFLEX )
619 Kernel::ContRef cont = evalState->cont_;
620 cont->takeValue( Kernel::ValueRef( new Lang::Length( val_ * d * Computation::specialUnitNoInflexion( a0, a1 ) ) ),
621 evalState );
622 return;
624 if( ! sort_ & Computation::SPECIALU_DIST )
626 throw Exceptions::InternalError( strrefdup( "The special unit is neither based on inflexion or distance" ) );
629 double res = 1;
631 if( sort_ & Computation::SPECIALU_CIRC )
633 res *= Computation::specialUnitCircleHandle( a0 );
636 if( sort_ & Computation::SPECIALU_CORR )
638 res *= Computation::specialUnitCorrection( a0, a1 );
641 if( sort_ & Computation::SPECIALU_NOINFLEX )
643 res = min( res, Computation::specialUnitNoInflexion( a0, a1 ) );
645 Kernel::ContRef cont = evalState->cont_;
646 cont->takeValue( Kernel::ValueRef( new Lang::Length( val_ * d * res ) ),
647 evalState );
651 Ast::DynamicVariable::DynamicVariable( const Ast::SourceLocation & loc, const Ast::Identifier * id )
652 : Ast::Expression( loc ), id_( id ), idKey_( new Kernel::Environment::LexicalKey * ( 0 ) )
654 immediate_ = true;
657 Ast::DynamicVariable::~DynamicVariable( )
659 delete id_;
660 if( *idKey_ != 0 )
662 delete *idKey_;
664 delete idKey_; // This can be done only as long as this is not shared!
667 void
668 Ast::DynamicVariable::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
670 if( *idKey_ == 0 )
672 *idKey_ = new Kernel::Environment::LexicalKey( env->findLexicalDynamicKey( loc_, *id_ ) );
676 void
677 Ast::DynamicVariable::eval( Kernel::EvalState * evalState ) const
679 const Kernel::DynamicVariableProperties & dynProps = evalState->env_->lookupDynamicVariable( **idKey_ );
681 Kernel::VariableHandle res = dynProps.fetch( evalState->dyn_ );
683 /* Now, we know that if the value was bound to a dynamic expression, a value was bound, and that value has
684 * a certain type.
686 if( ! res->isThunk( ) )
690 typedef const Lang::DynamicExpression DynType;
691 RefCountPtr< DynType > dynVal = res->tryVal< DynType >( );
692 dynVal->evalHelper( evalState );
693 return;
695 catch( const NonLocalExit::NotThisType & ball )
697 // Never mind.
701 Kernel::ContRef cont = evalState->cont_;
702 cont->takeHandle( res,
703 evalState );
707 Kernel::DynamicBindingContinuation::DynamicBindingContinuation( const Ast::SourceLocation & traceLoc, const Kernel::PassedEnv & env, const Kernel::Environment::LexicalKey & key, const Ast::DynamicBindingExpression * bindingExpr, const Kernel::ContRef & cont )
708 : Kernel::Continuation( traceLoc ), env_( env ), key_( key ), bindingExpr_( bindingExpr ), cont_( cont )
711 Kernel::DynamicBindingContinuation::~DynamicBindingContinuation( )
714 void
715 Kernel::DynamicBindingContinuation::takeHandle( Kernel::VariableHandle val, Kernel::EvalState * evalState, bool dummy ) const
717 if( val->isThunk( ) )
719 val->force( val, evalState );
720 return;
722 evalState->cont_ = cont_;
723 env_->lookupDynamicVariable( key_ ).makeBinding( val, bindingExpr_, evalState );
726 Kernel::ContRef
727 Kernel::DynamicBindingContinuation::up( ) const
729 return cont_;
732 RefCountPtr< const char >
733 Kernel::DynamicBindingContinuation::description( ) const
735 return strrefdup( "dynamic binding" );
738 void
739 Kernel::DynamicBindingContinuation::gcMark( Kernel::GCMarkedSet & marked )
741 env_->gcMark( marked );
742 cont_->gcMark( marked );
745 Ast::DynamicBindingExpression::DynamicBindingExpression( const Ast::SourceLocation & idLoc, const Ast::Identifier * id, Ast::Expression * expr, Kernel::Environment::LexicalKey ** idKey )
746 : Ast::Expression( Ast::SourceLocation( idLoc, expr->loc( ) ) ), idLoc_( idLoc ), id_( id ), expr_( expr ), idKey_( new Kernel::Environment::LexicalKey * ( 0 ) )
749 Ast::DynamicBindingExpression::~DynamicBindingExpression( )
751 delete id_;
752 delete expr_;
753 if( *idKey_ != 0 )
755 delete *idKey_;
756 *idKey_ = 0;
758 // Don't delete idKey as it's shared!
761 void
762 Ast::DynamicBindingExpression::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
764 expr_->analyze( this, env, freeStatesDst );
765 if( *idKey_ == 0 )
767 *idKey_ = new Kernel::Environment::LexicalKey( env->findLexicalDynamicKey( idLoc_, *id_ ) );
771 void
772 Ast::DynamicBindingExpression::eval( Kernel::EvalState * evalState ) const
774 const Kernel::DynamicVariableProperties & dynProps = evalState->env_->lookupDynamicVariable( **idKey_ );
776 if( dynProps.forceValue( ) || expr_->immediate_ )
778 evalState->expr_ = expr_;
779 evalState->cont_ = Kernel::ContRef( new Kernel::DynamicBindingContinuation( expr_->loc( ), evalState->env_, **idKey_, this, evalState->cont_ ) );
781 else
783 dynProps.makeBinding( Kernel::VariableHandle( new Kernel::Variable( new Kernel::Thunk( evalState->env_, evalState->dyn_, expr_ ) ) ),
784 this,
785 evalState );
790 Ast::DynamicStateBindingExpression::DynamicStateBindingExpression( const Ast::SourceLocation & loc, const Ast::SourceLocation & dstLoc, const Ast::Identifier * dstId, Ast::StateReference * src )
791 : Ast::Expression( loc ), dstLoc_( dstLoc ), dstId_( dstId ), dstIdKey_( new Kernel::Environment::LexicalKey * ( 0 ) ), src_( src )
794 Ast::DynamicStateBindingExpression::~DynamicStateBindingExpression( )
796 delete src_;
797 if( *dstIdKey_ != 0 )
799 delete *dstIdKey_;
801 delete dstIdKey_; // This can be done only as long as this is not shared!
804 void
805 Ast::DynamicStateBindingExpression::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
807 if( *dstIdKey_ == 0 )
809 *dstIdKey_ = new Kernel::Environment::LexicalKey( env->findLexicalDynamicKey( dstLoc_, *dstId_ ) );
813 void
814 Ast::DynamicStateBindingExpression::eval( Kernel::EvalState * evalState ) const
816 const Kernel::DynamicStateProperties & dstDynProps = evalState->env_->lookupDynamicState( **dstIdKey_ );
818 dstDynProps.makeBinding( src_->getHandle( evalState->env_, evalState->dyn_ ), this, evalState );
822 Kernel::WithDynamicContinuation::WithDynamicContinuation( const Ast::SourceLocation & traceLoc, Ast::Expression * expr, const Kernel::EvalState & evalState )
823 : Kernel::Continuation( traceLoc ), expr_( expr ), env_( evalState.env_ ), dyn_( evalState.dyn_ ), cont_( evalState.cont_ )
826 Kernel::WithDynamicContinuation::~WithDynamicContinuation( )
829 void
830 Kernel::WithDynamicContinuation::takeValue( const RefCountPtr< const Lang::Value > & val, Kernel::EvalState * evalState, bool dummy ) const
832 evalState->dyn_ = Kernel::PassedDyn( new Kernel::DynamicEnvironment( dyn_, *Helpers::down_cast< const Lang::DynamicBindings >( val, traceLoc_ ) ) );
833 evalState->env_ = env_;
834 evalState->expr_ = expr_;
835 evalState->cont_ = cont_;
838 Kernel::ContRef
839 Kernel::WithDynamicContinuation::up( ) const
841 return cont_;
844 RefCountPtr< const char >
845 Kernel::WithDynamicContinuation::description( ) const
847 return strrefdup("with dynamic bindings" );
850 void
851 Kernel::WithDynamicContinuation::gcMark( Kernel::GCMarkedSet & marked )
853 env_->gcMark( marked );
854 dyn_->gcMark( marked );
855 cont_->gcMark( marked );
859 Ast::WithDynamicExpr::WithDynamicExpr( const Ast::SourceLocation & loc, Ast::Expression * bindings, Ast::Expression * expr )
860 : Ast::Expression( loc ), bindings_( bindings ), expr_( expr )
863 Ast::WithDynamicExpr::~WithDynamicExpr( )
866 void
867 Ast::WithDynamicExpr::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
869 bindings_->analyze( this, env, freeStatesDst );
870 expr_->analyze( this, env, freeStatesDst );
873 void
874 Ast::WithDynamicExpr::eval( Kernel::EvalState * evalState ) const
876 evalState->expr_ = bindings_;
877 evalState->cont_ = Kernel::ContRef( new Kernel::WithDynamicContinuation( bindings_->loc( ), expr_, *evalState ) );
881 Ast::DynamicVariableDecl::DynamicVariableDecl( const Ast::SourceLocation & loc, const Ast::SourceLocation & idLoc, const Ast::PlacedIdentifier * id, Ast::Expression * filterExpr, Ast::Expression * defaultExpr )
882 : Ast::BindNode( loc, idLoc, id ), idPos_( new size_t * ( 0 ) )
884 /* This type of expression is an Ast::BindNode so that it is easy to recognize and extract the identifier for static analysis
885 * and similar tasks.
887 * The expression is implemented as a function call, since there are two subexpressions that may need evaluation.
890 Ast::ArgListExprs * args = new Ast::ArgListExprs( false );
891 Ast::DynamicVariableDeclFunction * res = new Ast::DynamicVariableDeclFunction( id, filterExpr, defaultExpr, idPos_ );
892 res->push_exprs( args );
893 Ast::CallExpr * callExpr =
894 new Ast::CallExpr( loc,
895 RefCountPtr< const Lang::Function >( res ),
896 args );
897 /* Wrap the call in Ast::Force as a poor substitute for doing the right thing, see comment in initializeEnvironment. */
898 impl_ = new Ast::Force( loc, callExpr );
901 Ast::DynamicVariableDecl::~DynamicVariableDecl( )
904 void
905 Ast::DynamicVariableDecl::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
907 impl_->analyze( this, env, freeStatesDst );
908 if( *idPos_ == 0 ){
909 *idPos_ = new size_t( env->findLocalDynamicPosition( idLoc_, *id_ ) );
913 void
914 Ast::DynamicVariableDecl::initializeEnvironment( Kernel::PassedEnv env, Kernel::PassedDyn dyn ) const
916 /* Here, the right thing to do is probably to put the impl_ call in a DynamicVariableProperties thunk, but
917 * that type of thunk is not invented yet.
919 * As a poor substitute for the right thing, the impl_ call is wrapped in Ast::Force, see contructor.
923 void
924 Ast::DynamicVariableDecl::evalHelper( Kernel::EvalState * evalState ) const
926 evalState->expr_ = impl_;
930 Ast::DynamicVariableDeclFunction::DynamicVariableDeclFunction( const Ast::PlacedIdentifier * id, Ast::Expression * filterExpr, Ast::Expression * defaultExpr, size_t ** idPos )
931 : Lang::Function( new Kernel::EvaluatedFormals( Ast::FileID::build_internal( "< dynamic variable declaration >" ) ) ), id_( id ), filterExpr_( filterExpr ), defaultExpr_( defaultExpr ), idPos_( idPos )
933 formals_->appendEvaluatedCoreFormal( "filter", Kernel::THE_SLOT_VARIABLE, true );
934 formals_->appendEvaluatedCoreFormal( "default", Kernel::THE_SLOT_VARIABLE, false );
937 Ast::DynamicVariableDeclFunction::~DynamicVariableDeclFunction( )
939 delete filterExpr_;
940 delete defaultExpr_;
943 void
944 Ast::DynamicVariableDeclFunction::push_exprs( Ast::ArgListExprs * args ) const
946 args->orderedExprs_->push_back( filterExpr_ );
947 args->orderedExprs_->push_back( defaultExpr_ );
950 void
951 Ast::DynamicVariableDeclFunction::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
953 /* The analysis is carried out by the DynamicVariableDecl expression.
957 void
958 Ast::DynamicVariableDeclFunction::call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
960 static const char * title = "< dynamic variable declaration >";
961 typedef const Lang::Function FilterType;
962 evalState->env_->defineDynamic( id_,
963 **idPos_,
964 Helpers::down_cast_CoreArgument< FilterType >( title, args, 0, callLoc ),
965 args.getHandle( 1 ) );
967 Kernel::ContRef cont = evalState->cont_;
968 cont->takeHandle( Kernel::THE_VOID_VARIABLE,
969 evalState );
972 Kernel::DynamicVariableDeclContinuation::DynamicVariableDeclContinuation( const Ast::SourceLocation & traceLoc, const Ast::DynamicVariableDecl *, Kernel::EvalState & evalState )
973 : Kernel::Continuation( traceLoc ), env_( evalState.env_ ), dyn_( evalState.dyn_ ), cont_( evalState.cont_ )
976 Kernel::DynamicVariableDeclContinuation::~DynamicVariableDeclContinuation( )
979 void
980 Kernel::DynamicVariableDeclContinuation::takeValue( const RefCountPtr< const Lang::Value > & val, Kernel::EvalState * evalState, bool dummy ) const
982 evalState->env_ = env_;
983 evalState->dyn_ = dyn_;
984 evalState->cont_ = cont_;
985 throw Exceptions::NotImplemented( "Deprecated: DynamicVariableDeclContinuation" );
986 // declExpr_->callBack( Helpers::down_cast< const Lang::Function >( val, traceLoc_ ),
987 // evalState );
990 Kernel::ContRef
991 Kernel::DynamicVariableDeclContinuation::up( ) const
993 return cont_;
996 RefCountPtr< const char >
997 Kernel::DynamicVariableDeclContinuation::description( ) const
999 return strrefdup( "dynamic variable declaration" );
1002 void
1003 Kernel::DynamicVariableDeclContinuation::gcMark( Kernel::GCMarkedSet & marked )
1005 env_->gcMark( marked );
1006 dyn_->gcMark( marked );
1007 cont_->gcMark( marked );
1011 Ast::DynamicStateDecl::DynamicStateDecl( const Ast::SourceLocation & loc, const Ast::SourceLocation & idLoc, const Ast::PlacedIdentifier * id, Ast::StateReference * defaultState, size_t ** idPos )
1012 : Ast::BindNode( loc, idLoc, id ), idPos_( idPos ), defaultState_( defaultState )
1015 Ast::DynamicStateDecl::~DynamicStateDecl( )
1019 void
1020 Ast::DynamicStateDecl::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1022 if( *idPos_ == 0 )
1024 *idPos_ = new size_t( env->findLocalDynamicStatePosition( idLoc_, *id_ ) );
1028 void
1029 Ast::DynamicStateDecl::initializeEnvironment( Kernel::PassedEnv env, Kernel::PassedDyn dyn ) const
1031 env->defineDynamicState( id_, **idPos_, env, dyn, defaultState_ );
1034 void
1035 Ast::DynamicStateDecl::evalHelper( Kernel::EvalState * evalState ) const
1037 Kernel::ContRef cont = evalState->cont_;
1038 cont->takeHandle( Kernel::THE_VOID_VARIABLE,
1039 evalState );
1043 Ast::EvalSymbolFunction::EvalSymbolFunction( const Ast::SourceLocation & loc, Ast::Expression * expr, const RefCountPtr< const Ast::NamespacePath > & lexicalPath )
1044 : Lang::Function( new Kernel::EvaluatedFormals( Ast::FileID::build_internal( "< symbol evaluation >" ), true ) ), loc_( loc ), expr_( expr ), lexicalPath_( lexicalPath )
1047 Ast::EvalSymbolFunction::~EvalSymbolFunction( )
1049 delete expr_;
1052 void
1053 Ast::EvalSymbolFunction::push_exprs( Ast::ArgListExprs * args ) const
1055 args->orderedExprs_->push_back( expr_ );
1058 void
1059 Ast::EvalSymbolFunction::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1061 analysisEnv_ = env;
1063 /* expr_ shall be analyzed from the calling expression.
1064 * Here, it is only used to locate errors.
1068 void
1069 Ast::EvalSymbolFunction::call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1071 static const RefCountPtr< const Ast::NamespacePath > EMPTY_RELATIVE_PATH( new Ast::NamespacePath( ) );
1073 RefCountPtr< const Lang::Value > untypedVal = args.getValue( 0 );
1074 typedef const Lang::Symbol ArgType;
1075 ArgType * val = dynamic_cast< ArgType * >( untypedVal.getPtr( ) );
1076 if( val == 0 )
1078 throw Exceptions::TypeMismatch( expr_->loc( ), untypedVal->getTypeName( ), ArgType::staticTypeName( ) );
1080 if( val->isUnique( ) )
1082 throw Exceptions::OutOfRange( expr_->loc( ), strrefdup( "Unique symbols can't denote variables." ) );
1085 RefCountPtr< const Ast::SearchContext > searchContext( new Ast::SearchContext( lexicalPath_, RefCountPtr< const char >( NullPtr< const char >( ) ) ) );
1086 Kernel::Environment::LexicalKey key = analysisEnv_->findLexicalVariableKey( loc_, Ast::Identifier( searchContext, Ast::NamespaceReference::RELATIVE, EMPTY_RELATIVE_PATH, val->name( ).getPtr( ) ) );
1088 Kernel::PassedEnv env = evalState->env_;
1089 env->lookup( key, evalState );
1093 Ast::DefineVariable::DefineVariable( const Ast::SourceLocation & idLoc, const Ast::PlacedIdentifier * id, Ast::Expression * expr, size_t ** idPos )
1094 : Ast::BindNode( Ast::SourceLocation( idLoc, expr->loc( ) ), idLoc, id ), expr_( expr ), idPos_( idPos )
1097 Ast::DefineVariable::~DefineVariable( )
1099 delete expr_;
1101 /* idPos_ is shared and will be a memory leak which must not be deleted.
1102 * It would be easy to fix the leak using RefCountPtr< size_t >, but the leakage is constant space, so silly efficiency is prioritized.
1106 void
1107 Ast::DefineVariable::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1109 Ast::StateIDSet freeStates;
1110 expr_->analyze( this, env, & freeStates );
1111 if( ! freeStates.empty( ) )
1113 Ast::Force * forcedExpr( new Ast::Force( loc_, expr_ ) );
1114 /* The forcedExpr should not be analyzed since the contained expr_ is already
1115 * analyzed, and analyzing forcedExpr would just cause expr_ to be analyzed again.
1116 * Instead, we just need to update parent/child links.
1118 expr_->changeParent( forcedExpr );
1119 forcedExpr->setParent( this, env );
1120 expr_ = forcedExpr;
1121 for( Ast::StateIDSet::const_iterator i = freeStates.begin( ); i != freeStates.end( ); ++i )
1123 freeStatesDst->insert( *i );
1126 if( *idPos_ == 0 )
1128 *idPos_ = new size_t( env->findLocalVariablePosition( idLoc_, *id_ ) );
1132 void
1133 Ast::DefineVariable::initializeEnvironment( Kernel::PassedEnv env, Kernel::PassedDyn dyn ) const
1135 env->define( **idPos_,
1136 Kernel::VariableHandle( new Kernel::Variable( new Kernel::Thunk( env, dyn, expr_ ) ) ) );
1139 void
1140 Ast::DefineVariable::evalHelper( Kernel::EvalState * evalState ) const
1142 if( expr_->immediate_ ){
1143 Kernel::VariableHandle var = evalState->env_->getVarHandle( **idPos_ );
1144 /* Using sufficient but not necessary condition for recognizing that the thunk
1145 * set up in initializeEnvironment is still not forced. The worst thing that
1146 * can happen is that another thunk for this expression, but in another environment
1147 * or another dynamic environment, is forced. If that happens, note that
1148 * expr_->immediate_ also applies to the other thunk, so it should be forced sooner or
1149 * later anywhay.
1151 if( var->isThunk( expr_ ) ){
1152 evalState->cont_ = Kernel::ContRef( new Kernel::IgnoreContinuation( evalState->cont_, expr_->loc( ) ) );
1153 var->force( var, evalState );
1154 return;
1158 Kernel::ContRef cont = evalState->cont_;
1159 cont->takeHandle( Kernel::THE_VOID_VARIABLE, evalState );
1163 Ast::DefineAlias::DefineAlias( const Ast::SourceLocation & idLoc, const Ast::SourceLocation & expansionLoc, const Ast::PlacedIdentifier * id, const Ast::NamespaceReference & expansion )
1164 : Ast::Node( idLoc ), idLoc_( idLoc ), id_( id ), expansion_( expansion ), expansionLoc_( expansionLoc )
1167 Ast::DefineAlias::~DefineAlias( )
1169 delete id_;
1172 void
1173 Ast::DefineAlias::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1175 throw Exceptions::InternalError( "Ast::DefineAlias::analyze_impl: Alias definitions should not be present at program analysis." );
1178 Ast::LexicalVariableLocationExpr::LexicalVariableLocationExpr( const Ast::SourceLocation & idLoc, const Ast::Identifier * id, Kind kind )
1179 : Ast::Expression( idLoc ), id_( id ), kind_( kind ), value_( NullPtr< const Lang::Value >( ) )
1181 immediate_ = true;
1184 Ast::LexicalVariableLocationExpr::~LexicalVariableLocationExpr( )
1187 void
1188 Ast::LexicalVariableLocationExpr::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1190 Kernel::Environment::LexicalKey key = Kernel::Environment::LexicalKey( env->findLexicalVariableKey( loc_, *id_ ) );
1191 if( key.isMissing( ) ){
1192 /* If the variable wasn't found, compilation will be terminated after the analysis sweep, and there's
1193 * no point in trying to assign something meaningless to value_.
1195 return;
1198 switch( kind_ )
1200 case INDEX:
1201 value_ = Kernel::ValueRef( new Lang::Integer( key.pos_ ) );
1202 break;
1203 case DEPTH:
1204 value_ = Kernel::ValueRef( new Lang::Integer( key.up_ ) );
1205 break;
1206 case ABSID:
1208 Ast::PlacedIdentifier idPlaced( env->reverseMapLexicalVariable( key ) );
1209 std::ostringstream oss;
1210 oss << Interaction::NAMESPACE_SEPARATOR ;
1211 idPlaced.show( oss, Ast::Identifier::VARIABLE );
1212 value_ = Kernel::ValueRef( new Lang::String( strrefdup( oss ) ) );
1214 break;
1218 void
1219 Ast::LexicalVariableLocationExpr::eval( Kernel::EvalState * evalState ) const
1221 Kernel::ContRef cont = evalState->cont_;
1222 cont->takeValue( value_, evalState );
1226 Ast::LexicalVariableNameExpr::LexicalVariableNameExpr( const Ast::SourceLocation & loc )
1227 : Ast::Expression( loc ), value_( NullPtr< const Lang::Value >( ) )
1229 immediate_ = true;
1232 Ast::LexicalVariableNameExpr::~LexicalVariableNameExpr( )
1235 void
1236 Ast::LexicalVariableNameExpr::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1238 Ast::Node * n = parent->parent( );
1239 while( n != 0 )
1241 Ast::BindNode * bn = dynamic_cast< Ast::DefineVariable * >( n );
1242 if( bn != 0 )
1244 std::ostringstream os;
1245 bn->id( )->show( os, Ast::Identifier::VARIABLE );
1246 value_ = Kernel::ValueRef( new Lang::String( strrefdup( os ) ) );
1247 return;
1249 n = n->parent( );
1251 Ast::theAnalysisErrorsList.push_back( new Exceptions::MiscellaneousStaticInconsistency( loc( ), strrefdup( "Cannot retrieve variable name, since the location is not inside a binding's right hand side." ) ) );
1254 void
1255 Ast::LexicalVariableNameExpr::eval( Kernel::EvalState * evalState ) const
1257 Kernel::ContRef cont = evalState->cont_;
1258 cont->takeValue( value_, evalState );
1262 Kernel::AssertStructureContinuation::AssertStructureContinuation( const Kernel::ContRef & cont, const Ast::SourceLocation & traceLoc )
1263 : Kernel::Continuation( traceLoc ), cont_( cont )
1266 Kernel::AssertStructureContinuation::~AssertStructureContinuation( )
1269 void
1270 Kernel::AssertStructureContinuation::takeValue( const RefCountPtr< const Lang::Value > & val, Kernel::EvalState * evalState, bool dummy ) const
1272 evalState->cont_ = cont_;
1273 cont_->takeValue( Helpers::down_cast_ContinuationArgument< const Lang::Structure >( val, this ), evalState );
1276 Kernel::ContRef
1277 Kernel::AssertStructureContinuation::up( ) const
1279 return cont_;
1282 RefCountPtr< const char >
1283 Kernel::AssertStructureContinuation::description( ) const
1285 return strrefdup( "Assert type is struct" );
1288 void
1289 Kernel::AssertStructureContinuation::gcMark( Kernel::GCMarkedSet & marked )
1291 cont_->gcMark( marked );
1295 Ast::StructSplitReference::StructSplitReference( Ast::SourceLocation fieldLoc, const char * fieldId, Ast::Expression * defaultExpr )
1296 : Ast::Expression( fieldLoc ),
1297 structLoc_( Ast::THE_UNKNOWN_LOCATION ), // This is a dummy value! The correct value is set later.
1298 fieldId_( fieldId ),
1299 defaultExpr_( defaultExpr )
1302 Ast::StructSplitReference::StructSplitReference( Ast::SourceLocation fieldLoc, size_t fieldPos, Ast::Expression * defaultExpr )
1303 : Ast::Expression( fieldLoc ),
1304 structLoc_( Ast::THE_UNKNOWN_LOCATION ), // This is a dummy value! The correct value is set later.
1305 fieldId_( 0 ), fieldPos_( fieldPos ),
1306 defaultExpr_( defaultExpr )
1309 Ast::StructSplitReference::~StructSplitReference( )
1311 if( fieldId_ != 0 )
1313 delete fieldId_;
1315 if( defaultExpr_ != 0 )
1317 delete defaultExpr_;
1321 void
1322 Ast::StructSplitReference::setStruct( Ast::SourceLocation structLoc, size_t ** structPos )
1324 structLoc_ = structLoc;
1325 structPos_ = structPos;
1328 void
1329 Ast::StructSplitReference::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1331 if( defaultExpr_ != 0 )
1333 defaultExpr_->analyze( this, env, freeStatesDst );
1337 void
1338 Ast::StructSplitReference::eval( Kernel::EvalState * evalState ) const
1340 Kernel::VariableHandle structHandle = evalState->env_->getVarHandle( **structPos_ );
1341 typedef const Lang::Structure StructType;
1342 RefCountPtr< StructType > structVal = structHandle->getVal< StructType >( "Type-checked value in StructSplitReference::eval." );
1344 Kernel::ContRef cont = evalState->cont_;
1345 if( fieldId_ != 0 )
1349 cont->takeHandle( structVal->getField( fieldId_, structVal ),
1350 evalState );
1351 return;
1353 catch( const Exceptions::NonExistentMember & ball )
1355 if( defaultExpr_ == 0 )
1357 throw;
1359 // Never mind, we use the default instead. See below.
1362 else
1366 cont->takeHandle( structVal->getPosition( fieldPos_, structVal ),
1367 evalState );
1368 return;
1370 catch( const Exceptions::NonExistentPosition & ball )
1372 if( defaultExpr_ == 0 )
1374 throw;
1376 // Never mind, we use the default instead. See below.
1380 if( defaultExpr_ == 0 )
1382 throw Exceptions::InternalError( "Just about to use null pointer defaultExpr_ in StructSplitReference::eval." );
1384 evalState->expr_ = defaultExpr_;
1387 Ast::StructSplitSink::StructSplitSink( )
1388 : Ast::Expression( Ast::THE_UNKNOWN_LOCATION ), structLoc_( Ast::THE_UNKNOWN_LOCATION )
1391 Ast::StructSplitSink::~StructSplitSink( )
1394 void
1395 Ast::StructSplitSink::setStruct( Ast::SourceLocation structLoc, size_t ** structPos, size_t consumedArguments )
1397 structLoc_ = structLoc;
1398 structPos_ = structPos;
1399 consumedArguments_ = consumedArguments;
1402 void
1403 Ast::StructSplitSink::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1405 /* Nothing to do! */
1408 void
1409 Ast::StructSplitSink::eval( Kernel::EvalState * evalState ) const
1411 Kernel::VariableHandle structHandle = evalState->env_->getVarHandle( **structPos_ );
1412 typedef const Lang::Structure StructType;
1413 RefCountPtr< StructType > structVal = structHandle->getVal< StructType >( "Type-checked value in StructSplitReference::eval." );
1415 Kernel::ContRef cont = evalState->cont_;
1416 cont->takeValue( structVal->getSink( consumedArguments_ ),
1417 evalState );
1421 Ast::AssertNoSinkNeeded::AssertNoSinkNeeded( const Ast::SourceLocation & loc, size_t orderedCount, Ast::SourceLocation structLoc, size_t ** structPos )
1422 : Ast::Assertion( loc ), orderedCount_( orderedCount ), structLoc_( structLoc ), structPos_( structPos )
1425 Ast::AssertNoSinkNeeded::~AssertNoSinkNeeded( )
1428 void
1429 Ast::AssertNoSinkNeeded::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1431 /* immediate_ is already true by the inheritage from Ast::Assertion. */
1434 void
1435 Ast::AssertNoSinkNeeded::eval( Kernel::EvalState * evalState ) const
1437 Kernel::VariableHandle structHandle = evalState->env_->getVarHandle( **structPos_ );
1438 typedef const Lang::Structure StructType;
1439 RefCountPtr< StructType > structVal = structHandle->getVal< StructType >( "Type-checked value in StructSplitReference::eval." );
1441 if( structVal->argList_->orderedExprs_->size( ) > orderedCount_ )
1443 throw Exceptions::SinkRequired( loc_, orderedCount_, structVal->argList_->orderedExprs_->size( ) );
1446 Kernel::ContRef cont = evalState->cont_;
1447 cont->takeHandle( Kernel::THE_VOID_VARIABLE, evalState );
1450 size_t Ast::SplitDefineVariables::splitVarCount = 0;
1451 PtrOwner_back_Access< std::list< const Ast::PlacedIdentifier * > > Ast::SplitDefineVariables::mem;
1453 Ast::SplitDefineVariables::SplitDefineVariables( )
1454 : sinkDefine_( 0 ), sinkExpr_( 0 ), seenNamed_( false ), seenDefault_( false )
1456 std::ostringstream oss;
1457 oss << Kernel::SPLIT_VAR_PREFIX << splitVarCount ;
1458 splitVarId_ = new Ast::PlacedIdentifier( Lang::THE_CORE_NAMESPACE_PATH, strdup( oss.str( ).c_str( ) ) );
1459 mem.push_back( splitVarId_ );
1460 ++splitVarCount;
1463 Ast::PlacedIdentifier *
1464 Ast::SplitDefineVariables::newSplitVarId( ) const
1466 return splitVarId_->clone( );
1470 Ast::StateReference::StateReference( const Ast::SourceLocation & loc )
1471 : Ast::Node( loc )
1474 Ast::StateReference::~StateReference( )
1478 Ast::LexiographicState::LexiographicState( const Ast::SourceLocation & loc, const Ast::Identifier * id, Kernel::Environment::LexicalKey ** idKey )
1479 : Ast::StateReference( loc ), id_( id ), idKey_( idKey )
1482 Ast::LexiographicState::~LexiographicState( )
1484 delete id_;
1485 if( *idKey_ != 0 )
1487 delete *idKey_;
1489 delete idKey_; // This can be done only as long as this is not shared!
1492 void
1493 Ast::LexiographicState::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1495 /* The following lines is the ugly solution to the problem that the inherited parent_ and analysisEnv_
1496 * are not well defined for reused nodes. And nodes of this type are typically reused.
1497 * For this type of node, one _could_ refer to someParent_ and someAnalysisEnv_ instead, but probably,
1498 * it is a mistake to even try.
1500 someParent_ = parent_;
1501 parent_ = 0;
1502 someAnalysisEnv_ = analysisEnv_;
1503 analysisEnv_ = 0;
1505 if( *idKey_ == 0 )
1507 *idKey_ = new Kernel::Environment::LexicalKey( env->findLexicalStateKey( loc_, *id_, this ) );
1509 if( ! (*idKey_)->isMissing( ) )
1511 freeStatesDst->insert( env->getStateID( **idKey_ ) );
1515 Kernel::StateHandle
1516 Ast::LexiographicState::getHandle( Kernel::PassedEnv env, Kernel::PassedDyn dyn ) const
1518 return env->getStateHandle( **idKey_ );
1522 Ast::DynamicState::DynamicState( const Ast::SourceLocation & loc, const Ast::Identifier * id )
1523 : Ast::StateReference( loc ), id_( id ), idKey_( new Kernel::Environment::LexicalKey * ( 0 ) )
1526 Ast::DynamicState::~DynamicState( )
1528 delete id_;
1529 if( *idKey_ != 0 )
1531 delete *idKey_;
1533 delete idKey_; // This can be done only as long as this is not shared!
1536 void
1537 Ast::DynamicState::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1539 /* See comment in LexicalState::analyze_impl.
1541 someParent_ = parent_;
1542 parent_ = 0;
1543 someAnalysisEnv_ = analysisEnv_;
1544 analysisEnv_ = 0;
1546 /* It would make sense to check the reference and...
1547 * This might be overly conservative... but we really shouldn't support dynamic states anyway.
1549 freeStatesDst->insert( Ast::AnalysisEnvironment::getTheAnyStateID( ) );
1552 Kernel::StateHandle
1553 Ast::DynamicState::getHandle( Kernel::PassedEnv env, Kernel::PassedDyn dyn ) const
1555 throw Exceptions::NotImplemented( "Referencing dynamic states" );
1559 Ast::IntroduceState::IntroduceState( const Ast::SourceLocation & idLoc, const Ast::PlacedIdentifier * id, Ast::Expression * expr, size_t ** idPos )
1560 : Ast::BindNode( Ast::SourceLocation( idLoc, expr->loc( ) ), idLoc, id ), expr_( expr ), idPos_( idPos )
1563 Ast::IntroduceState::~IntroduceState( )
1565 delete expr_;
1567 /* idPos_ shared and will be a memory leak which must not be deleted.
1568 * It would be easy to fix the leak using RefCountPtr< size_t >, but the leakage is constant space, so silly efficiency is prioritized.
1573 void
1574 Ast::IntroduceState::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1576 expr_->analyze( this, env, freeStatesDst );
1578 if( *idPos_ == 0 ){
1579 *idPos_ = new size_t( env->findLocalStatePosition( idLoc_, *id_ ) );
1582 const Ast::Node * firstUse = env->getStateFirstUse( **idPos_ );
1583 if( firstUse != NULL ){
1584 Ast::theAnalysisErrorsList.push_back( new Exceptions::StateUninitializedUse( firstUse->loc( ), id_, this ) );
1587 stateID_ = env->getStateID( **idPos_ );
1588 freeStatesDst->insert( stateID_ );
1591 void
1592 Ast::IntroduceState::initializeEnvironment( Kernel::PassedEnv env, Kernel::PassedDyn dyn ) const
1594 /* Although it would be possible to insert some kind of thunk in the environment here,
1595 * it is not obvious that such a feature would be desirable. With such a feature, one
1596 * would be able to use a state before the place in the code where it is introduced:
1598 * •dst << ...
1599 * ...
1600 * •dst: newGroup
1601 * •dst;
1603 * This just seems awkward; this is a stateful program, and order generally matters -- this is
1604 * why use before declaration is considered illegal and treated as error already during
1605 * static analysis.
1609 void
1610 Ast::IntroduceState::evalHelper( Kernel::EvalState * evalState ) const
1612 evalState->cont_ = Kernel::ContRef( new Kernel::IntroduceStateContinuation( evalState->env_,
1613 *idPos_,
1614 evalState->cont_,
1615 expr_->loc( ) ) );
1616 evalState->expr_ = expr_;
1620 Ast::Insertion::Insertion( Ast::StateReference * stateRef, Ast::Expression * expr )
1621 : Ast::Expression( Ast::SourceLocation( stateRef->loc( ), expr->loc( ) ) ), stateRef_( stateRef ), expr_( expr )
1624 Ast::Insertion::~Insertion( )
1627 void
1628 Ast::Insertion::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1630 stateRef_->analyze( this, env, freeStatesDst ); /* This will always add something to the set of free states. */
1631 expr_->analyze( this, env, freeStatesDst );
1634 void
1635 Ast::Insertion::eval( Kernel::EvalState * evalState ) const
1637 evalState->cont_ = Kernel::ContRef( new Kernel::InsertionContinuation( stateRef_->getHandle( evalState->env_, evalState->dyn_ ),
1638 evalState->cont_,
1639 evalState->dyn_,
1640 expr_->loc( ) ) );
1641 evalState->expr_ = expr_;
1644 Ast::InsertionMutatorCall::InsertionMutatorCall( const Ast::SourceLocation & loc, Ast::Expression * expr )
1645 : Ast::Expression( loc ), expr_( expr )
1648 Ast::InsertionMutatorCall::~InsertionMutatorCall( )
1651 void
1652 Ast::InsertionMutatorCall::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1654 throw Exceptions::InternalError( loc_, "An InsertionMutatorCall was analyzed (the contained expression should have been extracted and replaced this object)." );
1657 void
1658 Ast::InsertionMutatorCall::eval( Kernel::EvalState * evalState ) const
1660 throw Exceptions::InternalError( loc_, "An InsertionMutatorCall was evaluated (the contained expression should have been extracted and replaced this object)." );
1664 Ast::Freeze::Freeze( const Ast::SourceLocation & idLoc, const Ast::PlacedIdentifier * id, size_t ** idPos )
1665 : Ast::Expression( idLoc ), id_( id ), idPos_( idPos )
1667 immediate_ = true;
1670 Ast::Freeze::~Freeze( )
1672 /* idPos shared and will be a memory leak which must not be deleted.
1673 * It would be easy to fix the leak using RefCountPtr< size_t >, but the leakage is constant space, so silly efficiency is prioritized.
1677 void
1678 Ast::Freeze::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1680 if( *idPos_ == 0 )
1682 *idPos_ = new size_t( env->findLocalStatePosition( loc( ), *id_ ) );
1685 freeStatesDst->insert( env->getStateID( **idPos_ ) );
1688 void
1689 Ast::Freeze::eval( Kernel::EvalState * evalState ) const
1691 evalState->env_->freeze( **idPos_, evalState, loc( ) );
1695 Ast::Peek::Peek( const Ast::SourceLocation & idLoc, Ast::StateReference * stateRef )
1696 : Ast::Expression( idLoc ), stateRef_( stateRef )
1698 immediate_ = true;
1701 Ast::Peek::~Peek( )
1703 /* idPos shared and will be a memory leak which must not be deleted.
1704 * It would be easy to fix the leak using RefCountPtr< size_t >, but the leakage is constant space, so silly efficiency is prioritized.
1708 void
1709 Ast::Peek::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1711 stateRef_->analyze( this, env, freeStatesDst ); /* This will always add something to the set of free states. */
1714 void
1715 Ast::Peek::eval( Kernel::EvalState * evalState ) const
1717 stateRef_->getHandle( evalState->env_, evalState->dyn_ )->peek( evalState, loc( ) );
1721 Ast::DynamicExpression::DynamicExpression( const Ast::SourceLocation & loc, Ast::Expression * expr )
1722 : Ast::Expression( loc ), expr_( expr )
1724 immediate_ = true;
1727 Ast::DynamicExpression::~DynamicExpression( )
1730 void
1731 Ast::DynamicExpression::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1733 Ast::StateIDSet * freeStates = new Ast::StateIDSet;
1734 expr_->analyze( this, env, freeStates );
1736 if( ! freeStates->empty( ) )
1738 Ast::theAnalysisErrorsList.push_back( new Exceptions::IllegalFreeStates( expr_->loc( ), freeStates, "dynamic expressions must be pure" ) );
1740 else
1742 delete freeStates;
1746 void
1747 Ast::DynamicExpression::eval( Kernel::EvalState * evalState ) const
1749 Kernel::ContRef cont = evalState->cont_;
1750 cont->takeValue( Kernel::ValueRef( new Lang::DynamicExpression( evalState->env_, expr_ ) ),
1751 evalState );
1755 Ast::LexiographicType::LexiographicType( const Ast::SourceLocation & loc, const Ast::Identifier * id, Kernel::Environment::LexicalKey ** idKey )
1756 : Ast::Expression( loc ), id_( id ), idKey_( idKey )
1758 immediate_ = true;
1761 Ast::LexiographicType::~LexiographicType( )
1763 delete id_;
1764 if( *idKey_ != 0 )
1766 delete *idKey_;
1768 delete idKey_; // This can be done only as long as this is not shared!
1771 void
1772 Ast::LexiographicType::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1774 if( *idKey_ == 0 )
1776 *idKey_ = new Kernel::Environment::LexicalKey( env->findLexicalTypeKey( loc_, *id_ ) );
1780 void
1781 Ast::LexiographicType::eval( Kernel::EvalState * evalState ) const
1783 evalState->env_->lookup( **idKey_, evalState );