Update procedures
[shapes.git] / source / astflow.cc
blob1cfe3be7a2537fac9c2e88fa9583b3848ce65de9
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 Henrik Tidefelt
19 #include "astflow.h"
20 #include "globals.h"
21 #include "shapesexceptions.h"
22 #include "astfun.h"
23 #include "continuations.h"
25 using namespace Shapes;
26 using namespace std;
29 // Shapes::IfExpr::IfExpr( const Ast::SourceLocation & _loc, Ast::Expression * _predicate, Ast::Expression * _consequence, Ast::Expression * _alternative )
30 // : Ast::Expression( _loc ), predicate( _predicate ), consequence( _consequence ), alternative( _alternative )
31 // {
32 // predicate->setParent( this );
33 // consequence->setParent( this );
34 // alternative->setParent( this );
35 // }
37 // Shapes::IfExpr::IfExpr( const Ast::SourceLocation & _loc, Ast::Expression * _predicate, Ast::Expression * _consequence )
38 // : loc( _loc ), predicate( _predicate ), consequence( _consequence ), alternative( 0 )
39 // {
40 // predicate->setParent( this );
41 // consequence->setParent( this );
42 // }
44 // Shapes::IfExpr::~IfExpr( )
45 // {
46 // delete predicate;
47 // delete consequence;
48 // if( alternative != 0 )
49 // {
50 // delete alternative;
51 // }
52 // }
54 // RefCountPtr< const Lang::Value >
55 // Shapes::IfExpr::value( Kernel::Environment::VariableHandle dstgroup, SimplePDF::PDF_out * pdfo, Kernel::GraphicsState * metaState, Kernel::PassedEnv env ) const
56 // {
57 // RefCountPtr< const Lang::Value > predUntyped( predicate->value( dstgroup, pdfo, metaState, env ) );
58 // typedef const Lang::Boolean PredType;
59 // PredType * predVal = dynamic_cast< PredType * >( predUntyped.getPtr( ) );
60 // if( predVal == 0 )
61 // {
62 // throw Exceptions::TypeMismatch( predicate, predVal->getTypeName( ), PredType::staticTypeName( ) );
63 // }
64 // if( predVal->val )
65 // {
66 // return consequence->value( dstgroup, pdfo, metaState, env );
67 // }
68 // else if( alternative != 0 )
69 // {
70 // return alternative->value( dstgroup, pdfo, metaState, env );
71 // }
72 // else
73 // {
74 // return Shapes::THE_VOID;
75 // }
76 // }
79 Ast::ForceExpr::ForceExpr( const Ast::SourceLocation & loc, Ast::Expression * expr )
80 : Ast::Expression( loc ), expr_( expr )
82 immediate_ = true;
85 Ast::ForceExpr::~ForceExpr( )
86 { }
88 void
89 Ast::ForceExpr::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
91 expr_->analyze( this, env, freeStatesDst );
94 void
95 Ast::ForceExpr::eval( Kernel::EvalState * evalState ) const
97 evalState->cont_ = Kernel::ContRef( new Kernel::ForcingContinuation( evalState->cont_, expr_->loc( ) ) );
98 evalState->expr_ = expr_;
102 Ast::LetDynamicECExpr::LetDynamicECExpr( const Ast::SourceLocation & loc, const Ast::SourceLocation & idLoc, const char * id, Ast::Expression * expr )
103 : Ast::Expression( loc ), idLoc_( idLoc, bool( ) ), id_( id ), expr_( expr )
105 /* Should this expression have
106 * immediate_ = true;
107 * or not? Looking at an example like the following, taken from the amb.blank example,
108 * (escape_continuation return
109 * [( \ dummy → nil )
110 * !(escape_continuation amb_fail
111 * (escape_continue return [fun]))])
112 * it might be tempting to make the explicit forcing superflous by setting the immediate_ flag.
113 * However, it would then also be required that the expression inside is also immediate, which it
114 * is not (see comment in shapesparser.yy). This setting immediate_ for this expression wouldn't
115 * solve the problem, and not being immediate_ is the normal state for an expression, this should
116 * be the best choice for this expression as well.
118 * What matters is not whether this expression is immedate or not. What matters is that expr_ is
119 * forced. If expr_ is not forced, this expression may first return with a thunk, and later when
120 * that thunk is forced, this expression may return again as a consequence of the escape continuation
121 * being invoked inside the thunk. Returning more than once from an expression seems like a very
122 * bad idea.
124 * It may even be considered a good thing that the explicit forcing is needed, making it clearly
125 * visible that tricky things are going on here.
129 Ast::LetDynamicECExpr::~LetDynamicECExpr( )
131 delete id_;
132 delete expr_;
135 void
136 Ast::LetDynamicECExpr::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
138 expr_->analyze( this, env, freeStatesDst );
141 void
142 Ast::LetDynamicECExpr::eval( Kernel::EvalState * evalState ) const
144 evalState->dyn_ = Kernel::PassedDyn( new Kernel::DynamicEnvironment( evalState->dyn_, id_, evalState->cont_ ) );
145 evalState->cont_ = Kernel::ContRef( new Kernel::ForcingContinuation( evalState->cont_, expr_->loc( ) ) );
146 evalState->expr_ = expr_;
149 Ast::ContinueDynamicECFunction::ContinueDynamicECFunction( const Ast::SourceLocation & idLoc, const char * id, Ast::Expression * expr )
150 : Lang::Function( new Kernel::EvaluatedFormals( Ast::FileID::build_internal( "< dynamic escape continuation >" ), true ) ), idLoc_( idLoc, bool( ) ), id_( id ), expr_( expr )
153 Ast::ContinueDynamicECFunction::~ContinueDynamicECFunction( )
155 delete expr_;
156 delete id_;
159 void
160 Ast::ContinueDynamicECFunction::push_exprs( Ast::ArgListExprs * args ) const
162 args->orderedExprs_->push_back( expr_ );
165 void
166 Ast::ContinueDynamicECFunction::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
168 /* Nothing to analyze?
171 /* expr_ shall be analyzed from the calling expression.
172 * Here, it is only used to locate errors.
176 void
177 Ast::ContinueDynamicECFunction::call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
179 Kernel::ContRef cont = evalState->dyn_->getEscapeContinuation( id_, idLoc_ );
180 evalState->cont_ = cont;
181 evalState->expr_ = 0; /* If the next call fails, it may be very confusing if expr_ points to something completely irrelevant to the error. */
182 cont->takeHandle( args.getHandle( 0 ),
183 evalState );
186 Ast::GetECBacktraceExpr::GetECBacktraceExpr( const Ast::SourceLocation & idLoc, const char * id )
187 : Ast::Expression( idLoc ), id_( id )
190 Ast::GetECBacktraceExpr::~GetECBacktraceExpr( )
193 void
194 Ast::GetECBacktraceExpr::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
196 /* Nothing to do. */
199 void
200 Ast::GetECBacktraceExpr::eval( Kernel::EvalState * evalState ) const
202 Kernel::ContRef cont = evalState->cont_;
203 cont->takeValue( Kernel::ValueRef( new Lang::Continuation( evalState->dyn_->getEscapeContinuation( id_, loc_ ) ) ),
204 evalState );