3 #include "shapestypes.h"
4 #include "shapesexceptions.h"
7 #include "angleselect.h"
11 #include "continuations.h"
14 //#include "clapack.h"
16 #include <gsl/gsl_matrix.h>
17 #include <gsl/gsl_linalg.h>
18 #include <gsl/gsl_blas.h>
22 using namespace Shapes
;
25 void displayArray( std::ostream
& os
, const double * pr
, size_t m
, size_t n
)
30 for( r
= 0; r
< m
; ++r
)
32 for( c
= 0; c
< n
; ++c
)
34 sprintf( buf
, "%14.5e", *( pr
+ ( r
+ c
* m
) ) );
41 void displayArray( std::ostream
& os
, const gsl_matrix
* m
)
44 for( size_t r
= 0; r
< m
->size1
; ++r
)
46 for( size_t c
= 0; c
< m
->size2
; ++c
)
48 sprintf( buf
, "%14.5e", gsl_matrix_get( m
, r
, c
) );
56 Lang::Transform2D::Transform2D( double xx
, double yx
, double xy
, double yy
, Concrete::Length xt
, Concrete::Length yt
)
57 : xx_( xx
), yx_( yx
), xy_( xy
), yy_( yy
), xt_( xt
), yt_( yt
)
60 Lang::Transform2D::Transform2D( const Lang::Transform2D
& tf2
, const Lang::Transform2D
& tf1
)
61 : xx_( tf2
.xx_
* tf1
.xx_
+ tf2
.xy_
* tf1
.yx_
),
62 yx_( tf2
.yx_
* tf1
.xx_
+ tf2
.yy_
* tf1
.yx_
),
63 xy_( tf2
.xx_
* tf1
.xy_
+ tf2
.xy_
* tf1
.yy_
),
64 yy_( tf2
.yx_
* tf1
.xy_
+ tf2
.yy_
* tf1
.yy_
),
65 xt_( tf2
.xx_
* tf1
.xt_
+ tf2
.xy_
* tf1
.yt_
+ tf2
.xt_
),
66 yt_( tf2
.yx_
* tf1
.xt_
+ tf2
.yy_
* tf1
.yt_
+ tf2
.yt_
)
69 DISPATCHIMPL( Transform2D
);
72 Lang::Transform2D::isIdentity( ) const
75 xt_
== Concrete::ZERO_LENGTH
&& yt_
== Concrete::ZERO_LENGTH
&&
76 xx_
== 1 && yy_
== 1 &&
81 Lang::Transform2D::isTranslation( ) const
84 xx_
== 1 && yy_
== 1 &&
89 Lang::Transform2D::shipout( std::ostream
& os
) const
91 os
<< xx_
<< " " << yx_
<< " " << xy_
<< " " << yy_
<< " "
92 << Concrete::Length::offtype( xt_
) << " " << Concrete::Length::offtype( yt_
) ;
95 // to be used by text moveto commands
97 Lang::Transform2D::replaceBy( const Lang::Transform2D
& newtf
)
107 // to be used by text newline commands
109 Lang::Transform2D::prependShift( const Concrete::Coords2D
& d
)
111 // Think of d as tf1 when composing transforms.
113 xt_
+= xx_
* d
.x_
+ xy_
* d
.y_
;
114 yt_
+= yx_
* d
.x_
+ yy_
* d
.y_
;
117 // to be used by text painting commands
119 Lang::Transform2D::prependXShift( const Concrete::Length
& dx
)
121 // Think of d as tf1 when composing transforms.
127 RefCountPtr
< const Lang::Class
> Lang::Transform2D::TypeID( new Lang::SystemFinalClass( strrefdup( "Transform2D" ) ) );
128 TYPEINFOIMPL( Transform2D
);
131 Lang::Transform2D::show( std::ostream
& os
) const
134 << xx_
<< ", " << yx_
<< ") ("
135 << xy_
<< ", " << yy_
<< ") ("
136 << Lang::Length( xt_
) << ", " << Lang::Length( yt_
) << ") ]" ;
140 Lang::Transform3D::Transform3D( double xx
, double yx
, double zx
, double xy
, double yy
, double zy
, double xz
, double yz
, double zz
, Concrete::Length xt
, Concrete::Length yt
, Concrete::Length zt
)
141 : planeNormalTransformData_( 0 ),
142 xx_( xx
), yx_( yx
), zx_( zx
), xy_( xy
), yy_( yy
), zy_( zy
), xz_( xz
), yz_( yz
), zz_( zz
), xt_( xt
), yt_( yt
), zt_( zt
)
145 Lang::Transform3D::Transform3D( const Lang::Transform3D
& tf2
, const Lang::Transform3D
& tf1
)
146 : planeNormalTransformData_( 0 ),
147 xx_( tf2
.xx_
* tf1
.xx_
+ tf2
.xy_
* tf1
.yx_
+ tf2
.xz_
* tf1
.zx_
),
148 yx_( tf2
.yx_
* tf1
.xx_
+ tf2
.yy_
* tf1
.yx_
+ tf2
.yz_
* tf1
.zx_
),
149 zx_( tf2
.zx_
* tf1
.xx_
+ tf2
.zy_
* tf1
.yx_
+ tf2
.zz_
* tf1
.zx_
),
150 xy_( tf2
.xx_
* tf1
.xy_
+ tf2
.xy_
* tf1
.yy_
+ tf2
.xz_
* tf1
.zy_
),
151 yy_( tf2
.yx_
* tf1
.xy_
+ tf2
.yy_
* tf1
.yy_
+ tf2
.yz_
* tf1
.zy_
),
152 zy_( tf2
.zx_
* tf1
.xy_
+ tf2
.zy_
* tf1
.yy_
+ tf2
.zz_
* tf1
.zy_
),
153 xz_( tf2
.xx_
* tf1
.xz_
+ tf2
.xy_
* tf1
.yz_
+ tf2
.xz_
* tf1
.zz_
),
154 yz_( tf2
.yx_
* tf1
.xz_
+ tf2
.yy_
* tf1
.yz_
+ tf2
.yz_
* tf1
.zz_
),
155 zz_( tf2
.zx_
* tf1
.xz_
+ tf2
.zy_
* tf1
.yz_
+ tf2
.zz_
* tf1
.zz_
),
156 xt_( tf2
.xx_
* tf1
.xt_
+ tf2
.xy_
* tf1
.yt_
+ tf2
.xz_
* tf1
.zt_
+ tf2
.xt_
),
157 yt_( tf2
.yx_
* tf1
.xt_
+ tf2
.yy_
* tf1
.yt_
+ tf2
.yz_
* tf1
.zt_
+ tf2
.yt_
),
158 zt_( tf2
.zx_
* tf1
.xt_
+ tf2
.zy_
* tf1
.yt_
+ tf2
.zz_
* tf1
.zt_
+ tf2
.zt_
)
161 DISPATCHIMPL( Transform3D
);
163 Lang::Transform3D::~Transform3D( )
165 if( planeNormalTransformData_
!= 0 )
167 gsl_matrix_free( planeNormalTransformData_
);
168 // delete planeNormalTransformData_;
173 Lang::Transform3D::isIdentity( ) const
176 xt_
== Concrete::ZERO_LENGTH
&& yt_
== Concrete::ZERO_LENGTH
&& zt_
== Concrete::ZERO_LENGTH
&&
177 xx_
== 1 && yy_
== 1 && zz_
== 1 &&
178 xy_
== 0 && xz_
== 0 && yx_
== 0 && yz_
== 0 && zx_
== 0 && zy_
== 0;
181 Concrete::UnitFloatTriple
182 Lang::Transform3D::transformPlaneUnitNormal( const Concrete::UnitFloatTriple
& n
) const
185 // These statically allocated matrices will leak memory. They could be removed by using a static automaitc
186 // deallocator object. However, since they shall not be deleted by delete (but by gsl_matrix_free), we cannot
187 // us RefCountPtr< gsl_matrix >.
188 static gsl_matrix
* a
= gsl_matrix_alloc( N
, N
);
189 static gsl_matrix
* v
= gsl_matrix_alloc( N
, N
);
190 static gsl_vector
* s
= gsl_vector_alloc( N
);
191 static gsl_vector
* work
= gsl_vector_alloc( N
);
194 // static __CLPK_integer mn = N;
195 // static char jobuvt = 'A';
197 // static double a[ N * N ];
198 // static double u[ N * N ];
199 // static double vt[ N * N ];
200 // __CLPK_integer ldauvt = N;
201 // static double s[ N ];
202 // __CLPK_integer lwork;
203 // __CLPK_integer info;
205 // static __CLPK_doublereal * work = 0;
206 // static RefCountPtr< __CLPK_doublereal > workCleaner;
210 // // Then we ask LAPACK how much workspace it wants, and then we assume that this number will not change
211 // // as we call DGESVD with other arguments.
215 // dgesvd_( & jobuvt, & jobuvt,
217 // reinterpret_cast< __CLPK_doublereal * >( & a ), & ldauvt,
218 // reinterpret_cast< __CLPK_doublereal * >( & s ),
219 // reinterpret_cast< __CLPK_doublereal * >( & u ), & ldauvt,
220 // reinterpret_cast< __CLPK_doublereal * >( & vt ), & ldauvt,
221 // reinterpret_cast< __CLPK_doublereal * >( & tmpwork ), & lwork,
223 // lwork = static_cast< __CLPK_integer >( tmpwork );
224 // work = new __CLPK_doublereal[ lwork ];
225 // workCleaner = RefCountPtr< __CLPK_doublereal >( work );
229 if( planeNormalTransformData_
== 0 )
231 // This is the first time this transform is used to transform a unit plane normal.
232 // The linear part of this transform must then be computed, and we use the singular
233 // value decomposition for this.
235 planeNormalTransformData_
= gsl_matrix_alloc( N
, N
);
237 gsl_matrix_set( a
, 0, 0, xx_
);
238 gsl_matrix_set( a
, 1, 0, yx_
);
239 gsl_matrix_set( a
, 2, 0, zx_
);
240 gsl_matrix_set( a
, 0, 1, xy_
);
241 gsl_matrix_set( a
, 1, 1, yy_
);
242 gsl_matrix_set( a
, 2, 1, zy_
);
243 gsl_matrix_set( a
, 0, 2, xz_
);
244 gsl_matrix_set( a
, 1, 2, yz_
);
245 gsl_matrix_set( a
, 2, 2, zz_
);
247 // std::cerr << "Here's a:" << std::endl ;
248 // displayArray( std::cerr, a );
251 int status
= gsl_linalg_SV_decomp( a
, v
, s
, work
);
254 throw Exceptions::ExternalError( "Gnu Scientific Library SVD routine failed." );
268 // dgesvd_( & jobuvt, & jobuvt,
270 // reinterpret_cast< __CLPK_doublereal * >( & a ), & ldauvt,
271 // reinterpret_cast< __CLPK_doublereal * >( & s ),
272 // reinterpret_cast< __CLPK_doublereal * >( & u ), & ldauvt,
273 // reinterpret_cast< __CLPK_doublereal * >( & vt ), & ldauvt,
274 // reinterpret_cast< __CLPK_doublereal * >( work ), & lwork,
279 // throw Exceptions::ExternalError( "LAPACK routine DGESVD failed." );
282 if( gsl_vector_get( s
, 1 ) < 1e-5 )
284 throw Exceptions::AffineTransformKillsPlane( gsl_vector_get( s
, 1 ) );
287 // std::cerr << "Here's s:" << std::endl ;
288 // gsl_vector_fprintf( stderr, s, "%f" );
290 gsl_vector_set( s
, 0, gsl_vector_get( s
, 2 ) / gsl_vector_get( s
, 0 ) );
291 gsl_vector_set( s
, 1, gsl_vector_get( s
, 2 ) / gsl_vector_get( s
, 1 ) );
294 // std::cerr << "Here's the modified s:" << std::endl ;
295 // gsl_vector_fprintf( stderr, s, "%f" );
298 // if( s[ 1 ] < 1e-5 )
300 // throw Exceptions::AffineTransformKillsPlane( s[ 1 ] );
303 // s[ 0 ] = s[ 2 ] / s[ 0 ];
304 // s[ 1 ] = s[ 2 ] / s[ 1 ];
307 // We will now compute " u * diag( s ) * vt ".
309 // Note that "u" is stored in a when gsl_linalg_SV_decomp is used.
311 // std::cerr << "Here's u:" << std::endl ;
312 // displayArray( std::cerr, a );
314 gsl_matrix_set( a
, 0, 0, gsl_matrix_get( a
, 0, 0 ) * gsl_vector_get( s
, 0 ) );
315 gsl_matrix_set( a
, 1, 0, gsl_matrix_get( a
, 1, 0 ) * gsl_vector_get( s
, 0 ) );
316 gsl_matrix_set( a
, 2, 0, gsl_matrix_get( a
, 2, 0 ) * gsl_vector_get( s
, 0 ) );
317 gsl_matrix_set( a
, 0, 1, gsl_matrix_get( a
, 0, 1 ) * gsl_vector_get( s
, 1 ) );
318 gsl_matrix_set( a
, 1, 1, gsl_matrix_get( a
, 1, 1 ) * gsl_vector_get( s
, 1 ) );
319 gsl_matrix_set( a
, 2, 1, gsl_matrix_get( a
, 2, 1 ) * gsl_vector_get( s
, 1 ) );
320 // Note that s[ 2 ] == 1
328 // // Note that s[ 2 ] == 1
330 // std::cerr << "Here's the modified a:" << std::endl ;
331 // displayArray( std::cerr, a );
333 // std::cerr << "Here's v:" << std::endl ;
334 // displayArray( std::cerr, v );
336 gsl_blas_dgemm( CblasNoTrans
,
342 planeNormalTransformData_
);
344 // std::cerr << "Here's the matrix:" << std::endl ;
345 // displayArray( std::cerr, planeNormalTransformData_ );
347 // cblas_dgemm( CblasColMajor, CblasNoTrans, CblasNoTrans,
352 // 0., planeNormalTransformData_, N );
355 // Now that the linear, not too singular, transform has been computed, we just apply it and normalize the result.
356 // The normalization is made by the UnitFloatTriple constructor.
358 static gsl_vector
* _n
= gsl_vector_alloc( N
);
359 static gsl_vector
* res
= gsl_vector_alloc( N
);
361 // static double _n[ N ];
362 // static double res[ N ];
364 gsl_vector_set( _n
, 0, n
.x_
);
365 gsl_vector_set( _n
, 1, n
.y_
);
366 gsl_vector_set( _n
, 2, n
.z_
);
372 // std::cerr << "Input vector: " << std::endl ;
373 // gsl_vector_fprintf( stderr, _n, "%f" );
374 // std::cerr << std::endl ;
376 gsl_blas_dgemv( CblasNoTrans
,
378 planeNormalTransformData_
,
383 // std::cerr << "Result: " << std::endl ;
384 // gsl_vector_fprintf( stderr, res, "%f" );
385 // std::cerr << std::endl ;
387 // cblas_dgemv( CblasColMajor, CblasNoTrans,
390 // planeNormalTransformData_, N,
391 // reinterpret_cast< double * >( & _n ), 1,
392 // 0., reinterpret_cast< double * >( & res ), 1 );
394 return Concrete::UnitFloatTriple( gsl_vector_get( res
, 0 ),
395 gsl_vector_get( res
, 1 ),
396 gsl_vector_get( res
, 2 ) );
397 // return Concrete::UnitFloatTriple( res[0], res[1], res[2] );
401 // First we compute a unit vector in the plane
402 static const Concrete::UnitFloatTriple xHat( 1, 0, 0 );
403 static const Concrete::UnitFloatTriple yHat( 0, 1, 0 );
404 Concrete::UnitFloatTriple r1 = Shapes::cross( unitNormal_, xHat );
405 Concrete::UnitFloatTriple r2 = Shapes::cross( unitNormal_, yHat );
406 Concrete::UnitFloatTriple r( 0, 0, 0 );
407 if( r1.norm( ) > r2.norm( ) )
409 r = r1.normalized( );
413 r = r2.normalized( );
416 // Then we find one point that is in the plane
417 double ax = fabs( unitNormal_.x_ );
418 double ay = fabs( unitNormal_.y_ );
419 double az = fabs( unitNormal_.z_ );
421 Concrete::Coords3D x0( 0, 0, 0 );
422 if( ax >= ay && ax >= az )
424 x0 = Concrete::Coords3D( m_ / unitNormal_.x_, 0, 0 );
428 x0 = Concrete::Coords3D( 0, m_ / unitNormal_.y_, 0 );
432 x0 = Concrete::Coords3D( 0, 0, m_ / unitNormal_.z_ );
435 // Now it is easy to find two more points that span the plane together with x0
436 Concrete::Coords3D x1 = x0 + r;
437 Concrete::Coords3D x2 = x0 + Shapes::cross( unitNormal_, r );
439 // Now we see where these points go...
440 Concrete::Coords3D Tx0 = x0.transformed( tf );
441 Concrete::Coords3D Tx1 = x1.transformed( tf );
442 Concrete::Coords3D Tx2 = x2.transformed( tf );
444 // ... from which the new equation may be computed.
445 Concrete::UnitFloatTriple Tnormal = Shapes::cross( Tx1 - Tx0, Tx2 - Tx0 );
446 double TnormalNorm = Tnormal.norm( );
447 if( TnormalNorm == 0 )
449 // A polygon of lower dimension is invisible, so we may just return without pushing any triangles.
452 Concrete::UnitFloatTriple TunitNormal = Tnormal * ( 1 / TnormalNorm );
456 RefCountPtr
< const Lang::Class
> Lang::Transform3D::TypeID( new Lang::SystemFinalClass( strrefdup( "Transform3D" ) ) );
457 TYPEINFOIMPL( Transform3D
);
460 Lang::Transform3D::show( std::ostream
& os
) const
463 << xx_
<< ", " << yx_
<< ", " << zx_
<< ") ("
464 << xy_
<< ", " << yy_
<< ", " << zy_
<< ") ("
465 << xz_
<< ", " << yz_
<< ", " << zz_
<< ") ("
466 << Lang::Length( xt_
) << ", " << Lang::Length( yt_
) << ", " << Lang::Length( zt_
) << ") ]" ;
470 Kernel::Arguments::Arguments( const Kernel::EvaluatedFormals
* formals
)
471 : formals_( formals
), variables_( new Environment::ValueVector::ValueType
), dst_( 0 ),
472 hasSink_( formals_
->formals_
->hasSink( ) ),
473 dstEnd_( formals_
->formals_
->defaultExprs_
.size( ) ),
474 isSink_( formals_
->isSink_
),
475 sinkArgList_( 0 ), sinkValues_( NullPtr
< const Lang::SingleList
>( ) ),
476 states_( new Environment::StateVector::ValueType
), stateDst_( 0 ),
481 sinkArgList_
= new Ast::ArgListExprs( false ); // This is not an expression-owner.
482 sinkValues_
= RefCountPtr
< const Lang::SingleList
>( new Lang::SingleListNull( ) );
483 if( formals_
->formals_
->argumentOrder_
->empty( ) )
485 // All arguments go in the sink.
489 // Thinking of all the evaluated cuts, it actually makes some sense not to reserve memory here.
490 // variables_.reserve( formals_->argumentOrder_->size( ) );
491 // states_.reserve( formals_->stateOrder_->size( ) );
494 Kernel::Arguments::~Arguments( )
498 Kernel::Arguments::clone( ) const
501 if( ! states_
->empty( ) )
503 throw Exceptions::InternalError( "Arguments with states may not be cloned." );
507 Kernel::Arguments
res( formals_
);
509 res
.variables_
->reserve( variables_
->size( ) );
511 typedef typeof *variables_ ListType
;
512 for( ListType::const_iterator i
= variables_
->begin( ); i
!= variables_
->end( ); ++i
)
514 res
.variables_
->push_back( *i
);
517 res
.locations_
= locations_
;
519 if( sinkArgList_
!= 0 )
521 throw Exceptions::NotImplemented( "Cloning of arguments with sink." );
522 //res.sinkArgList_ = sinkArgList_->clone( );
523 res
.sinkValues_
= sinkValues_
;
531 Kernel::Arguments::addOrderedArgument( const Kernel::VariableHandle
& arg
, Ast::Expression
* loc
)
533 /* Recall that if there's a sink, this will be the last argument.
538 /* If there is a sink, put it there. Otherwise, we have detected an arity mismatch, but to generate a good
539 * error message we don't throw the message from here, but rest assured that an error will be delivered in
540 * due time when applyDefaults is invoked.
544 sinkArgList_
->orderedExprs_
->push_back( loc
);
545 sinkValues_
= RefCountPtr
< Lang::SingleList
>( new Lang::SingleListPair( arg
, sinkValues_
) );
549 variables_
->push_back( arg
);
550 locations_
.push_back( loc
);
551 ++dst_
; // I'm not sure this is meaningful here...
554 else if( dst_
== variables_
->size( ) )
556 variables_
->push_back( arg
);
557 locations_
.push_back( loc
);
562 (*variables_
)[ dst_
] = arg
;
563 locations_
[ dst_
] = loc
;
564 while( dst_
< variables_
->size( ) &&
565 (*variables_
)[ dst_
] != Kernel::THE_SLOT_VARIABLE
)
573 Kernel::Arguments::addNamedArgument( const char * id
, const Kernel::VariableHandle
& arg
, Ast::Expression
* loc
)
577 throw Exceptions::CoreNoNamedFormals( "???" );
580 typedef typeof *(formals_
->formals_
->argumentOrder_
) FormalsMapType
;
581 FormalsMapType
& formalsMap
= *(formals_
->formals_
->argumentOrder_
);
583 /* Note that the name of the sink is invisible, so referring to it is just another arguments which is
584 * put in the sink. This variable happens to have the same name as the sink.
586 FormalsMapType::const_iterator j
= formalsMap
.find( id
);
587 if( j
== formalsMap
.end( ) ||
589 j
->second
== dstEnd_
) )
593 if( sinkArgList_
->namedExprs_
->find( id
) != sinkArgList_
->namedExprs_
->end( ) )
595 throw Exceptions::InternalError( "It is a surprise that the sink got a repeated formal." );
597 sinkArgList_
->namedExprs_
->insert( std::pair
< const char *, Ast::Expression
* >( id
, loc
) );
598 sinkValues_
= RefCountPtr
< Lang::SingleList
>( new Lang::SingleListPair( arg
, sinkValues_
) );
601 throw Exceptions::NamedFormalMismatch( formals_
->formals_
->loc( ), strrefdup( id
), Exceptions::NamedFormalMismatch::VARIABLE
);
603 size_t pos
= j
->second
;
607 throw Exceptions::NamedFormalAlreadySpecified( formals_
->formals_
->loc( ), strrefdup( id
), pos
, Exceptions::NamedFormalAlreadySpecified::VARIABLE
);
610 if( pos
>= variables_
->size( ) )
612 while( variables_
->size( ) < pos
)
614 variables_
->push_back( Kernel::THE_SLOT_VARIABLE
);
615 locations_
.push_back( 0 );
617 variables_
->push_back( arg
);
618 locations_
.push_back( loc
);
622 if( (*variables_
)[ pos
] != Kernel::THE_SLOT_VARIABLE
)
624 throw Exceptions::NamedFormalAlreadySpecified( formals_
->formals_
->loc( ), strrefdup( id
), pos
, Exceptions::NamedFormalAlreadySpecified::VARIABLE
);
626 (*variables_
)[ pos
] = arg
;
627 locations_
[ pos
] = loc
;
631 while( dst_
< variables_
->size( ) &&
632 (*variables_
)[ dst_
] != Kernel::THE_SLOT_VARIABLE
)
640 Kernel::Arguments::addOrderedState( const Kernel::StateHandle
& state
, Ast::Node
* loc
)
642 if( stateDst_
== states_
->size( ) )
644 states_
->push_back( state
);
645 stateLocations_
.push_back( loc
);
650 (*states_
)[ stateDst_
] = state
;
651 stateLocations_
[ stateDst_
] = loc
;
652 while( stateDst_
< states_
->size( ) &&
653 (*states_
)[ stateDst_
] != Kernel::THE_SLOT_STATE
)
661 Kernel::Arguments::addNamedState( const char * id
, const Kernel::StateHandle
& state
, Ast::Node
* loc
)
665 throw Exceptions::CoreNoNamedFormals( "???" );
668 typedef typeof *(formals_
->formals_
->stateOrder_
) FormalsMapType
;
669 FormalsMapType
& formalsMap
= *(formals_
->formals_
->stateOrder_
);
671 FormalsMapType::const_iterator j
= formalsMap
.find( id
);
672 if( j
== formalsMap
.end( ) )
674 throw Exceptions::NamedFormalMismatch( formals_
->formals_
->loc( ), strrefdup( id
), Exceptions::NamedFormalMismatch::STATE
);
676 size_t pos
= j
->second
;
678 if( pos
< stateDst_
)
680 throw Exceptions::NamedFormalAlreadySpecified( formals_
->formals_
->loc( ), strrefdup( id
), pos
, Exceptions::NamedFormalAlreadySpecified::STATE
);
683 if( pos
>= states_
->size( ) )
685 while( states_
->size( ) < pos
)
687 states_
->push_back( Kernel::THE_SLOT_STATE
);
688 stateLocations_
.push_back( 0 );
690 states_
->push_back( state
);
691 stateLocations_
.push_back( loc
);
695 if( (*states_
)[ pos
] != Kernel::THE_SLOT_STATE
)
697 throw Exceptions::NamedFormalAlreadySpecified( formals_
->formals_
->loc( ), strrefdup( id
), pos
, Exceptions::NamedFormalAlreadySpecified::STATE
);
699 (*states_
)[ pos
] = state
;
700 stateLocations_
[ pos
] = loc
;
702 if( pos
== stateDst_
)
704 while( stateDst_
< states_
->size( ) &&
705 (*states_
)[ stateDst_
] != Kernel::THE_SLOT_STATE
)
713 Kernel::Arguments::applyDefaults( )
720 size_t numberOfArguments
= variables_
->size( );
721 size_t formalsSize
= formals_
->defaults_
.size( );
723 if( numberOfArguments
> formalsSize
&&
726 /* The location of the ball must be set by the caller. */
727 throw Exceptions::UserArityMismatch( formals_
->formals_
->loc( ), formalsSize
, numberOfArguments
, Exceptions::UserArityMismatch::VARIABLE
);
730 size_t numberOfStates
= states_
->size( );
731 size_t formalsStateSize
= formals_
->formals_
->stateOrder_
->size( );
732 if( numberOfStates
> formalsStateSize
)
734 /* The location of the ball must be set by the caller. */
735 throw Exceptions::UserArityMismatch( formals_
->formals_
->loc( ), formalsStateSize
, numberOfStates
, Exceptions::UserArityMismatch::STATE
);
738 /* First the easy part: All states must be specified.
740 std::map
< size_t, RefCountPtr
< const char > > * missingStates
= 0;
743 typedef typeof *states_ ListType
;
744 for( ListType::const_iterator i
= states_
->begin( ); i
!= states_
->end( ); ++i
, ++pos
)
746 if( *i
== Kernel::THE_SLOT_STATE
)
748 if( missingStates
== 0 )
750 missingStates
= new typeof *missingStates
;
752 typedef typeof *(formals_
->formals_
->stateOrder_
) FormalsMapType
;
753 FormalsMapType
& formalsMap
= *(formals_
->formals_
->stateOrder_
);
754 for( FormalsMapType::const_iterator i
= formalsMap
.begin( ); ; )
756 if( i
->second
== pos
)
758 missingStates
->insert( missingStates
->begin( ), std::pair
< size_t, RefCountPtr
< const char > >( pos
, strrefdup( i
->first
) ) );
762 if( i
== formalsMap
.end( ) )
764 throw Exceptions::InternalError( "Failed to find position of missing state." );
771 if( numberOfStates
< formalsStateSize
)
773 if( missingStates
== 0 )
775 missingStates
= new typeof *missingStates
;
777 typedef typeof *(formals_
->formals_
->stateOrder_
) FormalsMapType
;
778 FormalsMapType
& formalsMap
= *(formals_
->formals_
->stateOrder_
);
779 FormalsMapType::const_iterator i
= formalsMap
.begin( );
780 for( size_t j
= 0; j
< numberOfStates
; ++j
)
785 for( ; i
!= formalsMap
.end( ); ++i
, ++pos
)
787 missingStates
->insert( missingStates
->begin( ), std::pair
< size_t, RefCountPtr
< const char > >( pos
, strrefdup( i
->first
) ) );
793 /* Allocate positions in the vector for all arguments.
795 variables_
->reserve( hasSink_
? formalsSize
+ 1 : formalsSize
);
796 while( variables_
->size( ) < formalsSize
)
798 variables_
->push_back( Kernel::THE_SLOT_VARIABLE
);
800 locations_
.resize( formalsSize
);
802 typedef typeof *variables_ MyListType
;
803 typedef typeof formals_
->defaults_ DefaultListType
;
804 typedef typeof formals_
->locations_ LocationListType
;
805 DefaultListType::const_iterator src
= formals_
->defaults_
.begin( );
806 LocationListType::const_iterator srcLoc
= formals_
->locations_
.begin( );
807 std::map
< size_t, RefCountPtr
< const char > > * missingArgs
= 0;
809 typedef typeof locations_ MyLocationsType
;
810 for( MyListType::iterator dst
= variables_
->begin( ); dst
!= variables_
->end( ); ++dst
, ++src
, ++srcLoc
, ++pos
)
812 if( *dst
== Kernel::THE_SLOT_VARIABLE
)
814 /* Handle error situation.
816 if( *src
== Kernel::THE_SLOT_VARIABLE
)
818 if( missingArgs
== 0 )
820 missingArgs
= new typeof *missingArgs
;
822 typedef typeof *(formals_
->formals_
->argumentOrder_
) FormalsMapType
;
823 FormalsMapType
& formalsMap
= *(formals_
->formals_
->argumentOrder_
);
824 for( FormalsMapType::const_iterator i
= formalsMap
.begin( ); ; )
826 if( i
->second
== pos
)
828 missingArgs
->insert( missingArgs
->begin( ), std::pair
< size_t, RefCountPtr
< const char > >( pos
, strrefdup( i
->first
) ) );
832 if( i
== formalsMap
.end( ) )
834 throw Exceptions::InternalError( "Failed to find position of missing argument." );
842 locations_
[ pos
] = *srcLoc
;
846 if( missingArgs
!= 0 || missingStates
!= 0 )
848 throw Exceptions::MissingArguments( formals_
->formals_
->loc( ), missingArgs
, missingStates
);
853 variables_
->push_back
854 ( Helpers::newValHandle
855 ( new Lang::Structure( sinkArgList_
,
857 true ) ) ); // true means that the sinkArgList_ gets owned by the Structure.
863 Kernel::VariableHandle
&
864 Kernel::Arguments::getHandle( size_t i
)
866 return (*variables_
)[ i
];
869 RefCountPtr
< const Lang::Value
> &
870 Kernel::Arguments::getValue( size_t i
)
872 return (*variables_
)[ i
]->getUntyped( );
875 const Ast::SourceLocation
&
876 Kernel::Arguments::getLoc( size_t i
) const
878 return locations_
[ i
]->loc( );
882 Kernel::Arguments::getNode( size_t i
) const
884 return locations_
[ i
];
888 Kernel::Arguments::getThunk( size_t i
)
890 return (*variables_
)[ i
]->copyThunk( );
894 Kernel::Arguments::isSlot( size_t i
) const
896 return (*variables_
)[ i
] == Kernel::THE_SLOT_VARIABLE
;
900 Kernel::Arguments::getState( size_t i
)
902 return (*states_
)[ i
];
905 const Ast::SourceLocation
&
906 Kernel::Arguments::getStateLoc( size_t i
) const
908 return stateLocations_
[ i
]->loc( );
912 Kernel::Arguments::size( ) const
914 return variables_
->size( );
918 Kernel::Arguments::empty( ) const
920 return variables_
->empty( );
924 Kernel::Arguments::setMutatorSelf( Kernel::StateHandle mutatorSelf
)
926 mutatorSelf_
= mutatorSelf
;
930 Kernel::Arguments::getMutatorSelf( )
932 if( mutatorSelf_
== 0 )
934 throw Exceptions::InternalError( "Kernel::Arguments::getMutatorSelf: self is null." );
940 Kernel::Arguments::gcMark( Kernel::GCMarkedSet
& marked
)
943 typedef typeof *variables_ ListType
;
944 for( ListType::const_iterator i
= variables_
->begin( ); i
!= variables_
->end( ); ++i
)
946 const_cast< Kernel::Variable
* >( i
->getPtr( ) )->gcMark( marked
);
951 Kernel::Environment::ValueVector
952 Kernel::Arguments::getVariables( )
957 Kernel::Environment::StateVector
958 Kernel::Arguments::getStates( )
969 class FunctionOneHandleCont
: public Kernel::Continuation
971 RefCountPtr
< const Lang::Function
> fun_
;
972 Kernel::PassedDyn dyn_
;
973 Kernel::ContRef cont_
;
975 FunctionOneHandleCont( const RefCountPtr
< const Lang::Function
> & fun
, const Kernel::PassedDyn
& dyn
, Kernel::ContRef cont
, const Ast::SourceLocation
& traceLoc
)
976 : Kernel::Continuation( traceLoc
), fun_( fun
), dyn_( dyn
), cont_( cont
)
978 virtual ~FunctionOneHandleCont( ) { }
979 virtual void takeHandle( Kernel::VariableHandle val
, Kernel::EvalState
* evalState
, bool dummy
) const
981 /* This continuation really seeks forced arguments, for otherwise a thunk would have been generated directly.
982 * However, this continuation takes handles anyway, since handles is what goes into the argument list.
985 if( val
->isThunk( ) )
987 val
->force( val
, evalState
);
991 Kernel::Arguments args
= fun_
->newCurriedArguments( );
992 args
.addOrderedArgument( val
, & Ast::THE_INTERNAL_VALUE_EXPRESSION
);
994 evalState
->dyn_
= dyn_
;
995 evalState
->cont_
= cont_
;
996 fun_
->call( evalState
, args
, traceLoc_
);
998 virtual void backTrace( std::list
< Kernel::Continuation::BackTraceElem
> * trace
) const
1000 trace
->push_front( Kernel::Continuation::BackTraceElem( this, "internal function call with one handle" ) );
1001 cont_
->backTrace( trace
);
1003 virtual void gcMark( Kernel::GCMarkedSet
& marked
)
1005 const_cast< Lang::Function
* >( fun_
.getPtr( ) )->gcMark( marked
);
1006 dyn_
->gcMark( marked
);
1007 cont_
->gcMark( marked
);
1011 class FunctionTwoHandlesCont_2
: public Kernel::Continuation
1013 RefCountPtr
< const Lang::Function
> fun_
;
1014 Kernel::VariableHandle arg1_
;
1015 Kernel::PassedDyn dyn_
;
1016 Kernel::ContRef cont_
;
1018 FunctionTwoHandlesCont_2( const RefCountPtr
< const Lang::Function
> & fun
, const Kernel::VariableHandle
& arg1
, const Kernel::PassedDyn
& dyn
, Kernel::ContRef cont
, const Ast::SourceLocation
& traceLoc
)
1019 : Kernel::Continuation( traceLoc
), fun_( fun
), arg1_( arg1
), dyn_( dyn
), cont_( cont
)
1021 virtual ~FunctionTwoHandlesCont_2( ) { }
1022 virtual void takeHandle( Kernel::VariableHandle arg2
, Kernel::EvalState
* evalState
, bool dummy
) const
1024 /* This continuation really seeks forced arguments, for otherwise a thunk would have been generated directly.
1025 * However, this continuation takes handles anyway, since handles is what goes into the argument list.
1028 if( arg2
->isThunk( ) )
1030 arg2
->force( arg2
, evalState
);
1034 Kernel::Arguments args
= fun_
->newCurriedArguments( );
1035 args
.addOrderedArgument( arg1_
, & Ast::THE_INTERNAL_VALUE_EXPRESSION
);
1036 args
.addOrderedArgument( arg2
, & Ast::THE_INTERNAL_VALUE_EXPRESSION
);
1037 evalState
->dyn_
= dyn_
;
1038 evalState
->cont_
= cont_
;
1039 fun_
->call( evalState
, args
, traceLoc_
);
1041 virtual void backTrace( std::list
< Kernel::Continuation::BackTraceElem
> * trace
) const
1043 trace
->push_front( Kernel::Continuation::BackTraceElem( this, "internal function call with two handles, second" ) );
1044 cont_
->backTrace( trace
);
1046 virtual void gcMark( Kernel::GCMarkedSet
& marked
)
1048 const_cast< Lang::Function
* >( fun_
.getPtr( ) )->gcMark( marked
);
1049 dyn_
->gcMark( marked
);
1050 cont_
->gcMark( marked
);
1054 class FunctionTwoHandlesCont_1
: public Kernel::Continuation
1056 RefCountPtr
< const Lang::Function
> fun_
;
1057 Kernel::VariableHandle arg2_
;
1059 Kernel::PassedDyn dyn_
;
1060 Kernel::ContRef cont_
;
1062 FunctionTwoHandlesCont_1( const RefCountPtr
< const Lang::Function
> & fun
, const Kernel::VariableHandle
& arg2
, bool forceArg2
, const Kernel::PassedDyn
& dyn
, Kernel::ContRef cont
, const Ast::SourceLocation
& traceLoc
)
1063 : Kernel::Continuation( traceLoc
), fun_( fun
), arg2_( arg2
), forceArg2_( forceArg2
), dyn_( dyn
), cont_( cont
)
1065 virtual ~FunctionTwoHandlesCont_1( ) { }
1066 virtual void takeHandle( Kernel::VariableHandle arg1
, Kernel::EvalState
* evalState
, bool dummy
) const
1068 /* This continuation really seeks forced arguments, for otherwise a thunk would have been generated directly.
1069 * However, this continuation takes handles anyway, since handles is what goes into the argument list.
1072 if( arg1
->isThunk( ) )
1074 arg1
->force( arg1
, evalState
);
1080 Kernel::ContRef newCont
= Kernel::ContRef( new Kernel::FunctionTwoHandlesCont_2( fun_
, arg1
, dyn_
, cont_
, traceLoc_
) );
1081 evalState
->cont_
= newCont
;
1082 newCont
->takeHandle( arg2_
, evalState
);
1086 /* The second handle need not be forced
1088 Kernel::Arguments args
= fun_
->newCurriedArguments( );
1089 args
.addOrderedArgument( arg1
, & Ast::THE_INTERNAL_VALUE_EXPRESSION
);
1090 args
.addOrderedArgument( arg2_
, & Ast::THE_INTERNAL_VALUE_EXPRESSION
);
1091 evalState
->dyn_
= dyn_
;
1092 evalState
->cont_
= cont_
;
1093 fun_
->call( evalState
, args
, traceLoc_
);
1095 virtual void backTrace( std::list
< Kernel::Continuation::BackTraceElem
> * trace
) const
1097 trace
->push_front( Kernel::Continuation::BackTraceElem( this, "internal function call with two handles, first" ) );
1098 cont_
->backTrace( trace
);
1100 virtual void gcMark( Kernel::GCMarkedSet
& marked
)
1102 const_cast< Lang::Function
* >( fun_
.getPtr( ) )->gcMark( marked
);
1103 dyn_
->gcMark( marked
);
1104 cont_
->gcMark( marked
);
1108 class FunctionTwoHandlesOneStateCont_2
: public Kernel::Continuation
1110 RefCountPtr
< const Lang::Function
> fun_
;
1111 Kernel::VariableHandle arg1_
;
1112 Kernel::StateHandle state_
;
1113 Kernel::PassedDyn dyn_
;
1114 Kernel::ContRef cont_
;
1116 FunctionTwoHandlesOneStateCont_2( const RefCountPtr
< const Lang::Function
> & fun
, const Kernel::VariableHandle
& arg1
, Kernel::StateHandle state
, const Kernel::PassedDyn
& dyn
, Kernel::ContRef cont
, const Ast::SourceLocation
& traceLoc
)
1117 : Kernel::Continuation( traceLoc
), fun_( fun
), arg1_( arg1
), state_( state
), dyn_( dyn
), cont_( cont
)
1119 virtual ~FunctionTwoHandlesOneStateCont_2( ) { }
1120 virtual void takeHandle( Kernel::VariableHandle arg2
, Kernel::EvalState
* evalState
, bool dummy
) const
1122 /* This continuation really seeks forced arguments, for otherwise a thunk would have been generated directly.
1123 * However, this continuation takes handles anyway, since handles is what goes into the argument list.
1126 if( arg2
->isThunk( ) )
1128 arg2
->force( arg2
, evalState
);
1132 Kernel::Arguments args
= fun_
->newCurriedArguments( );
1133 args
.addOrderedArgument( arg1_
, & Ast::THE_INTERNAL_VALUE_EXPRESSION
);
1134 args
.addOrderedArgument( arg2
, & Ast::THE_INTERNAL_VALUE_EXPRESSION
);
1135 args
.addOrderedState( state_
, & Ast::THE_INTERNAL_VALUE_EXPRESSION
);
1136 evalState
->dyn_
= dyn_
;
1137 evalState
->cont_
= cont_
;
1138 fun_
->call( evalState
, args
, traceLoc_
);
1140 virtual void backTrace( std::list
< Kernel::Continuation::BackTraceElem
> * trace
) const
1142 trace
->push_front( Kernel::Continuation::BackTraceElem( this, "internal function call with two handles and one state, second" ) );
1143 cont_
->backTrace( trace
);
1145 virtual void gcMark( Kernel::GCMarkedSet
& marked
)
1147 const_cast< Lang::Function
* >( fun_
.getPtr( ) )->gcMark( marked
);
1148 state_
->gcMark( marked
);
1149 dyn_
->gcMark( marked
);
1150 cont_
->gcMark( marked
);
1154 class FunctionTwoHandlesOneStateCont_1
: public Kernel::Continuation
1156 RefCountPtr
< const Lang::Function
> fun_
;
1157 Kernel::VariableHandle arg2_
;
1159 Kernel::StateHandle state_
;
1160 Kernel::PassedDyn dyn_
;
1161 Kernel::ContRef cont_
;
1163 FunctionTwoHandlesOneStateCont_1( const RefCountPtr
< const Lang::Function
> & fun
, const Kernel::VariableHandle
& arg2
, bool forceArg2
, Kernel::StateHandle state
, const Kernel::PassedDyn
& dyn
, Kernel::ContRef cont
, const Ast::SourceLocation
& traceLoc
)
1164 : Kernel::Continuation( traceLoc
), fun_( fun
), arg2_( arg2
), forceArg2_( forceArg2
), state_( state
), dyn_( dyn
), cont_( cont
)
1166 virtual ~FunctionTwoHandlesOneStateCont_1( ) { }
1167 virtual void takeHandle( Kernel::VariableHandle arg1
, Kernel::EvalState
* evalState
, bool dummy
) const
1169 /* This continuation really seeks forced arguments, for otherwise a thunk would have been generated directly.
1170 * However, this continuation takes handles anyway, since handles is what goes into the argument list.
1173 if( arg1
->isThunk( ) )
1175 arg1
->force( arg1
, evalState
);
1181 Kernel::ContRef newCont
= Kernel::ContRef( new Kernel::FunctionTwoHandlesOneStateCont_2( fun_
, arg1
, state_
, dyn_
, cont_
, traceLoc_
) );
1182 evalState
->cont_
= newCont
;
1183 newCont
->takeHandle( arg2_
, evalState
);
1187 /* The second handle need not be forced
1189 Kernel::Arguments args
= fun_
->newCurriedArguments( );
1190 args
.addOrderedArgument( arg1
, & Ast::THE_INTERNAL_VALUE_EXPRESSION
);
1191 args
.addOrderedArgument( arg2_
, & Ast::THE_INTERNAL_VALUE_EXPRESSION
);
1192 args
.addOrderedState( state_
, & Ast::THE_INTERNAL_VALUE_EXPRESSION
);
1193 evalState
->dyn_
= dyn_
;
1194 evalState
->cont_
= cont_
;
1195 fun_
->call( evalState
, args
, traceLoc_
);
1197 virtual void backTrace( std::list
< Kernel::Continuation::BackTraceElem
> * trace
) const
1199 trace
->push_front( Kernel::Continuation::BackTraceElem( this, "internal function call with two handles and one state, first" ) );
1200 cont_
->backTrace( trace
);
1202 virtual void gcMark( Kernel::GCMarkedSet
& marked
)
1204 const_cast< Lang::Function
* >( fun_
.getPtr( ) )->gcMark( marked
);
1205 dyn_
->gcMark( marked
);
1206 cont_
->gcMark( marked
);
1207 state_
->gcMark( marked
);
1215 Lang::Function::Function( Kernel::EvaluatedFormals
* formals
)
1216 : formals_( formals
)
1219 DISPATCHIMPL( Function
);
1221 Lang::Function::~Function( )
1225 delete formals_
->formals_
;
1231 Lang::Function::transformed( const Lang::Transform2D
& tf
, Kernel::ValueRef self
) const
1233 return Kernel::ValueRef( new Lang::TransformedFunction2D( tf
, self
.down_cast
< const Lang::Function
>( ) ) );
1237 Lang::Function::isProcedural( ) const
1243 Lang::Function::inScope( Kernel::PassedEnv env
) const
1249 Lang::Function::call( Kernel::EvalState
* evalState
, const Kernel::ValueRef
& arg1
, const Ast::SourceLocation
& callLoc
) const
1251 Kernel::Arguments args
= this->newCurriedArguments( );
1253 args
.addOrderedArgument( Kernel::VariableHandle( new Kernel::Variable( arg1
) ), & Ast::THE_INTERNAL_VALUE_EXPRESSION
);
1255 this->call( evalState
, args
, callLoc
);
1259 Lang::Function::analyze( Ast::Node
* parent
, const Ast::AnalysisEnvironment
* env
)
1261 throw Exceptions::InternalError( "A syntax function is not overriding the analyze method." );
1265 Lang::Function::call( Kernel::EvalState
* evalState
, const Kernel::ValueRef
& arg1
, const Kernel::ValueRef
& arg2
, const Ast::SourceLocation
& callLoc
) const
1267 Kernel::Arguments args
= this->newCurriedArguments( );
1269 args
.addOrderedArgument( Kernel::VariableHandle( new Kernel::Variable( arg1
) ), & Ast::THE_INTERNAL_VALUE_EXPRESSION
);
1270 args
.addOrderedArgument( Kernel::VariableHandle( new Kernel::Variable( arg2
) ), & Ast::THE_INTERNAL_VALUE_EXPRESSION
);
1272 this->call( evalState
, args
, callLoc
);
1275 Ast::ArgListExprs
* Lang::Function::oneExprArgList
= new Ast::ArgListExprs( static_cast< size_t >( 1 ) );
1276 Ast::ArgListExprs
* Lang::Function::twoExprsArgList
= new Ast::ArgListExprs( static_cast< size_t >( 2 ) );
1279 Lang::Function::call( const RefCountPtr
< const Lang::Function
> & selfRef
, Kernel::EvalState
* evalState
, const Kernel::VariableHandle
& arg1
, const Ast::SourceLocation
& callLoc
) const
1281 const RefCountPtr
< const Kernel::CallContInfo
> info
= this->newCallContInfo( Lang::Function::oneExprArgList
, *evalState
);
1283 if( info
->force( 0 ) )
1285 Kernel::ContRef cont
= Kernel::ContRef( new Kernel::FunctionOneHandleCont( selfRef
, evalState
->dyn_
, evalState
->cont_
, callLoc
) );
1286 evalState
->cont_
= cont
;
1287 cont
->takeHandle( arg1
, evalState
);
1291 /* The handle need not be forced
1293 Kernel::Arguments args
= this->newCurriedArguments( );
1294 args
.addOrderedArgument( arg1
, & Ast::THE_INTERNAL_VALUE_EXPRESSION
);
1295 this->call( evalState
, args
, callLoc
);
1299 Lang::Function::call( const RefCountPtr
< const Lang::Function
> & selfRef
, Kernel::EvalState
* evalState
, const Kernel::VariableHandle
& arg1
, const Kernel::VariableHandle
& arg2
, const Ast::SourceLocation
& callLoc
) const
1301 const RefCountPtr
< const Kernel::CallContInfo
> info
= this->newCallContInfo( Lang::Function::twoExprsArgList
, *evalState
);
1303 /* Remember that arguments are ordered backwards!
1306 if( info
->force( 1 ) )
1308 Kernel::ContRef cont
= Kernel::ContRef( new Kernel::FunctionTwoHandlesCont_1( selfRef
, arg2
, info
->force( 0 ), evalState
->dyn_
, evalState
->cont_
, callLoc
) );
1309 evalState
->cont_
= cont
;
1310 cont
->takeHandle( arg1
, evalState
);
1314 if( info
->force( 0 ) )
1316 Kernel::ContRef cont
= Kernel::ContRef( new Kernel::FunctionTwoHandlesCont_2( selfRef
, arg1
, evalState
->dyn_
, evalState
->cont_
, callLoc
) );
1317 evalState
->cont_
= cont
;
1318 cont
->takeHandle( arg2
, evalState
);
1322 /* None of the handles need to be forced
1324 Kernel::Arguments args
= this->newCurriedArguments( );
1325 args
.addOrderedArgument( arg1
, & Ast::THE_INTERNAL_VALUE_EXPRESSION
);
1326 args
.addOrderedArgument( arg2
, & Ast::THE_INTERNAL_VALUE_EXPRESSION
);
1327 this->call( evalState
, args
, callLoc
);
1331 Lang::Function::call( const RefCountPtr
< const Lang::Function
> & selfRef
, Kernel::EvalState
* evalState
, const Kernel::VariableHandle
& arg1
, const Kernel::VariableHandle
& arg2
, Kernel::StateHandle state
, const Ast::SourceLocation
& callLoc
) const
1333 /* I'm not quite sure if we should also put a dummy state argument in info...
1335 const RefCountPtr
< const Kernel::CallContInfo
> info
= this->newCallContInfo( Lang::Function::twoExprsArgList
, *evalState
);
1337 /* Remember that arguments are ordered backwards!
1340 if( info
->force( 1 ) )
1342 Kernel::ContRef cont
= Kernel::ContRef( new Kernel::FunctionTwoHandlesOneStateCont_1( selfRef
, arg2
, info
->force( 0 ), state
, evalState
->dyn_
, evalState
->cont_
, callLoc
) );
1343 evalState
->cont_
= cont
;
1344 cont
->takeHandle( arg1
, evalState
);
1348 if( info
->force( 0 ) )
1350 Kernel::ContRef cont
= Kernel::ContRef( new Kernel::FunctionTwoHandlesOneStateCont_2( selfRef
, arg1
, state
, evalState
->dyn_
, evalState
->cont_
, callLoc
) );
1351 evalState
->cont_
= cont
;
1352 cont
->takeHandle( arg2
, evalState
);
1356 /* None of the handles need to be forced
1358 Kernel::Arguments args
= this->newCurriedArguments( );
1359 args
.addOrderedArgument( arg1
, & Ast::THE_INTERNAL_VALUE_EXPRESSION
);
1360 args
.addOrderedArgument( arg2
, & Ast::THE_INTERNAL_VALUE_EXPRESSION
);
1361 args
.addOrderedState( state
, & Ast::THE_INTERNAL_VALUE_EXPRESSION
);
1362 this->call( evalState
, args
, callLoc
);
1366 RefCountPtr
< Kernel::CallContInfo
>
1367 Lang::Function::newCallContInfo( const Ast::ArgListExprs
* argList
, const Kernel::EvalState
& evalState
) const
1369 return formals_
->newCallContInfo( argList
, evalState
);
1372 RefCountPtr
< Kernel::CallContInfo
>
1373 Lang::Function::newCallContInfo( const Ast::ArgListExprs
* argList
, const Kernel::EvalState
& evalState
, const Kernel::Arguments
& curryArgs
) const
1375 return formals_
->newCallContInfo( argList
, evalState
, curryArgs
);
1379 Lang::Function::newCurriedArguments( ) const
1381 return Kernel::Arguments( formals_
);
1385 RefCountPtr
< const Lang::Class
> Lang::Function::TypeID( new Lang::SystemFinalClass( strrefdup( "Function" ) ) );
1386 TYPEINFOIMPL( Function
);
1388 Kernel::EvaluatedFormals::EvaluatedFormals( Kernel::Formals
* formals
)
1389 : selectiveForcing_( false ), forceAll_( false ), formals_( formals
), isSink_( true )
1392 Kernel::EvaluatedFormals::EvaluatedFormals( const char * locationString
)
1393 : selectiveForcing_( true ), formals_( 0 ), isSink_( true )
1395 Kernel::Formals
* formals( new Kernel::Formals( ) );
1396 formals
->setLoc( Ast::SourceLocation( locationString
) );
1400 Kernel::EvaluatedFormals::EvaluatedFormals( const char * locationString
, bool forceAll
)
1401 : selectiveForcing_( false ), forceAll_( forceAll
), formals_( 0 ), isSink_( true )
1403 Kernel::Formals
* formals( new Kernel::Formals( ) );
1404 formals
->setLoc( Ast::SourceLocation( locationString
) );
1408 Kernel::EvaluatedFormals::~EvaluatedFormals( )
1410 /* Don't delete the orderedFormals, since we don't own it. A case for reference counting? */
1413 RefCountPtr
< Kernel::CallContInfo
>
1414 Kernel::EvaluatedFormals::newCallContInfo( const Ast::ArgListExprs
* argList
, const Kernel::EvalState
& evalState
) const
1416 if( selectiveForcing_
)
1418 return RefCountPtr
< Kernel::CallContInfo
>( new Kernel::CallContInfo( argList
, evalState
, formals_
->newArgListForcePos( argList
) ) );
1422 return RefCountPtr
< Kernel::CallContInfo
>( new Kernel::CallContInfo( argList
, evalState
, forceAll_
) );
1426 RefCountPtr
< Kernel::CallContInfo
>
1427 Kernel::EvaluatedFormals::newCallContInfo( const Ast::ArgListExprs
* argList
, const Kernel::EvalState
& evalState
, const Kernel::Arguments
& curryArgs
) const
1429 if( selectiveForcing_
)
1431 return RefCountPtr
< Kernel::CallContInfo
>( new Kernel::CallContInfo( argList
, evalState
, formals_
->newArgListForcePos( argList
, curryArgs
) ) );
1435 return RefCountPtr
< Kernel::CallContInfo
>( new Kernel::CallContInfo( argList
, evalState
, forceAll_
) );
1440 Kernel::EvaluatedFormals::appendEvaluatedFormal( const char * id
, const Kernel::VariableHandle
& defaultVal
, const Ast::Node
* loc
, bool force
)
1442 if( ! selectiveForcing_
)
1444 throw Exceptions::InternalError( "EvaluatedFormals::appendEvaluatedFormal: Function does not have selective forcing." );
1446 (*(formals_
->argumentOrder_
))[ id
] = defaults_
.size( );
1447 formals_
->forcePos_
.push_back( force
);
1448 defaults_
.push_back( defaultVal
);
1449 locations_
.push_back( loc
);
1453 Kernel::EvaluatedFormals::appendEvaluatedFormal( const char * id
, const Kernel::VariableHandle
& defaultVal
, const Ast::Node
* loc
)
1455 if( selectiveForcing_
)
1457 throw Exceptions::InternalError( "EvaluatedFormals::appendEvaluatedFormal: Function requires individual forcing specification." );
1459 (*(formals_
->argumentOrder_
))[ id
] = defaults_
.size( );
1460 formals_
->forcePos_
.push_back( forceAll_
);
1461 defaults_
.push_back( defaultVal
);
1462 locations_
.push_back( loc
);
1466 Kernel::EvaluatedFormals::appendEvaluatedCoreFormal( const char * id
, const Kernel::VariableHandle
& defaultVal
, bool force
)
1468 appendEvaluatedFormal( id
, defaultVal
, & Ast::THE_CORE_DEFAULT_VALUE_EXPRESSION
, force
);
1472 Kernel::EvaluatedFormals::appendEvaluatedCoreFormal( const char * id
, const Kernel::VariableHandle
& defaultVal
)
1474 appendEvaluatedFormal( id
, defaultVal
, & Ast::THE_CORE_DEFAULT_VALUE_EXPRESSION
);
1478 Kernel::EvaluatedFormals::appendCoreStateFormal( const char * id
)
1480 (*(formals_
->stateOrder_
))[ id
] = formals_
->stateOrder_
->size( );
1484 Kernel::EvaluatedFormals::gcMark( Kernel::GCMarkedSet
& marked
)
1486 typedef typeof defaults_ ListType
;
1487 for( ListType::const_iterator i
= defaults_
.begin( ); i
!= defaults_
.end( ); ++i
)
1489 if( *i
!= NullPtr
< Kernel::Variable
>( ) )
1491 const_cast< Kernel::Variable
* >( i
->getPtr( ) )->gcMark( marked
);
1497 Lang::CuteFunction::CuteFunction( RefCountPtr
< const Lang::Function
> callee
, const Kernel::Arguments
& someArgs
)
1498 : Lang::Function( 0 ), callee_( callee
), someArgs_( someArgs
.clone( ) )
1501 Lang::CuteFunction::~CuteFunction( )
1504 RefCountPtr
< Kernel::CallContInfo
>
1505 Lang::CuteFunction::newCallContInfo( const Ast::ArgListExprs
* argList
, const Kernel::EvalState
& evalState
) const
1507 return callee_
->newCallContInfo( argList
, evalState
, someArgs_
);
1510 RefCountPtr
< Kernel::CallContInfo
>
1511 Lang::CuteFunction::newCallContInfo( const Ast::ArgListExprs
* argList
, const Kernel::EvalState
& evalState
, const Kernel::Arguments
& curryArgs
) const
1513 /* when we are the callee of a CuteFunction, our someArgs are part of that CuteFunction's someArgs, and hence curryArgs
1514 contains everything that is to be passed to our callee.
1516 return callee_
->newCallContInfo( argList
, evalState
, curryArgs
);
1520 Lang::CuteFunction::newCurriedArguments( ) const
1522 return someArgs_
.clone( );
1526 Lang::CuteFunction::call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1528 /* Note that curruying "takes place" in newCurriedArguments. Other than that, this is the same as the original function.
1529 Also note that the total set of arguments being passed to the original function is no more than someArgs and what was passed in the last call.
1531 callee_
->call( evalState
, args
, callLoc
);
1535 Lang::CuteFunction::isTransforming( ) const
1537 return callee_
->isTransforming( );
1541 Lang::CuteFunction::gcMark( Kernel::GCMarkedSet
& marked
)
1543 const_cast< Lang::Function
* >( callee_
.getPtr( ) )->gcMark( marked
);
1544 someArgs_
.gcMark( marked
);
1548 Lang::ComposedFunction::ComposedFunction( const RefCountPtr
< const Lang::Function
> & second
, const RefCountPtr
< const Lang::Function
> & first
)
1549 : Lang::Function( 0 ), second_( second
), first_( first
)
1552 Lang::ComposedFunction::~ComposedFunction( )
1556 Lang::ComposedFunction::call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1558 /* Note that curruying "takes place" in newCurriedArguments. Other than that, this is the same as the original function.
1559 Also note that the total set of arguments being passed to the original function is no more than someArgs and what was passed in the last call.
1561 evalState
->cont_
= Kernel::ContRef( new Kernel::ComposedFunctionCall_cont( second_
, evalState
->dyn_
, evalState
->cont_
, callLoc
) );
1562 first_
->call( evalState
, args
, callLoc
);
1565 RefCountPtr
< Kernel::CallContInfo
>
1566 Lang::ComposedFunction::newCallContInfo( const Ast::ArgListExprs
* argList
, const Kernel::EvalState
& evalState
) const
1568 return first_
->newCallContInfo( argList
, evalState
);
1571 RefCountPtr
< Kernel::CallContInfo
>
1572 Lang::ComposedFunction::newCallContInfo( const Ast::ArgListExprs
* argList
, const Kernel::EvalState
& evalState
, const Kernel::Arguments
& curryArgs
) const
1574 return first_
->newCallContInfo( argList
, evalState
, curryArgs
);
1578 Lang::ComposedFunction::newCurriedArguments( ) const
1580 return first_
->newCurriedArguments( );
1584 Lang::ComposedFunction::isTransforming( ) const
1586 return second_
->isTransforming( );
1590 Lang::ComposedFunction::gcMark( Kernel::GCMarkedSet
& marked
)
1592 const_cast< Lang::Function
* >( second_
.getPtr( ) )->gcMark( marked
);
1593 const_cast< Lang::Function
* >( first_
.getPtr( ) )->gcMark( marked
);
1597 Lang::UserFunction::UserFunction( Kernel::EvaluatedFormals
* formals
, Ast::Expression
* body
, Kernel::PassedEnv env
, const Ast::FunctionMode
& functionMode
)
1598 : Lang::Function( formals
), body_( body
), env_( env
), functionMode_( functionMode
)
1601 // DISPATCHIMPL( UserFunction );
1603 Lang::UserFunction::~UserFunction( )
1605 // Note that we don't delete the things that we most likely share with other objects
1606 // Reference counting could be used here, but there will never be more such things than there are function expressions in the source
1608 // This prevents formals->formals from being deleted by Lang::Function::~Function
1614 Lang::UserFunction::call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1616 args
.applyDefaults( );
1617 evalState
->env_
= new Kernel::Environment( Kernel::theEnvironmentList
, env_
, formals_
->formals_
->argumentOrder_
, args
.getVariables( ), formals_
->formals_
->stateOrder_
, args
.getStates( ) );
1619 if( ! this->isProcedural( ) )
1621 evalState
->env_
->activateFunctionBoundary( );
1624 body_
->eval( evalState
);
1628 Lang::UserFunction::isTransforming( ) const
1630 return ( functionMode_
& Ast::FUNCTION_TRANSFORMING
) != 0;
1634 Lang::UserFunction::isProcedural( ) const
1636 return ( functionMode_
& Ast::FUNCTION_PROCEDURAL
) != 0;
1640 Lang::UserFunction::inScope( Kernel::PassedEnv env
) const
1642 return ! isProcedural( )
1643 || env_
->isProceduralParentOf( env
);
1647 Lang::UserFunction::gcMark( Kernel::GCMarkedSet
& marked
)
1649 env_
->gcMark( marked
);
1653 Lang::TransformedFunction2D::TransformedFunction2D( const Lang::Transform2D
& tf
, const RefCountPtr
< const Lang::Function
> & fun
)
1654 : Lang::Function( 0 ), tf_( tf
), fun_( fun
)
1657 Lang::TransformedFunction2D::~TransformedFunction2D( )
1661 Lang::TransformedFunction2D::call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1663 evalState
->cont_
= Kernel::ContRef( new Kernel::Transform2DCont( tf_
, evalState
->cont_
, 0 ) );
1664 fun_
->call( evalState
, args
, callLoc
);
1668 Lang::TransformedFunction2D::isTransforming( ) const
1670 return fun_
->isTransforming( );
1674 Lang::TransformedFunction2D::gcMark( Kernel::GCMarkedSet
& marked
)
1676 const_cast< Lang::Function
* >( fun_
.getPtr( ) )->gcMark( marked
);
1680 Lang::VectorFunction::VectorFunction( const std::vector
< Kernel::ValueRef
> * mem
)
1681 : Lang::Function( new Kernel::EvaluatedFormals( "<vector>", true ) ), mem_( mem
),
1682 memNumeric_( NullPtr
< const std::vector
< double > >( ) )
1684 formals_
->appendEvaluatedCoreFormal( "index", Kernel::THE_SLOT_VARIABLE
);
1687 // DISPATCHIMPL( VectorFunction );
1689 Lang::VectorFunction::~VectorFunction( )
1692 Kernel::VariableHandle
1693 Lang::VectorFunction::getField( const char * fieldID
, const RefCountPtr
< const Lang::Value
> & selfRef
) const
1695 if( strcmp( fieldID
, "size" ) == 0 )
1697 return Helpers::newValHandle( new Lang::Integer( mem_
->size( ) ) );
1699 throw Exceptions::NonExistentMember( getTypeName( ), fieldID
);
1702 const char * Lang::VectorFunction::title_
= "<vector>";
1705 Lang::VectorFunction::call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1707 const size_t ARITY
= 1;
1708 if( args
.size( ) != ARITY
)
1710 throw Exceptions::CoreArityMismatch( title_
, ARITY
, args
.size( ) );
1713 typedef const Lang::Integer ArgType
;
1714 RefCountPtr
< ArgType
> arg
= Helpers::down_cast_CoreArgument
< ArgType
>( title_
, args
, 0, callLoc
);
1718 throw Exceptions::CoreOutOfRange( title_
, args
, 0, "Index is negative." );
1721 if( arg
->val_
>= static_cast< int >( mem_
->size( ) ) )
1723 throw Exceptions::CoreOutOfRange( title_
, args
, 0, "Index exceeds vector size." );
1726 Kernel::ContRef cont
= evalState
->cont_
;
1727 cont
->takeValue( (*mem_
)[ arg
->val_
],
1732 Lang::VectorFunction::isTransforming( ) const
1738 Lang::VectorFunction::gcMark( Kernel::GCMarkedSet
& marked
)
1740 for( std::vector
< Kernel::ValueRef
>::const_iterator i
= mem_
->begin( ); i
!= mem_
->end( ); ++i
)
1742 const_cast< Lang::Value
* >( i
->getPtr( ) )->gcMark( marked
);
1746 RefCountPtr
< const std::vector
< double > >
1747 Lang::VectorFunction::getNumeric( const Ast::SourceLocation
& callLoc
) const
1749 if( memNumeric_
== NullPtr
< const std::vector
< double > >( ) )
1751 RefCountPtr
< std::vector
< double > > res( new std::vector
< double > ); // Note that this is not const, so far...
1752 res
->reserve( mem_
->size( ) );
1753 typedef typeof *mem_ SrcType
;
1754 for( SrcType::const_iterator src
= mem_
->begin( ); src
!= mem_
->end( ); ++src
)
1756 res
->push_back( Helpers::down_cast
< const Lang::Float
>( *src
, callLoc
)->val_
);
1765 const char * Lang::ColorInterpolator::title_
= "<color-interpolator>";
1767 Lang::ColorInterpolator::ColorInterpolator( const RefCountPtr
< KeyContainer
> & key
,
1768 const RefCountPtr
< RGBContainer
> & RGBcolor
,
1769 const RefCountPtr
< GrayContainer
> & graycolor
,
1770 const RefCountPtr
< CMYKContainer
> & CMYKcolor
,
1771 ColorType colorType
)
1772 : Lang::Function( new Kernel::EvaluatedFormals( Lang::ColorInterpolator::title_
, true ) ),
1773 key_( key
), RGBcolor_ ( RGBcolor
), graycolor_ ( graycolor
), CMYKcolor_ ( CMYKcolor
), colorType_(colorType
)
1775 formals_
->appendEvaluatedCoreFormal( "key", Kernel::THE_SLOT_VARIABLE
);
1778 Lang::ColorInterpolator::~ColorInterpolator( )
1781 Kernel::VariableHandle
1782 Lang::ColorInterpolator::getField( const char * fieldID
, const RefCountPtr
< const Lang::Value
> & selfRef
) const
1784 if( strcmp( fieldID
, "low" ) == 0 )
1786 return Helpers::newValHandle( new Lang::Float( key_
->front( ) ) );
1788 if( strcmp( fieldID
, "high" ) == 0 )
1790 return Helpers::newValHandle( new Lang::Float( key_
->back( ) ) );
1792 throw Exceptions::NonExistentMember( getTypeName( ), fieldID
);
1796 template <class COLOR_TYPE
, class COLOR_CONTAINER
>
1798 Lang::ColorInterpolator::callHelper( Kernel::EvalState
* evalState
,
1799 const RefCountPtr
< COLOR_CONTAINER
> & colorContainer
,
1800 double key
, KeyContainer::const_iterator keyHi
) const
1802 if( keyHi
== key_
->end( ) )
1804 Kernel::ContRef cont
= evalState
->cont_
;
1805 cont
->takeValue( RefCountPtr
< const::Lang::Value
>( new COLOR_TYPE( colorContainer
->back( ) ) ),
1810 if( keyHi
== key_
->begin( ) )
1812 Kernel::ContRef cont
= evalState
->cont_
;
1813 cont
->takeValue( RefCountPtr
< const::Lang::Value
>( new COLOR_TYPE( colorContainer
->front( ) ) ),
1818 KeyContainer::const_iterator keyLo
= keyHi
- 1;
1819 double rem
= ( key
- *keyLo
) / ( *keyHi
- *keyLo
);
1821 Kernel::ContRef cont
= evalState
->cont_
;
1823 typename
COLOR_CONTAINER::const_iterator colorHi
= colorContainer
->begin( ) + ( keyHi
- key_
->begin( ) );
1824 typename
COLOR_CONTAINER::const_iterator colorLo
= colorHi
- 1;
1826 cont
->takeValue( RefCountPtr
< const::Lang::Value
>( new COLOR_TYPE( colorLo
->mulNoCheck( 1 - rem
).addNoCheck( colorHi
->mulNoCheck( rem
) ) ) ),
1832 Lang::ColorInterpolator::call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1834 const size_t ARITY
= 1;
1835 if( args
.size( ) != ARITY
)
1837 throw Exceptions::CoreArityMismatch( title_
, ARITY
, args
.size( ) );
1840 typedef const Lang::Float ArgType
;
1841 double key
= Helpers::down_cast_CoreArgument
< ArgType
>( title_
, args
, 0, callLoc
)->val_
;
1843 KeyContainer::const_iterator keyHi
= lower_bound( key_
->begin( ), key_
->end( ), key
);
1844 switch( colorType_
)
1847 callHelper
< Lang::RGB
>( evalState
, RGBcolor_
, key
, keyHi
);
1850 callHelper
< Lang::Gray
>( evalState
, graycolor_
, key
, keyHi
);
1853 callHelper
< Lang::CMYK
>( evalState
, CMYKcolor_
, key
, keyHi
);
1856 throw Exceptions::InternalError( "ColorInterpolator::call: Did not expect UNDEFINED in ennum switch." );
1861 Lang::ColorInterpolator::isTransforming( ) const
1867 Lang::ColorInterpolator::gcMark( Kernel::GCMarkedSet
& marked
)
1871 Lang::BinaryOperatorFunction::BinaryOperatorFunction( Ast::BinaryInfixExpr
* opExpr
, const char * title
)
1872 : Lang::Function( new Kernel::EvaluatedFormals( title
, true ) ), opExpr_( opExpr
), title_( title
)
1874 formals_
->appendEvaluatedCoreFormal( "first", Kernel::THE_SLOT_VARIABLE
);
1875 formals_
->appendEvaluatedCoreFormal( "second", Kernel::THE_SLOT_VARIABLE
);
1878 Lang::BinaryOperatorFunction::~BinaryOperatorFunction( )
1884 Lang::BinaryOperatorFunction::call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1886 const size_t ARITY
= 2;
1887 CHECK_ARITY( args
, ARITY
, title_
);
1888 RefCountPtr
< const Lang::Value
> arg1
= args
.getValue( 0 );
1889 RefCountPtr
< const Lang::Value
> arg2
= args
.getValue( 1 );
1893 Kernel::ContRef cont
= evalState
->cont_
;
1894 cont
->takeValue( arg1
->binaryDispatch1( arg1
, arg2
, evalState
->dyn_
, opExpr_
),
1897 catch( Exceptions::BinaryInfixNotApplicable
& ball
)
1899 ball
.setOperatorSymbol( title_
);
1905 Lang::BinaryOperatorFunction::isTransforming( ) const
1911 Lang::UnaryOperatorFunction::UnaryOperatorFunction( Ast::UnaryExpr
* opExpr
, const char * title
)
1912 : Lang::Function( new Kernel::EvaluatedFormals( title
, true ) ), opExpr_( opExpr
), title_( title
)
1914 formals_
->appendEvaluatedCoreFormal( "only", Kernel::THE_SLOT_VARIABLE
);
1917 Lang::UnaryOperatorFunction::~UnaryOperatorFunction( )
1923 Lang::UnaryOperatorFunction::call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1925 const size_t ARITY
= 1;
1926 CHECK_ARITY( args
, ARITY
, title_
);
1928 RefCountPtr
< const Lang::Value
> arg
= args
.getValue( 0 );
1932 Kernel::ContRef cont
= evalState
->cont_
;
1933 cont
->takeValue( arg
->unaryDispatch( arg
, evalState
->dyn_
, opExpr_
),
1936 catch( Exceptions::UnaryPrefixNotApplicable
& ball
)
1938 ball
.setOperatorSymbol( title_
);
1941 catch( Exceptions::UnaryPostfixNotApplicable
& ball
)
1943 ball
.setOperatorSymbol( title_
);
1949 Lang::UnaryOperatorFunction::isTransforming( ) const