Update procedures
[shapes.git] / source / astvar.cc
blob7bf7afdff88a7f9a63bf36932e268919828cc727
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, 2013, 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
328 std::list< Ast::Node * >::const_iterator next = pos;
329 ++next;
330 if( next == nodes_->end( ) ){
331 evalState->cont_ = info->cont_;
332 }else{
333 evalState->cont_ = Kernel::ContRef( new Kernel::CodeBracketContinuation( (*pos)->loc( ), info, next ) );
336 evalState->env_ = info->env_;
337 evalState->dyn_ = info->dyn_;
338 if( Ast::Expression * e = dynamic_cast< Ast::Expression * >( *pos ) ){
339 evalState->expr_ = e;
340 return;
342 if( const Ast::BindNode * bn = dynamic_cast< const Ast::BindNode * >( *pos ) ){
343 bn->evalHelper( evalState );
344 return;
346 throw Exceptions::InternalError( (*pos)->loc( ), "CodeBracket::evalAt: Node was neither Expression or BindNode." );
350 Kernel::CodeBracketContInfo::CodeBracketContInfo( const Ast::CodeBracket * bracketExpr, const Kernel::EvalState & evalState )
351 : bracketExpr_( bracketExpr ), env_( evalState.env_ ), dyn_( evalState.dyn_ ), cont_( evalState.cont_ )
354 Kernel::CodeBracketContInfo::~CodeBracketContInfo( )
357 void
358 Kernel::CodeBracketContInfo::gcMark( Kernel::GCMarkedSet & marked )
360 env_->gcMark( marked );
361 dyn_->gcMark( marked );
362 cont_->gcMark( marked );
365 Kernel::CodeBracketContinuation::CodeBracketContinuation( const Ast::SourceLocation & traceLoc, const RefCountPtr< const Kernel::CodeBracketContInfo > & info, const std::list< Ast::Node * >::const_iterator & pos )
366 : Kernel::Continuation( traceLoc ), info_( info ), pos_( pos )
369 Kernel::CodeBracketContinuation::~CodeBracketContinuation( )
372 void
373 Kernel::CodeBracketContinuation::takeValue( const RefCountPtr< const Lang::Value > & val, Kernel::EvalState * evalState, bool dummy ) const
375 if( val.down_cast< const Lang::Void >( ) == NullPtr< const Lang::Void >( ) )
377 throw Exceptions::NonVoidStatement( traceLoc_, val );
379 info_->bracketExpr_->evalAt( info_,
380 pos_,
381 evalState );
384 Kernel::ContRef
385 Kernel::CodeBracketContinuation::up( ) const
387 return info_->cont_;
390 RefCountPtr< const char >
391 Kernel::CodeBracketContinuation::description( ) const
393 return strrefdup( "code bracket" );
396 void
397 Kernel::CodeBracketContinuation::gcMark( Kernel::GCMarkedSet & marked )
399 const_cast< Kernel::CodeBracketContInfo * >( info_.getPtr( ) )->gcMark( marked );
403 Ast::LexiographicVariable::LexiographicVariable( const Ast::SourceLocation & loc, const Ast::Identifier * id, Kernel::Environment::LexicalKey ** idKey )
404 : Ast::Expression( loc ), id_( id ), idKey_( idKey )
406 immediate_ = true;
409 Ast::LexiographicVariable::~LexiographicVariable( )
411 delete id_;
412 if( *idKey_ != 0 )
414 delete *idKey_;
416 delete idKey_; /* This can be done only as long as this is not shared! */
419 void
420 Ast::LexiographicVariable::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
422 if( *idKey_ == 0 )
424 *idKey_ = new Kernel::Environment::LexicalKey( env->findLexicalVariableKey( loc_, *id_ ) );
426 scope_level_ = env->level( ) - (*idKey_)->up_;
429 void
430 Ast::LexiographicVariable::eval( Kernel::EvalState * evalState ) const
432 evalState->env_->lookup( **idKey_, evalState );
436 Ast::PrivateAliasVariable::PrivateAliasVariable( const Ast::SourceLocation & loc, const Ast::PlacedIdentifier & id, const RefCountPtr< const char > & privateName )
437 : Ast::Expression( loc ), id_( id ), privateName_( privateName ), aliasKey_( NULL )
439 immediate_ = true;
442 Ast::PrivateAliasVariable::~PrivateAliasVariable( )
444 /* Don't delete id_ -- it will be shared with the id_ of a DefineVariable. */
445 if( aliasKey_ != NULL ){
446 delete aliasKey_;
450 void
451 Ast::PrivateAliasVariable::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
453 aliasKey_ = new Kernel::Environment::LexicalKey( env->findPrivateAliasVariableKey( loc_, id_, privateName_.getPtr( ) ) );
456 void
457 Ast::PrivateAliasVariable::eval( Kernel::EvalState * evalState ) const
459 evalState->env_->lookup( *aliasKey_, evalState );
463 Ast::Force::Force( const Ast::SourceLocation & loc, Ast::Expression * expr )
464 : Ast::Expression( loc ), expr_( expr )
466 immediate_ = true;
469 Ast::Force::~Force( )
471 delete expr_;
474 void
475 Ast::Force::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
477 expr_->analyze( this, env, freeStatesDst );
480 void
481 Ast::Force::eval( Kernel::EvalState * evalState ) const
483 evalState->cont_ = Kernel::ContRef( new Kernel::ForcingContinuation( evalState->cont_, loc_ ) );
484 evalState->expr_ = expr_;
488 Ast::EvalOutsideExpr::EvalOutsideExpr( const Ast::SourceLocation & loc, Ast::Expression * expr )
489 : Ast::Expression( loc ), expr_( expr )
491 immediate_ = true;
494 Ast::EvalOutsideExpr::~EvalOutsideExpr( )
496 delete expr_;
499 void
500 Ast::EvalOutsideExpr::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
502 expr_->analyze( this, env->getParent( ), freeStatesDst );
505 void
506 Ast::EvalOutsideExpr::eval( Kernel::EvalState * evalState ) const
508 evalState->expr_ = expr_;
509 evalState->env_ = evalState->env_->getParent( );
513 Ast::MemberReferenceFunction::MemberReferenceFunction( const Ast::SourceLocation & loc, Ast::Expression * variable, const char * fieldID )
514 : Lang::Function( new Kernel::EvaluatedFormals( Ast::FileID::build_internal( "<>.<>" ), true ) ), loc_( loc, bool( ) ), variable_( variable ), fieldID_( fieldID )
517 Ast::MemberReferenceFunction::~MemberReferenceFunction( )
519 delete variable_;
520 delete fieldID_;
523 void
524 Ast::MemberReferenceFunction::push_exprs( Ast::ArgListExprs * args ) const
526 args->orderedExprs_->push_back( variable_ );
529 void
530 Ast::MemberReferenceFunction::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
532 /* The variable is analyzed as part of the arguments passed to this function, so nothing needs to be done here...
533 * unless we would be able to figure out the type of the argument, and then check if the field reference is valid.
537 void
538 Ast::MemberReferenceFunction::call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
540 Kernel::ContRef cont = evalState->cont_;
541 RefCountPtr< const Lang::Value > arg = args.getValue( 0 );
542 cont->takeHandle( arg->getField( fieldID_, arg ),
543 evalState );
548 Ast::MutatorReference::MutatorReference( const Ast::SourceLocation & mutatorLoc, Ast::StateReference * state, const char * mutatorID )
549 : Ast::Expression( mutatorLoc ), mutatorLoc_( mutatorLoc, bool( ) ), state_( state ), mutatorID_( mutatorID )
552 Ast::MutatorReference::~MutatorReference( )
554 /* At the time of implementing this bug-fix, state_ will allways be owned by the Ast::CallExpr that is also the owner of us.
555 * Hence, we do not consider ourselves owners. Perhaps one should have a flag indicating whether ownership is transferred
556 * when calling the constructor, but at the moment this seems like a waste of resources.
558 // delete state_;
559 delete mutatorID_;
562 void
563 Ast::MutatorReference::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
565 state_->analyze( this, env, freeStatesDst );
566 /* If the type of the state was known here, we should verify that there is a mutator corresponding to the message <mutatorID>.
570 void
571 Ast::MutatorReference::eval( Kernel::EvalState * evalState ) const
573 Kernel::ContRef cont = evalState->cont_;
574 cont->takeValue( state_->getHandle( evalState->env_, evalState->dyn_ )->getMutator( mutatorID_ ),
575 evalState );
580 Ast::SpecialLength::SpecialLength( const Ast::SourceLocation & loc, double val, int sort )
581 : Ast::Expression( loc ), val_( val ), sort_( sort )
584 Ast::SpecialLength::~SpecialLength( )
587 void
588 Ast::SpecialLength::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
590 /* Nothing to do! */
593 void
594 Ast::SpecialLength::eval( Kernel::EvalState * evalState ) const
596 Concrete::Length d;
597 double a0;
598 double a1;
600 evalState->dyn_->specialUnitService( & d, & a0, & a1 );
602 if( sort_ == Computation::SPECIALU_NOINFLEX )
604 Kernel::ContRef cont = evalState->cont_;
605 cont->takeValue( Kernel::ValueRef( new Lang::Length( val_ * d * Computation::specialUnitNoInflexion( a0, a1 ) ) ),
606 evalState );
607 return;
609 if( ! sort_ & Computation::SPECIALU_DIST )
611 throw Exceptions::InternalError( strrefdup( "The special unit is neither based on inflexion or distance" ) );
614 double res = 1;
616 if( sort_ & Computation::SPECIALU_CIRC )
618 res *= Computation::specialUnitCircleHandle( a0 );
621 if( sort_ & Computation::SPECIALU_CORR )
623 res *= Computation::specialUnitCorrection( a0, a1 );
626 if( sort_ & Computation::SPECIALU_NOINFLEX )
628 res = min( res, Computation::specialUnitNoInflexion( a0, a1 ) );
630 Kernel::ContRef cont = evalState->cont_;
631 cont->takeValue( Kernel::ValueRef( new Lang::Length( val_ * d * res ) ),
632 evalState );
636 Ast::DynamicVariable::DynamicVariable( const Ast::SourceLocation & loc, const Ast::Identifier * id )
637 : Ast::Expression( loc ), id_( id ), idKey_( new Kernel::Environment::LexicalKey * ( 0 ) )
639 immediate_ = true;
642 Ast::DynamicVariable::~DynamicVariable( )
644 delete id_;
645 if( *idKey_ != 0 )
647 delete *idKey_;
649 delete idKey_; // This can be done only as long as this is not shared!
652 void
653 Ast::DynamicVariable::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
655 if( *idKey_ == 0 )
657 *idKey_ = new Kernel::Environment::LexicalKey( env->findLexicalDynamicKey( loc_, *id_ ) );
661 void
662 Ast::DynamicVariable::eval( Kernel::EvalState * evalState ) const
664 const Kernel::DynamicVariableProperties & dynProps = evalState->env_->lookupDynamicVariable( **idKey_ );
666 Kernel::VariableHandle res = dynProps.fetch( evalState->dyn_ );
668 /* Now, we know that if the value was bound to a dynamic expression, a value was bound, and that value has
669 * a certain type.
671 if( ! res->isThunk( ) )
675 typedef const Lang::DynamicExpression DynType;
676 RefCountPtr< DynType > dynVal = res->tryVal< DynType >( );
677 dynVal->evalHelper( evalState );
678 return;
680 catch( const NonLocalExit::NotThisType & ball )
682 /* Never mind. */
686 Kernel::ContRef cont = evalState->cont_;
687 cont->takeHandle( res,
688 evalState );
692 Kernel::DynamicBindingContinuation::DynamicBindingContinuation( const Ast::SourceLocation & traceLoc, const Kernel::PassedEnv & env, const Kernel::Environment::LexicalKey & key, const Ast::DynamicBindingExpression * bindingExpr, const Kernel::ContRef & cont )
693 : Kernel::Continuation( traceLoc ), env_( env ), key_( key ), bindingExpr_( bindingExpr ), cont_( cont )
696 Kernel::DynamicBindingContinuation::~DynamicBindingContinuation( )
699 void
700 Kernel::DynamicBindingContinuation::takeHandle( Kernel::VariableHandle val, Kernel::EvalState * evalState, bool dummy ) const
702 if( val->isThunk( ) )
704 val->force( val, evalState );
705 return;
707 evalState->cont_ = cont_;
708 env_->lookupDynamicVariable( key_ ).makeBinding( val, bindingExpr_, evalState );
711 Kernel::ContRef
712 Kernel::DynamicBindingContinuation::up( ) const
714 return cont_;
717 RefCountPtr< const char >
718 Kernel::DynamicBindingContinuation::description( ) const
720 return strrefdup( "dynamic binding" );
723 void
724 Kernel::DynamicBindingContinuation::gcMark( Kernel::GCMarkedSet & marked )
726 env_->gcMark( marked );
727 cont_->gcMark( marked );
730 Ast::DynamicBindingExpression::DynamicBindingExpression( const Ast::SourceLocation & idLoc, const Ast::Identifier * id, Ast::Expression * expr, Kernel::Environment::LexicalKey ** idKey )
731 : Ast::Expression( idLoc, expr->loc( ) ), idLoc_( idLoc, bool( ) ), id_( id ), expr_( expr ), idKey_( new Kernel::Environment::LexicalKey * ( 0 ) )
734 Ast::DynamicBindingExpression::~DynamicBindingExpression( )
736 delete id_;
737 delete expr_;
738 if( *idKey_ != 0 )
740 delete *idKey_;
741 *idKey_ = 0;
743 // Don't delete idKey as it's shared!
746 void
747 Ast::DynamicBindingExpression::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
749 expr_->analyze( this, env, freeStatesDst );
750 if( *idKey_ == 0 )
752 *idKey_ = new Kernel::Environment::LexicalKey( env->findLexicalDynamicKey( idLoc_, *id_ ) );
756 void
757 Ast::DynamicBindingExpression::eval( Kernel::EvalState * evalState ) const
759 const Kernel::DynamicVariableProperties & dynProps = evalState->env_->lookupDynamicVariable( **idKey_ );
761 if( dynProps.forceValue( ) || expr_->immediate_ )
763 evalState->expr_ = expr_;
764 evalState->cont_ = Kernel::ContRef( new Kernel::DynamicBindingContinuation( expr_->loc( ), evalState->env_, **idKey_, this, evalState->cont_ ) );
766 else
768 dynProps.makeBinding( Kernel::VariableHandle( new Kernel::Variable( new Kernel::Thunk( evalState->env_, evalState->dyn_, expr_ ) ) ),
769 this,
770 evalState );
775 Ast::DynamicStateBindingExpression::DynamicStateBindingExpression( const Ast::SourceLocation & loc, const Ast::SourceLocation & dstLoc, const Ast::Identifier * dstId, Ast::StateReference * src )
776 : Ast::Expression( loc ), dstLoc_( dstLoc, bool( ) ), dstId_( dstId ), dstIdKey_( new Kernel::Environment::LexicalKey * ( 0 ) ), src_( src )
779 Ast::DynamicStateBindingExpression::~DynamicStateBindingExpression( )
781 delete src_;
782 if( *dstIdKey_ != 0 )
784 delete *dstIdKey_;
786 delete dstIdKey_; // This can be done only as long as this is not shared!
789 void
790 Ast::DynamicStateBindingExpression::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
792 if( *dstIdKey_ == 0 )
794 *dstIdKey_ = new Kernel::Environment::LexicalKey( env->findLexicalDynamicKey( dstLoc_, *dstId_ ) );
798 void
799 Ast::DynamicStateBindingExpression::eval( Kernel::EvalState * evalState ) const
801 const Kernel::DynamicStateProperties & dstDynProps = evalState->env_->lookupDynamicState( **dstIdKey_ );
803 dstDynProps.makeBinding( src_->getHandle( evalState->env_, evalState->dyn_ ), this, evalState );
807 Kernel::WithDynamicContinuation::WithDynamicContinuation( const Ast::SourceLocation & traceLoc, Ast::Expression * expr, const Kernel::EvalState & evalState )
808 : Kernel::Continuation( traceLoc ), expr_( expr ), env_( evalState.env_ ), dyn_( evalState.dyn_ ), cont_( evalState.cont_ )
811 Kernel::WithDynamicContinuation::~WithDynamicContinuation( )
814 void
815 Kernel::WithDynamicContinuation::takeValue( const RefCountPtr< const Lang::Value > & val, Kernel::EvalState * evalState, bool dummy ) const
817 evalState->dyn_ = Kernel::PassedDyn( new Kernel::DynamicEnvironment( dyn_, *Helpers::down_cast< const Lang::DynamicBindings >( val, traceLoc_ ) ) );
818 evalState->env_ = env_;
819 evalState->expr_ = expr_;
820 evalState->cont_ = cont_;
823 Kernel::ContRef
824 Kernel::WithDynamicContinuation::up( ) const
826 return cont_;
829 RefCountPtr< const char >
830 Kernel::WithDynamicContinuation::description( ) const
832 return strrefdup("with dynamic bindings" );
835 void
836 Kernel::WithDynamicContinuation::gcMark( Kernel::GCMarkedSet & marked )
838 env_->gcMark( marked );
839 dyn_->gcMark( marked );
840 cont_->gcMark( marked );
844 Ast::WithDynamicExpr::WithDynamicExpr( const Ast::SourceLocation & loc, Ast::Expression * bindings, Ast::Expression * expr )
845 : Ast::Expression( loc ), bindings_( bindings ), expr_( expr )
848 Ast::WithDynamicExpr::~WithDynamicExpr( )
851 void
852 Ast::WithDynamicExpr::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
854 bindings_->analyze( this, env, freeStatesDst );
855 expr_->analyze( this, env, freeStatesDst );
858 void
859 Ast::WithDynamicExpr::eval( Kernel::EvalState * evalState ) const
861 evalState->expr_ = bindings_;
862 evalState->cont_ = Kernel::ContRef( new Kernel::WithDynamicContinuation( bindings_->loc( ), expr_, *evalState ) );
866 Ast::DynamicVariableDecl::DynamicVariableDecl( const Ast::SourceLocation & loc, const Ast::SourceLocation & idLoc, const Ast::PlacedIdentifier * id, Ast::Expression * filterExpr, Ast::Expression * defaultExpr )
867 : Ast::BindNode( loc, idLoc, id ), idPos_( new size_t * ( 0 ) )
869 /* This type of expression is an Ast::BindNode so that it is easy to recognize and extract the identifier for static analysis
870 * and similar tasks.
872 * The expression is implemented as a function call, since there are two subexpressions that may need evaluation.
875 Ast::ArgListExprs * args = new Ast::ArgListExprs( false );
876 Ast::DynamicVariableDeclFunction * res = new Ast::DynamicVariableDeclFunction( id, filterExpr, defaultExpr, idPos_ );
877 res->push_exprs( args );
878 Ast::CallExpr * callExpr =
879 new Ast::CallExpr( loc,
880 RefCountPtr< const Lang::Function >( res ),
881 args );
882 /* Wrap the call in Ast::Force as a poor substitute for doing the right thing, see comment in initializeEnvironment. */
883 impl_ = new Ast::Force( loc, callExpr );
886 Ast::DynamicVariableDecl::~DynamicVariableDecl( )
889 void
890 Ast::DynamicVariableDecl::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
892 impl_->analyze( this, env, freeStatesDst );
893 if( *idPos_ == 0 ){
894 *idPos_ = new size_t( env->findLocalDynamicPosition( idLoc_, *id_ ) );
898 void
899 Ast::DynamicVariableDecl::initializeEnvironment( Kernel::PassedEnv env, Kernel::PassedDyn dyn ) const
901 /* Here, the right thing to do is probably to put the impl_ call in a DynamicVariableProperties thunk, but
902 * that type of thunk is not invented yet.
904 * As a poor substitute for the right thing, the impl_ call is wrapped in Ast::Force, see contructor.
908 void
909 Ast::DynamicVariableDecl::evalHelper( Kernel::EvalState * evalState ) const
911 evalState->expr_ = impl_;
915 Ast::DynamicVariableDeclFunction::DynamicVariableDeclFunction( const Ast::PlacedIdentifier * id, Ast::Expression * filterExpr, Ast::Expression * defaultExpr, size_t ** idPos )
916 : Lang::Function( new Kernel::EvaluatedFormals( Ast::FileID::build_internal( "< dynamic variable declaration >" ) ) ), id_( id ), filterExpr_( filterExpr ), defaultExpr_( defaultExpr ), idPos_( idPos )
918 formals_->appendEvaluatedCoreFormal( "filter", Kernel::THE_SLOT_VARIABLE, true );
919 formals_->appendEvaluatedCoreFormal( "default", Kernel::THE_SLOT_VARIABLE, false );
922 Ast::DynamicVariableDeclFunction::~DynamicVariableDeclFunction( )
924 delete filterExpr_;
925 delete defaultExpr_;
928 void
929 Ast::DynamicVariableDeclFunction::push_exprs( Ast::ArgListExprs * args ) const
931 args->orderedExprs_->push_back( filterExpr_ );
932 args->orderedExprs_->push_back( defaultExpr_ );
935 void
936 Ast::DynamicVariableDeclFunction::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
938 /* The analysis is carried out by the DynamicVariableDecl expression.
942 void
943 Ast::DynamicVariableDeclFunction::call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
945 static const char * title = "< dynamic variable declaration >";
946 typedef const Lang::Function FilterType;
947 evalState->env_->defineDynamic( id_,
948 **idPos_,
949 Helpers::down_cast_SyntaxArgument< FilterType >( title, args, 0, callLoc ),
950 args.getHandle( 1 ) );
952 Kernel::ContRef cont = evalState->cont_;
953 cont->takeHandle( Kernel::THE_VOID_VARIABLE,
954 evalState );
958 Ast::DynamicStateDecl::DynamicStateDecl( const Ast::SourceLocation & loc, const Ast::SourceLocation & idLoc, const Ast::PlacedIdentifier * id, Ast::StateReference * defaultState, size_t ** idPos )
959 : Ast::BindNode( loc, idLoc, id ), idPos_( idPos ), defaultState_( defaultState )
962 Ast::DynamicStateDecl::~DynamicStateDecl( )
966 void
967 Ast::DynamicStateDecl::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
969 if( *idPos_ == 0 )
971 *idPos_ = new size_t( env->findLocalDynamicStatePosition( idLoc_, *id_ ) );
975 void
976 Ast::DynamicStateDecl::initializeEnvironment( Kernel::PassedEnv env, Kernel::PassedDyn dyn ) const
978 env->defineDynamicState( id_, **idPos_, env, dyn, defaultState_ );
981 void
982 Ast::DynamicStateDecl::evalHelper( Kernel::EvalState * evalState ) const
984 Kernel::ContRef cont = evalState->cont_;
985 cont->takeHandle( Kernel::THE_VOID_VARIABLE,
986 evalState );
990 Ast::EvalSymbolFunction::EvalSymbolFunction( const Ast::SourceLocation & loc, Ast::Expression * expr, const RefCountPtr< const Ast::NamespacePath > & lexicalPath )
991 : Lang::Function( new Kernel::EvaluatedFormals( Ast::FileID::build_internal( "< symbol evaluation >" ), true ) ), loc_( loc, bool( ) ), expr_( expr ), lexicalPath_( lexicalPath )
994 Ast::EvalSymbolFunction::~EvalSymbolFunction( )
996 delete expr_;
999 void
1000 Ast::EvalSymbolFunction::push_exprs( Ast::ArgListExprs * args ) const
1002 args->orderedExprs_->push_back( expr_ );
1005 void
1006 Ast::EvalSymbolFunction::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1008 analysisEnv_ = env;
1010 /* expr_ shall be analyzed from the calling expression.
1011 * Here, it is only used to locate errors.
1015 void
1016 Ast::EvalSymbolFunction::call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1018 static const RefCountPtr< const Ast::NamespacePath > EMPTY_RELATIVE_PATH( new Ast::NamespacePath( ) );
1020 RefCountPtr< const Lang::Value > untypedVal = args.getValue( 0 );
1021 typedef const Lang::Symbol ArgType;
1022 ArgType * val = dynamic_cast< ArgType * >( untypedVal.getPtr( ) );
1023 if( val == 0 )
1025 throw Exceptions::TypeMismatch( expr_->loc( ), untypedVal->getTypeName( ), ArgType::staticTypeName( ) );
1027 if( val->isUnique( ) )
1029 throw Exceptions::OutOfRange( expr_->loc( ), strrefdup( "Unique symbols can't denote variables." ) );
1032 RefCountPtr< const Ast::SearchContext > searchContext( new Ast::SearchContext( lexicalPath_, RefCountPtr< const char >( NullPtr< const char >( ) ) ) );
1033 Kernel::Environment::LexicalKey key = analysisEnv_->findLexicalVariableKey( loc_, Ast::Identifier( searchContext, Ast::NamespaceReference::RELATIVE, EMPTY_RELATIVE_PATH, val->name( ).getPtr( ) ) );
1035 Kernel::PassedEnv env = evalState->env_;
1036 env->lookup( key, evalState );
1040 Ast::DefineVariable::DefineVariable( const Ast::SourceLocation & idLoc, const Ast::PlacedIdentifier * id, Ast::Expression * expr, size_t ** idPos )
1041 : Ast::BindNode( idLoc, expr->loc( ), idLoc, id ), expr_( expr ), idPos_( idPos )
1044 Ast::DefineVariable::~DefineVariable( )
1046 delete expr_;
1048 /* idPos_ is shared and will be a memory leak which must not be deleted.
1049 * It would be easy to fix the leak using RefCountPtr< size_t >, but the leakage is constant space, so silly efficiency is prioritized.
1053 void
1054 Ast::DefineVariable::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1056 Ast::StateIDSet freeStates;
1057 expr_->analyze( this, env, & freeStates );
1058 if( ! freeStates.empty( ) )
1060 Ast::Force * forcedExpr( new Ast::Force( loc_, expr_ ) );
1061 /* The forcedExpr should not be analyzed since the contained expr_ is already
1062 * analyzed, and analyzing forcedExpr would just cause expr_ to be analyzed again.
1063 * Instead, we just need to update parent/child links.
1065 expr_->changeParent( forcedExpr );
1066 forcedExpr->setParent( this, env );
1067 expr_ = forcedExpr;
1068 for( Ast::StateIDSet::const_iterator i = freeStates.begin( ); i != freeStates.end( ); ++i )
1070 freeStatesDst->insert( *i );
1073 if( *idPos_ == 0 )
1075 *idPos_ = new size_t( env->findLocalVariablePosition( idLoc_, *id_ ) );
1079 void
1080 Ast::DefineVariable::initializeEnvironment( Kernel::PassedEnv env, Kernel::PassedDyn dyn ) const
1082 env->define( **idPos_,
1083 Kernel::VariableHandle( new Kernel::Variable( new Kernel::Thunk( env, dyn, expr_ ) ) ) );
1086 void
1087 Ast::DefineVariable::evalHelper( Kernel::EvalState * evalState ) const
1089 if( expr_->immediate_ ){
1090 Kernel::VariableHandle var = evalState->env_->getVarHandle( **idPos_ );
1091 /* Using sufficient but not necessary condition for recognizing that the thunk
1092 * set up in initializeEnvironment is still not forced. The worst thing that
1093 * can happen is that another thunk for this expression, but in another environment
1094 * or another dynamic environment, is forced. If that happens, note that
1095 * expr_->immediate_ also applies to the other thunk, so it should be forced sooner or
1096 * later anywhay.
1098 if( var->isThunk( expr_ ) ){
1099 evalState->cont_ = Kernel::ContRef( new Kernel::IgnoreContinuation( evalState->cont_, expr_->loc( ) ) );
1100 var->force( var, evalState );
1101 return;
1105 Kernel::ContRef cont = evalState->cont_;
1106 cont->takeHandle( Kernel::THE_VOID_VARIABLE, evalState );
1110 Ast::DefineAlias::DefineAlias( const Ast::SourceLocation & idLoc, const Ast::SourceLocation & expansionLoc, const Ast::PlacedIdentifier * id, const Ast::NamespaceReference & expansion )
1111 : Ast::Node( idLoc ), idLoc_( idLoc, bool( ) ), id_( id ), expansion_( expansion ), expansionLoc_( expansionLoc, bool( ) )
1114 Ast::DefineAlias::~DefineAlias( )
1116 delete id_;
1119 void
1120 Ast::DefineAlias::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1122 throw Exceptions::InternalError( "Ast::DefineAlias::analyze_impl: Alias definitions should not be present at program analysis." );
1125 Ast::LexicalVariableLocationExpr::LexicalVariableLocationExpr( const Ast::SourceLocation & idLoc, const Ast::Identifier * id, Kind kind )
1126 : Ast::Expression( idLoc ), id_( id ), kind_( kind ), value_( NullPtr< const Lang::Value >( ) )
1128 immediate_ = true;
1131 Ast::LexicalVariableLocationExpr::~LexicalVariableLocationExpr( )
1134 void
1135 Ast::LexicalVariableLocationExpr::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1137 Kernel::Environment::LexicalKey key = Kernel::Environment::LexicalKey( env->findLexicalVariableKey( loc_, *id_ ) );
1138 if( key.isMissing( ) ){
1139 /* If the variable wasn't found, compilation will be terminated after the analysis sweep, and there's
1140 * no point in trying to assign something meaningless to value_.
1142 return;
1145 switch( kind_ )
1147 case INDEX:
1148 value_ = Kernel::ValueRef( new Lang::Integer( key.pos_ ) );
1149 break;
1150 case DEPTH:
1151 value_ = Kernel::ValueRef( new Lang::Integer( key.up_ ) );
1152 break;
1153 case ABSID:
1155 Ast::PlacedIdentifier idPlaced( env->reverseMapLexicalVariable( key ) );
1156 std::ostringstream oss;
1157 oss << Interaction::NAMESPACE_SEPARATOR ;
1158 idPlaced.show( oss, Ast::Identifier::VARIABLE );
1159 value_ = Kernel::ValueRef( new Lang::String( strrefdup( oss ) ) );
1161 break;
1165 void
1166 Ast::LexicalVariableLocationExpr::eval( Kernel::EvalState * evalState ) const
1168 Kernel::ContRef cont = evalState->cont_;
1169 cont->takeValue( value_, evalState );
1173 Ast::LexicalVariableNameExpr::LexicalVariableNameExpr( const Ast::SourceLocation & loc )
1174 : Ast::Expression( loc ), value_( NullPtr< const Lang::Value >( ) )
1176 immediate_ = true;
1179 Ast::LexicalVariableNameExpr::~LexicalVariableNameExpr( )
1182 void
1183 Ast::LexicalVariableNameExpr::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1185 Ast::Node * n = parent->parent( );
1186 while( n != 0 )
1188 Ast::BindNode * bn = dynamic_cast< Ast::DefineVariable * >( n );
1189 if( bn != 0 )
1191 std::ostringstream os;
1192 bn->id( )->show( os, Ast::Identifier::VARIABLE );
1193 value_ = Kernel::ValueRef( new Lang::String( strrefdup( os ) ) );
1194 return;
1196 n = n->parent( );
1198 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." ) ) );
1201 void
1202 Ast::LexicalVariableNameExpr::eval( Kernel::EvalState * evalState ) const
1204 Kernel::ContRef cont = evalState->cont_;
1205 cont->takeValue( value_, evalState );
1209 Kernel::AssertStructureContinuation::AssertStructureContinuation( const Kernel::ContRef & cont, const Ast::SourceLocation & traceLoc )
1210 : Kernel::Continuation( traceLoc ), cont_( cont )
1213 Kernel::AssertStructureContinuation::~AssertStructureContinuation( )
1216 void
1217 Kernel::AssertStructureContinuation::takeValue( const RefCountPtr< const Lang::Value > & val, Kernel::EvalState * evalState, bool dummy ) const
1219 evalState->cont_ = cont_;
1220 cont_->takeValue( Helpers::down_cast_ContinuationArgument< const Lang::Structure >( val, this ), evalState );
1223 Kernel::ContRef
1224 Kernel::AssertStructureContinuation::up( ) const
1226 return cont_;
1229 RefCountPtr< const char >
1230 Kernel::AssertStructureContinuation::description( ) const
1232 return strrefdup( "Assert type is struct" );
1235 void
1236 Kernel::AssertStructureContinuation::gcMark( Kernel::GCMarkedSet & marked )
1238 cont_->gcMark( marked );
1242 Ast::StructSplitReference::StructSplitReference( const Ast::SourceLocation & fieldLoc, const char * fieldId, Ast::Expression * defaultExpr )
1243 : Ast::Expression( fieldLoc ),
1244 structLoc_( Ast::THE_UNKNOWN_LOCATION, bool( ) ), // This is a dummy value! The correct value is set later.
1245 fieldId_( fieldId ),
1246 defaultExpr_( defaultExpr )
1249 Ast::StructSplitReference::StructSplitReference( const Ast::SourceLocation & fieldLoc, size_t fieldPos, Ast::Expression * defaultExpr )
1250 : Ast::Expression( fieldLoc ),
1251 structLoc_( Ast::THE_UNKNOWN_LOCATION, bool( ) ), // This is a dummy value! The correct value is set later.
1252 fieldId_( 0 ), fieldPos_( fieldPos ),
1253 defaultExpr_( defaultExpr )
1256 Ast::StructSplitReference::~StructSplitReference( )
1258 if( fieldId_ != 0 )
1260 delete fieldId_;
1262 if( defaultExpr_ != 0 )
1264 delete defaultExpr_;
1268 void
1269 Ast::StructSplitReference::setStruct( const Ast::SourceLocation & structLoc, size_t ** structPos )
1271 structLoc_ = structLoc;
1272 structPos_ = structPos;
1275 void
1276 Ast::StructSplitReference::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1278 if( defaultExpr_ != 0 )
1280 defaultExpr_->analyze( this, env, freeStatesDst );
1284 void
1285 Ast::StructSplitReference::eval( Kernel::EvalState * evalState ) const
1287 Kernel::VariableHandle structHandle = evalState->env_->getVarHandle( **structPos_ );
1288 typedef const Lang::Structure StructType;
1289 RefCountPtr< StructType > structVal = structHandle->getVal< StructType >( "Type-checked value in StructSplitReference::eval." );
1291 Kernel::ContRef cont = evalState->cont_;
1292 if( fieldId_ != 0 )
1296 cont->takeHandle( structVal->getField( fieldId_, structVal ),
1297 evalState );
1298 return;
1300 catch( const Exceptions::NonExistentMember & ball )
1302 if( defaultExpr_ == 0 )
1304 throw;
1306 /* Never mind, we use the default instead. See below. */
1309 else
1313 cont->takeHandle( structVal->getPosition( fieldPos_, structVal ),
1314 evalState );
1315 return;
1317 catch( const Exceptions::NonExistentPosition & ball )
1319 if( defaultExpr_ == 0 )
1321 throw;
1323 /* Never mind, we use the default instead. See below. */
1327 if( defaultExpr_ == 0 )
1329 throw Exceptions::InternalError( "Just about to use null pointer defaultExpr_ in StructSplitReference::eval." );
1331 evalState->expr_ = defaultExpr_;
1334 Ast::StructSplitSink::StructSplitSink( )
1335 : Ast::Expression( Ast::THE_UNKNOWN_LOCATION ), structLoc_( Ast::THE_UNKNOWN_LOCATION, bool( ) )
1338 Ast::StructSplitSink::~StructSplitSink( )
1341 void
1342 Ast::StructSplitSink::setStruct( const Ast::SourceLocation & structLoc, size_t ** structPos, size_t consumedArguments )
1344 structLoc_ = structLoc;
1345 structPos_ = structPos;
1346 consumedArguments_ = consumedArguments;
1349 void
1350 Ast::StructSplitSink::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1352 /* Nothing to do! */
1355 void
1356 Ast::StructSplitSink::eval( Kernel::EvalState * evalState ) const
1358 Kernel::VariableHandle structHandle = evalState->env_->getVarHandle( **structPos_ );
1359 typedef const Lang::Structure StructType;
1360 RefCountPtr< StructType > structVal = structHandle->getVal< StructType >( "Type-checked value in StructSplitReference::eval." );
1362 Kernel::ContRef cont = evalState->cont_;
1363 cont->takeValue( structVal->getSink( consumedArguments_ ),
1364 evalState );
1368 Ast::AssertNoSinkNeeded::AssertNoSinkNeeded( const Ast::SourceLocation & loc, size_t orderedCount, const Ast::SourceLocation & structLoc, size_t ** structPos )
1369 : Ast::Assertion( loc ), orderedCount_( orderedCount ), structLoc_( structLoc, bool( ) ), structPos_( structPos )
1372 Ast::AssertNoSinkNeeded::~AssertNoSinkNeeded( )
1375 void
1376 Ast::AssertNoSinkNeeded::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1378 /* immediate_ is already true by the inheritage from Ast::Assertion. */
1381 void
1382 Ast::AssertNoSinkNeeded::eval( Kernel::EvalState * evalState ) const
1384 Kernel::VariableHandle structHandle = evalState->env_->getVarHandle( **structPos_ );
1385 typedef const Lang::Structure StructType;
1386 RefCountPtr< StructType > structVal = structHandle->getVal< StructType >( "Type-checked value in StructSplitReference::eval." );
1388 if( structVal->argList_->orderedExprs_->size( ) > orderedCount_ )
1390 throw Exceptions::SinkRequired( loc_, orderedCount_, structVal->argList_->orderedExprs_->size( ) );
1393 Kernel::ContRef cont = evalState->cont_;
1394 cont->takeHandle( Kernel::THE_VOID_VARIABLE, evalState );
1397 size_t Ast::SplitDefineVariables::splitVarCount = 0;
1398 PtrOwner_back_Access< std::list< const Ast::PlacedIdentifier * > > Ast::SplitDefineVariables::mem;
1400 Ast::SplitDefineVariables::SplitDefineVariables( )
1401 : sinkDefine_( 0 ), sinkExpr_( 0 ), seenNamed_( false ), seenDefault_( false )
1403 std::ostringstream oss;
1404 oss << Kernel::SPLIT_VAR_PREFIX << splitVarCount ;
1405 splitVarId_ = new Ast::PlacedIdentifier( Lang::THE_NAMESPACE_Shapes, strdup( oss.str( ).c_str( ) ) );
1406 mem.push_back( splitVarId_ );
1407 ++splitVarCount;
1410 Ast::PlacedIdentifier *
1411 Ast::SplitDefineVariables::newSplitVarId( ) const
1413 return splitVarId_->clone( );
1417 Ast::StateReference::StateReference( const Ast::SourceLocation & loc )
1418 : Ast::Node( loc )
1421 Ast::StateReference::~StateReference( )
1425 Ast::LexiographicState::LexiographicState( const Ast::SourceLocation & loc, const Ast::Identifier * id, Kernel::Environment::LexicalKey ** idKey )
1426 : Ast::StateReference( loc ), id_( id ), idKey_( idKey )
1429 Ast::LexiographicState::~LexiographicState( )
1431 delete id_;
1432 if( *idKey_ != 0 )
1434 delete *idKey_;
1436 delete idKey_; // This can be done only as long as this is not shared!
1439 void
1440 Ast::LexiographicState::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1442 /* The following lines is the ugly solution to the problem that the inherited parent_ and analysisEnv_
1443 * are not well defined for reused nodes. And nodes of this type are typically reused.
1444 * For this type of node, one _could_ refer to someParent_ and someAnalysisEnv_ instead, but probably,
1445 * it is a mistake to even try.
1447 someParent_ = parent_;
1448 parent_ = 0;
1449 someAnalysisEnv_ = analysisEnv_;
1450 analysisEnv_ = 0;
1452 if( *idKey_ == 0 )
1454 *idKey_ = new Kernel::Environment::LexicalKey( env->findLexicalStateKey( loc_, *id_, this ) );
1456 if( ! (*idKey_)->isMissing( ) )
1458 freeStatesDst->insert( env->getStateID( **idKey_ ) );
1462 Kernel::StateHandle
1463 Ast::LexiographicState::getHandle( Kernel::PassedEnv env, Kernel::PassedDyn dyn ) const
1465 return env->getStateHandle( **idKey_ );
1469 Ast::DynamicState::DynamicState( const Ast::SourceLocation & loc, const Ast::Identifier * id )
1470 : Ast::StateReference( loc ), id_( id ), idKey_( new Kernel::Environment::LexicalKey * ( 0 ) )
1473 Ast::DynamicState::~DynamicState( )
1475 delete id_;
1476 if( *idKey_ != 0 )
1478 delete *idKey_;
1480 delete idKey_; // This can be done only as long as this is not shared!
1483 void
1484 Ast::DynamicState::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1486 /* See comment in LexicalState::analyze_impl.
1488 someParent_ = parent_;
1489 parent_ = 0;
1490 someAnalysisEnv_ = analysisEnv_;
1491 analysisEnv_ = 0;
1493 /* It would make sense to check the reference and...
1494 * This might be overly conservative... but we really shouldn't support dynamic states anyway.
1496 freeStatesDst->insert( Ast::AnalysisEnvironment::getTheAnyStateID( ) );
1499 Kernel::StateHandle
1500 Ast::DynamicState::getHandle( Kernel::PassedEnv env, Kernel::PassedDyn dyn ) const
1502 throw Exceptions::NotImplemented( "Referencing dynamic states" );
1506 Ast::IntroduceState::IntroduceState( const Ast::SourceLocation & idLoc, const Ast::PlacedIdentifier * id, Ast::Expression * expr, size_t ** idPos )
1507 : Ast::BindNode( idLoc, expr->loc( ), idLoc, id ), expr_( expr ), idPos_( idPos )
1510 Ast::IntroduceState::~IntroduceState( )
1512 delete expr_;
1514 /* idPos_ shared and will be a memory leak which must not be deleted.
1515 * It would be easy to fix the leak using RefCountPtr< size_t >, but the leakage is constant space, so silly efficiency is prioritized.
1520 void
1521 Ast::IntroduceState::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1523 expr_->analyze( this, env, freeStatesDst );
1525 if( *idPos_ == 0 ){
1526 *idPos_ = new size_t( env->findLocalStatePosition( idLoc_, *id_ ) );
1529 const Ast::Node * firstUse = env->getStateFirstUse( **idPos_ );
1530 if( firstUse != NULL ){
1531 Ast::theAnalysisErrorsList.push_back( new Exceptions::StateUninitializedUse( firstUse->loc( ), id_, this ) );
1534 stateID_ = env->getStateID( **idPos_ );
1535 freeStatesDst->insert( stateID_ );
1538 void
1539 Ast::IntroduceState::initializeEnvironment( Kernel::PassedEnv env, Kernel::PassedDyn dyn ) const
1541 /* Although it would be possible to insert some kind of thunk in the environment here,
1542 * it is not obvious that such a feature would be desirable. With such a feature, one
1543 * would be able to use a state before the place in the code where it is introduced:
1545 * •dst << ...
1546 * ...
1547 * •dst: newGroup
1548 * •dst;
1550 * This just seems awkward; this is a stateful program, and order generally matters -- this is
1551 * why use before declaration is considered illegal and treated as error already during
1552 * static analysis.
1556 void
1557 Ast::IntroduceState::evalHelper( Kernel::EvalState * evalState ) const
1559 evalState->cont_ = Kernel::ContRef( new Kernel::IntroduceStateContinuation( evalState->env_,
1560 *idPos_,
1561 evalState->cont_,
1562 expr_->loc( ) ) );
1563 evalState->expr_ = expr_;
1567 Ast::Insertion::Insertion( Ast::StateReference * stateRef, Ast::Expression * expr )
1568 : Ast::Expression( stateRef->loc( ), expr->loc( ) ), stateRef_( stateRef ), expr_( expr )
1571 Ast::Insertion::~Insertion( )
1574 void
1575 Ast::Insertion::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1577 stateRef_->analyze( this, env, freeStatesDst ); /* This will always add something to the set of free states. */
1578 expr_->analyze( this, env, freeStatesDst );
1581 void
1582 Ast::Insertion::eval( Kernel::EvalState * evalState ) const
1584 evalState->cont_ = Kernel::ContRef( new Kernel::InsertionContinuation( stateRef_->getHandle( evalState->env_, evalState->dyn_ ),
1585 evalState->cont_,
1586 evalState->dyn_,
1587 expr_->loc( ) ) );
1588 evalState->expr_ = expr_;
1591 Ast::InsertionMutatorCall::InsertionMutatorCall( const Ast::SourceLocation & loc, Ast::Expression * expr )
1592 : Ast::Expression( loc ), expr_( expr )
1595 Ast::InsertionMutatorCall::~InsertionMutatorCall( )
1598 void
1599 Ast::InsertionMutatorCall::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1601 throw Exceptions::InternalError( loc_, "An InsertionMutatorCall was analyzed (the contained expression should have been extracted and replaced this object)." );
1604 void
1605 Ast::InsertionMutatorCall::eval( Kernel::EvalState * evalState ) const
1607 throw Exceptions::InternalError( loc_, "An InsertionMutatorCall was evaluated (the contained expression should have been extracted and replaced this object)." );
1611 Ast::Freeze::Freeze( const Ast::SourceLocation & idLoc, const Ast::PlacedIdentifier * id, size_t ** idPos )
1612 : Ast::Expression( idLoc ), id_( id ), idPos_( idPos )
1614 immediate_ = true;
1617 Ast::Freeze::~Freeze( )
1619 /* idPos shared and will be a memory leak which must not be deleted.
1620 * It would be easy to fix the leak using RefCountPtr< size_t >, but the leakage is constant space, so silly efficiency is prioritized.
1624 void
1625 Ast::Freeze::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1627 if( *idPos_ == 0 )
1629 *idPos_ = new size_t( env->findLocalStatePosition( loc( ), *id_ ) );
1632 freeStatesDst->insert( env->getStateID( **idPos_ ) );
1635 void
1636 Ast::Freeze::eval( Kernel::EvalState * evalState ) const
1638 evalState->env_->freeze( **idPos_, evalState, loc( ) );
1642 Ast::Peek::Peek( const Ast::SourceLocation & idLoc, Ast::StateReference * stateRef )
1643 : Ast::Expression( idLoc ), stateRef_( stateRef )
1645 immediate_ = true;
1648 Ast::Peek::~Peek( )
1650 /* idPos shared and will be a memory leak which must not be deleted.
1651 * It would be easy to fix the leak using RefCountPtr< size_t >, but the leakage is constant space, so silly efficiency is prioritized.
1655 void
1656 Ast::Peek::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1658 stateRef_->analyze( this, env, freeStatesDst ); /* This will always add something to the set of free states. */
1661 void
1662 Ast::Peek::eval( Kernel::EvalState * evalState ) const
1664 stateRef_->getHandle( evalState->env_, evalState->dyn_ )->peek( evalState, loc( ) );
1668 Ast::DynamicExpression::DynamicExpression( const Ast::SourceLocation & loc, Ast::Expression * expr )
1669 : Ast::Expression( loc ), expr_( expr )
1671 immediate_ = true;
1674 Ast::DynamicExpression::~DynamicExpression( )
1677 void
1678 Ast::DynamicExpression::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1680 Ast::StateIDSet * freeStates = new Ast::StateIDSet;
1681 expr_->analyze( this, env, freeStates );
1683 if( ! freeStates->empty( ) )
1685 Ast::theAnalysisErrorsList.push_back( new Exceptions::IllegalFreeStates( expr_->loc( ), freeStates, "dynamic expressions must be pure" ) );
1687 else
1689 delete freeStates;
1693 void
1694 Ast::DynamicExpression::eval( Kernel::EvalState * evalState ) const
1696 Kernel::ContRef cont = evalState->cont_;
1697 cont->takeValue( Kernel::ValueRef( new Lang::DynamicExpression( evalState->env_, expr_ ) ),
1698 evalState );
1702 Ast::LexiographicType::LexiographicType( const Ast::SourceLocation & loc, const Ast::Identifier * id, Kernel::Environment::LexicalKey ** idKey )
1703 : Ast::Expression( loc ), id_( id ), idKey_( idKey )
1705 immediate_ = true;
1708 Ast::LexiographicType::~LexiographicType( )
1710 delete id_;
1711 if( *idKey_ != 0 )
1713 delete *idKey_;
1715 delete idKey_; /* This can be done only as long as this is not shared! */
1718 void
1719 Ast::LexiographicType::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1721 if( *idKey_ == 0 )
1723 *idKey_ = new Kernel::Environment::LexicalKey( env->findLexicalTypeKey( loc_, *id_ ) );
1727 void
1728 Ast::LexiographicType::eval( Kernel::EvalState * evalState ) const
1730 evalState->env_->lookup( **idKey_, evalState );