Remove old documentation chapter on core bindings
[shapes.git] / source / astvar.cc
blob54cf874f30379812efb6997dfba6a5581f916de8
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
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 ), 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 ), 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( Ast::SourceLocation( idLoc, expr->loc( ) ) ), idLoc_( idLoc ), 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 ), 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 );
957 Kernel::DynamicVariableDeclContinuation::DynamicVariableDeclContinuation( const Ast::SourceLocation & traceLoc, const Ast::DynamicVariableDecl *, Kernel::EvalState & evalState )
958 : Kernel::Continuation( traceLoc ), env_( evalState.env_ ), dyn_( evalState.dyn_ ), cont_( evalState.cont_ )
961 Kernel::DynamicVariableDeclContinuation::~DynamicVariableDeclContinuation( )
964 void
965 Kernel::DynamicVariableDeclContinuation::takeValue( const RefCountPtr< const Lang::Value > & val, Kernel::EvalState * evalState, bool dummy ) const
967 evalState->env_ = env_;
968 evalState->dyn_ = dyn_;
969 evalState->cont_ = cont_;
970 throw Exceptions::NotImplemented( "Deprecated: DynamicVariableDeclContinuation" );
971 // declExpr_->callBack( Helpers::down_cast< const Lang::Function >( val, traceLoc_ ),
972 // evalState );
975 Kernel::ContRef
976 Kernel::DynamicVariableDeclContinuation::up( ) const
978 return cont_;
981 RefCountPtr< const char >
982 Kernel::DynamicVariableDeclContinuation::description( ) const
984 return strrefdup( "dynamic variable declaration" );
987 void
988 Kernel::DynamicVariableDeclContinuation::gcMark( Kernel::GCMarkedSet & marked )
990 env_->gcMark( marked );
991 dyn_->gcMark( marked );
992 cont_->gcMark( marked );
996 Ast::DynamicStateDecl::DynamicStateDecl( const Ast::SourceLocation & loc, const Ast::SourceLocation & idLoc, const Ast::PlacedIdentifier * id, Ast::StateReference * defaultState, size_t ** idPos )
997 : Ast::BindNode( loc, idLoc, id ), idPos_( idPos ), defaultState_( defaultState )
1000 Ast::DynamicStateDecl::~DynamicStateDecl( )
1004 void
1005 Ast::DynamicStateDecl::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1007 if( *idPos_ == 0 )
1009 *idPos_ = new size_t( env->findLocalDynamicStatePosition( idLoc_, *id_ ) );
1013 void
1014 Ast::DynamicStateDecl::initializeEnvironment( Kernel::PassedEnv env, Kernel::PassedDyn dyn ) const
1016 env->defineDynamicState( id_, **idPos_, env, dyn, defaultState_ );
1019 void
1020 Ast::DynamicStateDecl::evalHelper( Kernel::EvalState * evalState ) const
1022 Kernel::ContRef cont = evalState->cont_;
1023 cont->takeHandle( Kernel::THE_VOID_VARIABLE,
1024 evalState );
1028 Ast::EvalSymbolFunction::EvalSymbolFunction( const Ast::SourceLocation & loc, Ast::Expression * expr, const RefCountPtr< const Ast::NamespacePath > & lexicalPath )
1029 : Lang::Function( new Kernel::EvaluatedFormals( Ast::FileID::build_internal( "< symbol evaluation >" ), true ) ), loc_( loc ), expr_( expr ), lexicalPath_( lexicalPath )
1032 Ast::EvalSymbolFunction::~EvalSymbolFunction( )
1034 delete expr_;
1037 void
1038 Ast::EvalSymbolFunction::push_exprs( Ast::ArgListExprs * args ) const
1040 args->orderedExprs_->push_back( expr_ );
1043 void
1044 Ast::EvalSymbolFunction::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1046 analysisEnv_ = env;
1048 /* expr_ shall be analyzed from the calling expression.
1049 * Here, it is only used to locate errors.
1053 void
1054 Ast::EvalSymbolFunction::call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1056 static const RefCountPtr< const Ast::NamespacePath > EMPTY_RELATIVE_PATH( new Ast::NamespacePath( ) );
1058 RefCountPtr< const Lang::Value > untypedVal = args.getValue( 0 );
1059 typedef const Lang::Symbol ArgType;
1060 ArgType * val = dynamic_cast< ArgType * >( untypedVal.getPtr( ) );
1061 if( val == 0 )
1063 throw Exceptions::TypeMismatch( expr_->loc( ), untypedVal->getTypeName( ), ArgType::staticTypeName( ) );
1065 if( val->isUnique( ) )
1067 throw Exceptions::OutOfRange( expr_->loc( ), strrefdup( "Unique symbols can't denote variables." ) );
1070 RefCountPtr< const Ast::SearchContext > searchContext( new Ast::SearchContext( lexicalPath_, RefCountPtr< const char >( NullPtr< const char >( ) ) ) );
1071 Kernel::Environment::LexicalKey key = analysisEnv_->findLexicalVariableKey( loc_, Ast::Identifier( searchContext, Ast::NamespaceReference::RELATIVE, EMPTY_RELATIVE_PATH, val->name( ).getPtr( ) ) );
1073 Kernel::PassedEnv env = evalState->env_;
1074 env->lookup( key, evalState );
1078 Ast::DefineVariable::DefineVariable( const Ast::SourceLocation & idLoc, const Ast::PlacedIdentifier * id, Ast::Expression * expr, size_t ** idPos )
1079 : Ast::BindNode( Ast::SourceLocation( idLoc, expr->loc( ) ), idLoc, id ), expr_( expr ), idPos_( idPos )
1082 Ast::DefineVariable::~DefineVariable( )
1084 delete expr_;
1086 /* idPos_ is shared and will be a memory leak which must not be deleted.
1087 * It would be easy to fix the leak using RefCountPtr< size_t >, but the leakage is constant space, so silly efficiency is prioritized.
1091 void
1092 Ast::DefineVariable::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1094 Ast::StateIDSet freeStates;
1095 expr_->analyze( this, env, & freeStates );
1096 if( ! freeStates.empty( ) )
1098 Ast::Force * forcedExpr( new Ast::Force( loc_, expr_ ) );
1099 /* The forcedExpr should not be analyzed since the contained expr_ is already
1100 * analyzed, and analyzing forcedExpr would just cause expr_ to be analyzed again.
1101 * Instead, we just need to update parent/child links.
1103 expr_->changeParent( forcedExpr );
1104 forcedExpr->setParent( this, env );
1105 expr_ = forcedExpr;
1106 for( Ast::StateIDSet::const_iterator i = freeStates.begin( ); i != freeStates.end( ); ++i )
1108 freeStatesDst->insert( *i );
1111 if( *idPos_ == 0 )
1113 *idPos_ = new size_t( env->findLocalVariablePosition( idLoc_, *id_ ) );
1117 void
1118 Ast::DefineVariable::initializeEnvironment( Kernel::PassedEnv env, Kernel::PassedDyn dyn ) const
1120 env->define( **idPos_,
1121 Kernel::VariableHandle( new Kernel::Variable( new Kernel::Thunk( env, dyn, expr_ ) ) ) );
1124 void
1125 Ast::DefineVariable::evalHelper( Kernel::EvalState * evalState ) const
1127 if( expr_->immediate_ ){
1128 Kernel::VariableHandle var = evalState->env_->getVarHandle( **idPos_ );
1129 /* Using sufficient but not necessary condition for recognizing that the thunk
1130 * set up in initializeEnvironment is still not forced. The worst thing that
1131 * can happen is that another thunk for this expression, but in another environment
1132 * or another dynamic environment, is forced. If that happens, note that
1133 * expr_->immediate_ also applies to the other thunk, so it should be forced sooner or
1134 * later anywhay.
1136 if( var->isThunk( expr_ ) ){
1137 evalState->cont_ = Kernel::ContRef( new Kernel::IgnoreContinuation( evalState->cont_, expr_->loc( ) ) );
1138 var->force( var, evalState );
1139 return;
1143 Kernel::ContRef cont = evalState->cont_;
1144 cont->takeHandle( Kernel::THE_VOID_VARIABLE, evalState );
1148 Ast::DefineAlias::DefineAlias( const Ast::SourceLocation & idLoc, const Ast::SourceLocation & expansionLoc, const Ast::PlacedIdentifier * id, const Ast::NamespaceReference & expansion )
1149 : Ast::Node( idLoc ), idLoc_( idLoc ), id_( id ), expansion_( expansion ), expansionLoc_( expansionLoc )
1152 Ast::DefineAlias::~DefineAlias( )
1154 delete id_;
1157 void
1158 Ast::DefineAlias::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1160 throw Exceptions::InternalError( "Ast::DefineAlias::analyze_impl: Alias definitions should not be present at program analysis." );
1163 Ast::LexicalVariableLocationExpr::LexicalVariableLocationExpr( const Ast::SourceLocation & idLoc, const Ast::Identifier * id, Kind kind )
1164 : Ast::Expression( idLoc ), id_( id ), kind_( kind ), value_( NullPtr< const Lang::Value >( ) )
1166 immediate_ = true;
1169 Ast::LexicalVariableLocationExpr::~LexicalVariableLocationExpr( )
1172 void
1173 Ast::LexicalVariableLocationExpr::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1175 Kernel::Environment::LexicalKey key = Kernel::Environment::LexicalKey( env->findLexicalVariableKey( loc_, *id_ ) );
1176 if( key.isMissing( ) ){
1177 /* If the variable wasn't found, compilation will be terminated after the analysis sweep, and there's
1178 * no point in trying to assign something meaningless to value_.
1180 return;
1183 switch( kind_ )
1185 case INDEX:
1186 value_ = Kernel::ValueRef( new Lang::Integer( key.pos_ ) );
1187 break;
1188 case DEPTH:
1189 value_ = Kernel::ValueRef( new Lang::Integer( key.up_ ) );
1190 break;
1191 case ABSID:
1193 Ast::PlacedIdentifier idPlaced( env->reverseMapLexicalVariable( key ) );
1194 std::ostringstream oss;
1195 oss << Interaction::NAMESPACE_SEPARATOR ;
1196 idPlaced.show( oss, Ast::Identifier::VARIABLE );
1197 value_ = Kernel::ValueRef( new Lang::String( strrefdup( oss ) ) );
1199 break;
1203 void
1204 Ast::LexicalVariableLocationExpr::eval( Kernel::EvalState * evalState ) const
1206 Kernel::ContRef cont = evalState->cont_;
1207 cont->takeValue( value_, evalState );
1211 Ast::LexicalVariableNameExpr::LexicalVariableNameExpr( const Ast::SourceLocation & loc )
1212 : Ast::Expression( loc ), value_( NullPtr< const Lang::Value >( ) )
1214 immediate_ = true;
1217 Ast::LexicalVariableNameExpr::~LexicalVariableNameExpr( )
1220 void
1221 Ast::LexicalVariableNameExpr::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1223 Ast::Node * n = parent->parent( );
1224 while( n != 0 )
1226 Ast::BindNode * bn = dynamic_cast< Ast::DefineVariable * >( n );
1227 if( bn != 0 )
1229 std::ostringstream os;
1230 bn->id( )->show( os, Ast::Identifier::VARIABLE );
1231 value_ = Kernel::ValueRef( new Lang::String( strrefdup( os ) ) );
1232 return;
1234 n = n->parent( );
1236 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." ) ) );
1239 void
1240 Ast::LexicalVariableNameExpr::eval( Kernel::EvalState * evalState ) const
1242 Kernel::ContRef cont = evalState->cont_;
1243 cont->takeValue( value_, evalState );
1247 Kernel::AssertStructureContinuation::AssertStructureContinuation( const Kernel::ContRef & cont, const Ast::SourceLocation & traceLoc )
1248 : Kernel::Continuation( traceLoc ), cont_( cont )
1251 Kernel::AssertStructureContinuation::~AssertStructureContinuation( )
1254 void
1255 Kernel::AssertStructureContinuation::takeValue( const RefCountPtr< const Lang::Value > & val, Kernel::EvalState * evalState, bool dummy ) const
1257 evalState->cont_ = cont_;
1258 cont_->takeValue( Helpers::down_cast_ContinuationArgument< const Lang::Structure >( val, this ), evalState );
1261 Kernel::ContRef
1262 Kernel::AssertStructureContinuation::up( ) const
1264 return cont_;
1267 RefCountPtr< const char >
1268 Kernel::AssertStructureContinuation::description( ) const
1270 return strrefdup( "Assert type is struct" );
1273 void
1274 Kernel::AssertStructureContinuation::gcMark( Kernel::GCMarkedSet & marked )
1276 cont_->gcMark( marked );
1280 Ast::StructSplitReference::StructSplitReference( Ast::SourceLocation fieldLoc, const char * fieldId, Ast::Expression * defaultExpr )
1281 : Ast::Expression( fieldLoc ),
1282 structLoc_( Ast::THE_UNKNOWN_LOCATION ), // This is a dummy value! The correct value is set later.
1283 fieldId_( fieldId ),
1284 defaultExpr_( defaultExpr )
1287 Ast::StructSplitReference::StructSplitReference( Ast::SourceLocation fieldLoc, size_t fieldPos, Ast::Expression * defaultExpr )
1288 : Ast::Expression( fieldLoc ),
1289 structLoc_( Ast::THE_UNKNOWN_LOCATION ), // This is a dummy value! The correct value is set later.
1290 fieldId_( 0 ), fieldPos_( fieldPos ),
1291 defaultExpr_( defaultExpr )
1294 Ast::StructSplitReference::~StructSplitReference( )
1296 if( fieldId_ != 0 )
1298 delete fieldId_;
1300 if( defaultExpr_ != 0 )
1302 delete defaultExpr_;
1306 void
1307 Ast::StructSplitReference::setStruct( Ast::SourceLocation structLoc, size_t ** structPos )
1309 structLoc_ = structLoc;
1310 structPos_ = structPos;
1313 void
1314 Ast::StructSplitReference::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1316 if( defaultExpr_ != 0 )
1318 defaultExpr_->analyze( this, env, freeStatesDst );
1322 void
1323 Ast::StructSplitReference::eval( Kernel::EvalState * evalState ) const
1325 Kernel::VariableHandle structHandle = evalState->env_->getVarHandle( **structPos_ );
1326 typedef const Lang::Structure StructType;
1327 RefCountPtr< StructType > structVal = structHandle->getVal< StructType >( "Type-checked value in StructSplitReference::eval." );
1329 Kernel::ContRef cont = evalState->cont_;
1330 if( fieldId_ != 0 )
1334 cont->takeHandle( structVal->getField( fieldId_, structVal ),
1335 evalState );
1336 return;
1338 catch( const Exceptions::NonExistentMember & ball )
1340 if( defaultExpr_ == 0 )
1342 throw;
1344 // Never mind, we use the default instead. See below.
1347 else
1351 cont->takeHandle( structVal->getPosition( fieldPos_, structVal ),
1352 evalState );
1353 return;
1355 catch( const Exceptions::NonExistentPosition & ball )
1357 if( defaultExpr_ == 0 )
1359 throw;
1361 // Never mind, we use the default instead. See below.
1365 if( defaultExpr_ == 0 )
1367 throw Exceptions::InternalError( "Just about to use null pointer defaultExpr_ in StructSplitReference::eval." );
1369 evalState->expr_ = defaultExpr_;
1372 Ast::StructSplitSink::StructSplitSink( )
1373 : Ast::Expression( Ast::THE_UNKNOWN_LOCATION ), structLoc_( Ast::THE_UNKNOWN_LOCATION )
1376 Ast::StructSplitSink::~StructSplitSink( )
1379 void
1380 Ast::StructSplitSink::setStruct( Ast::SourceLocation structLoc, size_t ** structPos, size_t consumedArguments )
1382 structLoc_ = structLoc;
1383 structPos_ = structPos;
1384 consumedArguments_ = consumedArguments;
1387 void
1388 Ast::StructSplitSink::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1390 /* Nothing to do! */
1393 void
1394 Ast::StructSplitSink::eval( Kernel::EvalState * evalState ) const
1396 Kernel::VariableHandle structHandle = evalState->env_->getVarHandle( **structPos_ );
1397 typedef const Lang::Structure StructType;
1398 RefCountPtr< StructType > structVal = structHandle->getVal< StructType >( "Type-checked value in StructSplitReference::eval." );
1400 Kernel::ContRef cont = evalState->cont_;
1401 cont->takeValue( structVal->getSink( consumedArguments_ ),
1402 evalState );
1406 Ast::AssertNoSinkNeeded::AssertNoSinkNeeded( const Ast::SourceLocation & loc, size_t orderedCount, Ast::SourceLocation structLoc, size_t ** structPos )
1407 : Ast::Assertion( loc ), orderedCount_( orderedCount ), structLoc_( structLoc ), structPos_( structPos )
1410 Ast::AssertNoSinkNeeded::~AssertNoSinkNeeded( )
1413 void
1414 Ast::AssertNoSinkNeeded::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1416 /* immediate_ is already true by the inheritage from Ast::Assertion. */
1419 void
1420 Ast::AssertNoSinkNeeded::eval( Kernel::EvalState * evalState ) const
1422 Kernel::VariableHandle structHandle = evalState->env_->getVarHandle( **structPos_ );
1423 typedef const Lang::Structure StructType;
1424 RefCountPtr< StructType > structVal = structHandle->getVal< StructType >( "Type-checked value in StructSplitReference::eval." );
1426 if( structVal->argList_->orderedExprs_->size( ) > orderedCount_ )
1428 throw Exceptions::SinkRequired( loc_, orderedCount_, structVal->argList_->orderedExprs_->size( ) );
1431 Kernel::ContRef cont = evalState->cont_;
1432 cont->takeHandle( Kernel::THE_VOID_VARIABLE, evalState );
1435 size_t Ast::SplitDefineVariables::splitVarCount = 0;
1436 PtrOwner_back_Access< std::list< const Ast::PlacedIdentifier * > > Ast::SplitDefineVariables::mem;
1438 Ast::SplitDefineVariables::SplitDefineVariables( )
1439 : sinkDefine_( 0 ), sinkExpr_( 0 ), seenNamed_( false ), seenDefault_( false )
1441 std::ostringstream oss;
1442 oss << Kernel::SPLIT_VAR_PREFIX << splitVarCount ;
1443 splitVarId_ = new Ast::PlacedIdentifier( Lang::THE_NAMESPACE_Shapes, strdup( oss.str( ).c_str( ) ) );
1444 mem.push_back( splitVarId_ );
1445 ++splitVarCount;
1448 Ast::PlacedIdentifier *
1449 Ast::SplitDefineVariables::newSplitVarId( ) const
1451 return splitVarId_->clone( );
1455 Ast::StateReference::StateReference( const Ast::SourceLocation & loc )
1456 : Ast::Node( loc )
1459 Ast::StateReference::~StateReference( )
1463 Ast::LexiographicState::LexiographicState( const Ast::SourceLocation & loc, const Ast::Identifier * id, Kernel::Environment::LexicalKey ** idKey )
1464 : Ast::StateReference( loc ), id_( id ), idKey_( idKey )
1467 Ast::LexiographicState::~LexiographicState( )
1469 delete id_;
1470 if( *idKey_ != 0 )
1472 delete *idKey_;
1474 delete idKey_; // This can be done only as long as this is not shared!
1477 void
1478 Ast::LexiographicState::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1480 /* The following lines is the ugly solution to the problem that the inherited parent_ and analysisEnv_
1481 * are not well defined for reused nodes. And nodes of this type are typically reused.
1482 * For this type of node, one _could_ refer to someParent_ and someAnalysisEnv_ instead, but probably,
1483 * it is a mistake to even try.
1485 someParent_ = parent_;
1486 parent_ = 0;
1487 someAnalysisEnv_ = analysisEnv_;
1488 analysisEnv_ = 0;
1490 if( *idKey_ == 0 )
1492 *idKey_ = new Kernel::Environment::LexicalKey( env->findLexicalStateKey( loc_, *id_, this ) );
1494 if( ! (*idKey_)->isMissing( ) )
1496 freeStatesDst->insert( env->getStateID( **idKey_ ) );
1500 Kernel::StateHandle
1501 Ast::LexiographicState::getHandle( Kernel::PassedEnv env, Kernel::PassedDyn dyn ) const
1503 return env->getStateHandle( **idKey_ );
1507 Ast::DynamicState::DynamicState( const Ast::SourceLocation & loc, const Ast::Identifier * id )
1508 : Ast::StateReference( loc ), id_( id ), idKey_( new Kernel::Environment::LexicalKey * ( 0 ) )
1511 Ast::DynamicState::~DynamicState( )
1513 delete id_;
1514 if( *idKey_ != 0 )
1516 delete *idKey_;
1518 delete idKey_; // This can be done only as long as this is not shared!
1521 void
1522 Ast::DynamicState::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1524 /* See comment in LexicalState::analyze_impl.
1526 someParent_ = parent_;
1527 parent_ = 0;
1528 someAnalysisEnv_ = analysisEnv_;
1529 analysisEnv_ = 0;
1531 /* It would make sense to check the reference and...
1532 * This might be overly conservative... but we really shouldn't support dynamic states anyway.
1534 freeStatesDst->insert( Ast::AnalysisEnvironment::getTheAnyStateID( ) );
1537 Kernel::StateHandle
1538 Ast::DynamicState::getHandle( Kernel::PassedEnv env, Kernel::PassedDyn dyn ) const
1540 throw Exceptions::NotImplemented( "Referencing dynamic states" );
1544 Ast::IntroduceState::IntroduceState( const Ast::SourceLocation & idLoc, const Ast::PlacedIdentifier * id, Ast::Expression * expr, size_t ** idPos )
1545 : Ast::BindNode( Ast::SourceLocation( idLoc, expr->loc( ) ), idLoc, id ), expr_( expr ), idPos_( idPos )
1548 Ast::IntroduceState::~IntroduceState( )
1550 delete expr_;
1552 /* idPos_ shared and will be a memory leak which must not be deleted.
1553 * It would be easy to fix the leak using RefCountPtr< size_t >, but the leakage is constant space, so silly efficiency is prioritized.
1558 void
1559 Ast::IntroduceState::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1561 expr_->analyze( this, env, freeStatesDst );
1563 if( *idPos_ == 0 ){
1564 *idPos_ = new size_t( env->findLocalStatePosition( idLoc_, *id_ ) );
1567 const Ast::Node * firstUse = env->getStateFirstUse( **idPos_ );
1568 if( firstUse != NULL ){
1569 Ast::theAnalysisErrorsList.push_back( new Exceptions::StateUninitializedUse( firstUse->loc( ), id_, this ) );
1572 stateID_ = env->getStateID( **idPos_ );
1573 freeStatesDst->insert( stateID_ );
1576 void
1577 Ast::IntroduceState::initializeEnvironment( Kernel::PassedEnv env, Kernel::PassedDyn dyn ) const
1579 /* Although it would be possible to insert some kind of thunk in the environment here,
1580 * it is not obvious that such a feature would be desirable. With such a feature, one
1581 * would be able to use a state before the place in the code where it is introduced:
1583 * •dst << ...
1584 * ...
1585 * •dst: newGroup
1586 * •dst;
1588 * This just seems awkward; this is a stateful program, and order generally matters -- this is
1589 * why use before declaration is considered illegal and treated as error already during
1590 * static analysis.
1594 void
1595 Ast::IntroduceState::evalHelper( Kernel::EvalState * evalState ) const
1597 evalState->cont_ = Kernel::ContRef( new Kernel::IntroduceStateContinuation( evalState->env_,
1598 *idPos_,
1599 evalState->cont_,
1600 expr_->loc( ) ) );
1601 evalState->expr_ = expr_;
1605 Ast::Insertion::Insertion( Ast::StateReference * stateRef, Ast::Expression * expr )
1606 : Ast::Expression( Ast::SourceLocation( stateRef->loc( ), expr->loc( ) ) ), stateRef_( stateRef ), expr_( expr )
1609 Ast::Insertion::~Insertion( )
1612 void
1613 Ast::Insertion::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1615 stateRef_->analyze( this, env, freeStatesDst ); /* This will always add something to the set of free states. */
1616 expr_->analyze( this, env, freeStatesDst );
1619 void
1620 Ast::Insertion::eval( Kernel::EvalState * evalState ) const
1622 evalState->cont_ = Kernel::ContRef( new Kernel::InsertionContinuation( stateRef_->getHandle( evalState->env_, evalState->dyn_ ),
1623 evalState->cont_,
1624 evalState->dyn_,
1625 expr_->loc( ) ) );
1626 evalState->expr_ = expr_;
1629 Ast::InsertionMutatorCall::InsertionMutatorCall( const Ast::SourceLocation & loc, Ast::Expression * expr )
1630 : Ast::Expression( loc ), expr_( expr )
1633 Ast::InsertionMutatorCall::~InsertionMutatorCall( )
1636 void
1637 Ast::InsertionMutatorCall::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1639 throw Exceptions::InternalError( loc_, "An InsertionMutatorCall was analyzed (the contained expression should have been extracted and replaced this object)." );
1642 void
1643 Ast::InsertionMutatorCall::eval( Kernel::EvalState * evalState ) const
1645 throw Exceptions::InternalError( loc_, "An InsertionMutatorCall was evaluated (the contained expression should have been extracted and replaced this object)." );
1649 Ast::Freeze::Freeze( const Ast::SourceLocation & idLoc, const Ast::PlacedIdentifier * id, size_t ** idPos )
1650 : Ast::Expression( idLoc ), id_( id ), idPos_( idPos )
1652 immediate_ = true;
1655 Ast::Freeze::~Freeze( )
1657 /* idPos shared and will be a memory leak which must not be deleted.
1658 * It would be easy to fix the leak using RefCountPtr< size_t >, but the leakage is constant space, so silly efficiency is prioritized.
1662 void
1663 Ast::Freeze::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1665 if( *idPos_ == 0 )
1667 *idPos_ = new size_t( env->findLocalStatePosition( loc( ), *id_ ) );
1670 freeStatesDst->insert( env->getStateID( **idPos_ ) );
1673 void
1674 Ast::Freeze::eval( Kernel::EvalState * evalState ) const
1676 evalState->env_->freeze( **idPos_, evalState, loc( ) );
1680 Ast::Peek::Peek( const Ast::SourceLocation & idLoc, Ast::StateReference * stateRef )
1681 : Ast::Expression( idLoc ), stateRef_( stateRef )
1683 immediate_ = true;
1686 Ast::Peek::~Peek( )
1688 /* idPos shared and will be a memory leak which must not be deleted.
1689 * It would be easy to fix the leak using RefCountPtr< size_t >, but the leakage is constant space, so silly efficiency is prioritized.
1693 void
1694 Ast::Peek::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1696 stateRef_->analyze( this, env, freeStatesDst ); /* This will always add something to the set of free states. */
1699 void
1700 Ast::Peek::eval( Kernel::EvalState * evalState ) const
1702 stateRef_->getHandle( evalState->env_, evalState->dyn_ )->peek( evalState, loc( ) );
1706 Ast::DynamicExpression::DynamicExpression( const Ast::SourceLocation & loc, Ast::Expression * expr )
1707 : Ast::Expression( loc ), expr_( expr )
1709 immediate_ = true;
1712 Ast::DynamicExpression::~DynamicExpression( )
1715 void
1716 Ast::DynamicExpression::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1718 Ast::StateIDSet * freeStates = new Ast::StateIDSet;
1719 expr_->analyze( this, env, freeStates );
1721 if( ! freeStates->empty( ) )
1723 Ast::theAnalysisErrorsList.push_back( new Exceptions::IllegalFreeStates( expr_->loc( ), freeStates, "dynamic expressions must be pure" ) );
1725 else
1727 delete freeStates;
1731 void
1732 Ast::DynamicExpression::eval( Kernel::EvalState * evalState ) const
1734 Kernel::ContRef cont = evalState->cont_;
1735 cont->takeValue( Kernel::ValueRef( new Lang::DynamicExpression( evalState->env_, expr_ ) ),
1736 evalState );
1740 Ast::LexiographicType::LexiographicType( const Ast::SourceLocation & loc, const Ast::Identifier * id, Kernel::Environment::LexicalKey ** idKey )
1741 : Ast::Expression( loc ), id_( id ), idKey_( idKey )
1743 immediate_ = true;
1746 Ast::LexiographicType::~LexiographicType( )
1748 delete id_;
1749 if( *idKey_ != 0 )
1751 delete *idKey_;
1753 delete idKey_; /* This can be done only as long as this is not shared! */
1756 void
1757 Ast::LexiographicType::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1759 if( *idKey_ == 0 )
1761 *idKey_ = new Kernel::Environment::LexicalKey( env->findLexicalTypeKey( loc_, *id_ ) );
1765 void
1766 Ast::LexiographicType::eval( Kernel::EvalState * evalState ) const
1768 evalState->env_->lookup( **idKey_, evalState );