Updating the changelog in the VERSION file, and version_sync.
[shapes.git] / source / functiontypes.cc
blobd948c1475d922dfefe91eedf43ec5ac0701118e4
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 Henrik Tidefelt
19 #include <cmath>
21 #include "shapestypes.h"
22 #include "shapesexceptions.h"
23 #include "astexpr.h"
24 #include "consts.h"
25 #include "angleselect.h"
26 #include "astvar.h"
27 #include "astclass.h"
28 #include "globals.h"
29 #include "continuations.h"
30 #include "methodbase.h"
31 #include "check.h"
33 //#include "clapack.h"
34 //#include "cblas.h"
35 #include <gsl/gsl_matrix.h>
36 #include <gsl/gsl_linalg.h>
37 #include <gsl/gsl_blas.h>
38 #include <ctype.h>
39 #include <stack>
40 #include <algorithm>
42 #define CHOP_Ltol( x )\
43 if( fabs( x ) < Ltol )\
45 x = 0;\
47 else if( fabs( x - 1 ) < Ltol )\
49 x = 1;\
51 else if( fabs( x + 1 ) < Ltol )\
53 x = -1;\
56 #define CHOP_ptol( x )\
57 if( x.abs( ) < ptol )\
59 x = Concrete::ZERO_LENGTH;\
62 using namespace Shapes;
63 using namespace std;
65 void displayArray( std::ostream & os, const double * pr, size_t m, size_t n )
67 size_t r;
68 size_t c;
69 char buf[20];
70 for( r = 0; r < m; ++r )
72 for( c = 0; c < n; ++c )
74 sprintf( buf, "%14.5e", *( pr + ( r + c * m ) ) );
75 os << buf ;
77 os << std::endl ;
81 void displayArray( std::ostream & os, const gsl_matrix * m )
83 char buf[20];
84 for( size_t r = 0; r < m->size1; ++r )
86 for( size_t c = 0; c < m->size2; ++c )
88 sprintf( buf, "%14.5e", gsl_matrix_get( m, r, c ) );
89 os << buf ;
91 os << std::endl ;
95 namespace Shapes
98 namespace Lang
101 class Transform2DMethod_chop : public Lang::MethodBase< Lang::Transform2D >
103 public:
104 Transform2DMethod_chop( RefCountPtr< const Lang::Transform2D > _self, const Ast::FileID * fullMethodID );
105 virtual ~Transform2DMethod_chop( );
106 virtual void call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const;
107 static const char * staticFieldID( ) { return "chop"; }
110 class Transform3DMethod_chop : public Lang::MethodBase< Lang::Transform3D >
112 public:
113 Transform3DMethod_chop( RefCountPtr< const Lang::Transform3D > _self, const Ast::FileID * fullMethodID );
114 virtual ~Transform3DMethod_chop( );
115 virtual void call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const;
116 static const char * staticFieldID( ) { return "chop"; }
122 void
123 Transform2D_register_methods( Lang::SystemFinalClass * dstClass )
125 dstClass->registerMethod( new Kernel::MethodFactory< Lang::Transform2D, Lang::Transform2DMethod_chop >( ) );
128 RefCountPtr< const Lang::Class > Lang::Transform2D::TypeID( new Lang::SystemFinalClass( strrefdup( "Transform2D" ), Transform2D_register_methods ) );
129 TYPEINFOIMPL( Transform2D );
131 Lang::Transform2D::Transform2D( double xx, double yx, double xy, double yy, Concrete::Length xt, Concrete::Length yt )
132 : xx_( xx ), yx_( yx ), xy_( xy ), yy_( yy ), xt_( xt ), yt_( yt )
135 Lang::Transform2D::Transform2D( const Lang::Transform2D & tf2, const Lang::Transform2D & tf1 )
136 : xx_( tf2.xx_ * tf1.xx_ + tf2.xy_ * tf1.yx_ ),
137 yx_( tf2.yx_ * tf1.xx_ + tf2.yy_ * tf1.yx_ ),
138 xy_( tf2.xx_ * tf1.xy_ + tf2.xy_ * tf1.yy_ ),
139 yy_( tf2.yx_ * tf1.xy_ + tf2.yy_ * tf1.yy_ ),
140 xt_( tf2.xx_ * tf1.xt_ + tf2.xy_ * tf1.yt_ + tf2.xt_ ),
141 yt_( tf2.yx_ * tf1.xt_ + tf2.yy_ * tf1.yt_ + tf2.yt_ )
144 DISPATCHIMPL( Transform2D );
146 Lang::Transform2D::~Transform2D( )
149 Kernel::VariableHandle
150 Lang::Transform2D::getField( const char * fieldID, const RefCountPtr< const Lang::Value > & selfRef ) const
152 const size_t N = 2;
153 if( strcmp( fieldID, "p" ) == 0 )
155 return Helpers::newValHandle( new Lang::Coords2D( xt_, yt_ ) );
157 if( strcmp( fieldID, "L" ) == 0 )
159 return Helpers::newValHandle( new Lang::Transform2D( xx_, yx_, xy_, yy_, 0, 0 ) );
161 if( strcmp( fieldID, "Lx" ) == 0 )
163 return Helpers::newValHandle( new Lang::FloatPair( xx_, yx_ ) );
165 if( strcmp( fieldID, "Ly" ) == 0 )
167 return Helpers::newValHandle( new Lang::FloatPair( xy_, yy_ ) );
169 if( strcmp( fieldID, "xL" ) == 0 )
171 return Helpers::newValHandle( new Lang::FloatPair( xx_, xy_ ) );
173 if( strcmp( fieldID, "yL" ) == 0 )
175 return Helpers::newValHandle( new Lang::FloatPair( yx_, yy_ ) );
177 if( strcmp( fieldID, "linear?" ) == 0 )
179 return ( xt_ == 0 && yt_ == 0 ) ? Kernel::THE_TRUE_VARIABLE : Kernel::THE_FALSE_VARIABLE;
181 if( strcmp( fieldID, "translation?" ) == 0 )
183 return isTranslation( ) ? Kernel::THE_TRUE_VARIABLE : Kernel::THE_FALSE_VARIABLE;
185 if( strcmp( fieldID, "special?" ) == 0 )
187 gsl_matrix * A = gsl_matrix_alloc( N, N );
188 gsl_permutation * perm = gsl_permutation_alloc( N );
189 int signum;
190 write_gsl_matrix( A );
191 gsl_linalg_LU_decomp( A, perm, & signum );
192 bool res = gsl_linalg_LU_det( A, signum ) > 0;
193 gsl_matrix_free( A );
194 gsl_permutation_free( perm );
195 return res ? Kernel::THE_TRUE_VARIABLE : Kernel::THE_FALSE_VARIABLE;
197 if( strcmp( fieldID, "Euclidean?" ) == 0 )
199 gsl_matrix * A = gsl_matrix_alloc( N, N );
200 gsl_vector * SVD_work = gsl_vector_alloc( N );
201 gsl_vector * sigma = gsl_vector_alloc( N );
202 gsl_matrix * V = gsl_matrix_alloc( N, N );
203 write_gsl_matrix( A );
204 gsl_linalg_SV_decomp( A, V, sigma, SVD_work );
205 const double tol = 1e-4;
206 bool res = 1 - tol < gsl_vector_get( sigma, N - 1 ) && gsl_vector_get( sigma, 0 ) < 1 + tol;
207 gsl_matrix_free( V );
208 gsl_vector_free( sigma );
209 gsl_vector_free( SVD_work );
210 gsl_matrix_free( A );
211 return res ? Kernel::THE_TRUE_VARIABLE : Kernel::THE_FALSE_VARIABLE;
214 return TypeID->getMethod( selfRef, fieldID ); /* This will throw if there is no such method. */
217 Lang::Transform2D *
218 Lang::Transform2D::clone( ) const
220 return new Transform2D( xx_, yx_,
221 xy_, yy_,
222 xt_, yt_ );
225 bool
226 Lang::Transform2D::isIdentity( ) const
228 return
229 xt_ == Concrete::ZERO_LENGTH && yt_ == Concrete::ZERO_LENGTH &&
230 xx_ == 1 && yy_ == 1 &&
231 xy_ == 0 && yx_ == 0;
234 bool
235 Lang::Transform2D::isTranslation( ) const
237 return
238 xx_ == 1 && yy_ == 1 &&
239 xy_ == 0 && yx_ == 0;
242 void
243 Lang::Transform2D::write_gsl_matrix( gsl_matrix * matrix_2_2 ) const
245 gsl_matrix_set( matrix_2_2, 0, 0, xx_ );
246 gsl_matrix_set( matrix_2_2, 1, 0, yx_ );
247 gsl_matrix_set( matrix_2_2, 0, 1, xy_ );
248 gsl_matrix_set( matrix_2_2, 1, 1, yy_ );
251 void
252 Lang::Transform2D::write_gsl_vector( gsl_vector * vec_2 ) const
254 gsl_vector_set( vec_2, 0, Concrete::Length::offtype( xt_ ) );
255 gsl_vector_set( vec_2, 1, Concrete::Length::offtype( yt_ ) );
258 void
259 Lang::Transform2D::shipout( std::ostream & os ) const
261 os << xx_ << " " << yx_ << " " << xy_ << " " << yy_ << " "
262 << Concrete::Length::offtype( xt_ ) << " " << Concrete::Length::offtype( yt_ ) ;
265 // to be used by text moveto commands
266 void
267 Lang::Transform2D::replaceBy( const Lang::Transform2D & newtf )
269 xx_ = newtf.xx_;
270 yx_ = newtf.yx_;
271 xy_ = newtf.xy_;
272 yy_ = newtf.yy_;
273 xt_ = newtf.xt_;
274 yt_ = newtf.yt_;
277 // to be used by text newline commands
278 void
279 Lang::Transform2D::prependShift( const Concrete::Coords2D & d )
281 // Think of d as tf1 when composing transforms.
283 xt_ += xx_ * d.x_ + xy_ * d.y_;
284 yt_ += yx_ * d.x_ + yy_ * d.y_;
287 // to be used by text painting commands
288 void
289 Lang::Transform2D::prependXShift( const Concrete::Length & dx )
291 // Think of d as tf1 when composing transforms.
293 xt_ += xx_ * dx;
294 yt_ += yx_ * dx;
297 void
298 Lang::Transform2D::show( std::ostream & os ) const
300 os << "[ ("
301 << xx_ << ", " << yx_ << ") ("
302 << xy_ << ", " << yy_ << ") ("
303 << Lang::Length( xt_ ) << ", " << Lang::Length( yt_ ) << ") ]" ;
307 void
308 Transform3D_register_methods( Lang::SystemFinalClass * dstClass )
310 dstClass->registerMethod( new Kernel::MethodFactory< Lang::Transform3D, Lang::Transform3DMethod_chop >( ) );
313 RefCountPtr< const Lang::Class > Lang::Transform3D::TypeID( new Lang::SystemFinalClass( strrefdup( "Transform3D" ), Transform3D_register_methods ) );
314 TYPEINFOIMPL( Transform3D );
316 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 )
317 : planeNormalTransformData_( 0 ),
318 xx_( xx ), yx_( yx ), zx_( zx ), xy_( xy ), yy_( yy ), zy_( zy ), xz_( xz ), yz_( yz ), zz_( zz ), xt_( xt ), yt_( yt ), zt_( zt )
321 Lang::Transform3D::Transform3D( const gsl_matrix * matrix_3_3, const gsl_vector * vec_3 )
322 : planeNormalTransformData_( 0 ),
323 xx_( gsl_matrix_get( matrix_3_3, 0, 0 ) ), yx_( gsl_matrix_get( matrix_3_3, 1, 0 ) ), zx_( gsl_matrix_get( matrix_3_3, 2, 0 ) ),
324 xy_( gsl_matrix_get( matrix_3_3, 0, 1 ) ), yy_( gsl_matrix_get( matrix_3_3, 1, 1 ) ), zy_( gsl_matrix_get( matrix_3_3, 2, 1 ) ),
325 xz_( gsl_matrix_get( matrix_3_3, 0, 2 ) ), yz_( gsl_matrix_get( matrix_3_3, 1, 2 ) ), zz_( gsl_matrix_get( matrix_3_3, 2, 2 ) ),
326 xt_( gsl_vector_get( vec_3, 0 ) ), yt_( gsl_vector_get( vec_3, 1 ) ), zt_( gsl_vector_get( vec_3, 2 ) )
331 Lang::Transform3D::Transform3D( const Lang::Transform3D & tf2, const Lang::Transform3D & tf1 )
332 : planeNormalTransformData_( 0 ),
333 xx_( tf2.xx_ * tf1.xx_ + tf2.xy_ * tf1.yx_ + tf2.xz_ * tf1.zx_ ),
334 yx_( tf2.yx_ * tf1.xx_ + tf2.yy_ * tf1.yx_ + tf2.yz_ * tf1.zx_ ),
335 zx_( tf2.zx_ * tf1.xx_ + tf2.zy_ * tf1.yx_ + tf2.zz_ * tf1.zx_ ),
336 xy_( tf2.xx_ * tf1.xy_ + tf2.xy_ * tf1.yy_ + tf2.xz_ * tf1.zy_ ),
337 yy_( tf2.yx_ * tf1.xy_ + tf2.yy_ * tf1.yy_ + tf2.yz_ * tf1.zy_ ),
338 zy_( tf2.zx_ * tf1.xy_ + tf2.zy_ * tf1.yy_ + tf2.zz_ * tf1.zy_ ),
339 xz_( tf2.xx_ * tf1.xz_ + tf2.xy_ * tf1.yz_ + tf2.xz_ * tf1.zz_ ),
340 yz_( tf2.yx_ * tf1.xz_ + tf2.yy_ * tf1.yz_ + tf2.yz_ * tf1.zz_ ),
341 zz_( tf2.zx_ * tf1.xz_ + tf2.zy_ * tf1.yz_ + tf2.zz_ * tf1.zz_ ),
342 xt_( tf2.xx_ * tf1.xt_ + tf2.xy_ * tf1.yt_ + tf2.xz_ * tf1.zt_ + tf2.xt_ ),
343 yt_( tf2.yx_ * tf1.xt_ + tf2.yy_ * tf1.yt_ + tf2.yz_ * tf1.zt_ + tf2.yt_ ),
344 zt_( tf2.zx_ * tf1.xt_ + tf2.zy_ * tf1.yt_ + tf2.zz_ * tf1.zt_ + tf2.zt_ )
347 DISPATCHIMPL( Transform3D );
349 Lang::Transform3D::~Transform3D( )
351 if( planeNormalTransformData_ != 0 )
353 gsl_matrix_free( planeNormalTransformData_ );
354 // delete planeNormalTransformData_;
358 Kernel::VariableHandle
359 Lang::Transform3D::getField( const char * fieldID, const RefCountPtr< const Lang::Value > & selfRef ) const
361 const size_t N = 3;
362 if( strcmp( fieldID, "p" ) == 0 )
364 return Helpers::newValHandle( new Lang::Coords3D( xt_, yt_, zt_ ) );
366 if( strcmp( fieldID, "L" ) == 0 )
368 return Helpers::newValHandle( new Lang::Transform3D( xx_, yx_, zx_, xy_, yy_, zy_, xz_, yz_, zz_, 0, 0, 0 ) );
370 if( strcmp( fieldID, "Lx" ) == 0 )
372 return Helpers::newValHandle( new Lang::FloatTriple( xx_, yx_, zx_ ) );
374 if( strcmp( fieldID, "Ly" ) == 0 )
376 return Helpers::newValHandle( new Lang::FloatTriple( xy_, yy_, zy_ ) );
378 if( strcmp( fieldID, "Lz" ) == 0 )
380 return Helpers::newValHandle( new Lang::FloatTriple( xz_, yz_, zz_ ) );
382 if( strcmp( fieldID, "xL" ) == 0 )
384 return Helpers::newValHandle( new Lang::FloatTriple( xx_, xy_, xz_ ) );
386 if( strcmp( fieldID, "yL" ) == 0 )
388 return Helpers::newValHandle( new Lang::FloatTriple( yx_, yy_, yz_ ) );
390 if( strcmp( fieldID, "zL" ) == 0 )
392 return Helpers::newValHandle( new Lang::FloatTriple( zx_, zy_, zz_ ) );
394 if( strcmp( fieldID, "linear?" ) == 0 )
396 return ( xt_ == 0 && yt_ == 0 && zt_ == 0 ) ? Kernel::THE_TRUE_VARIABLE : Kernel::THE_FALSE_VARIABLE;
398 if( strcmp( fieldID, "translation?" ) == 0 )
400 return isTranslation( ) ? Kernel::THE_TRUE_VARIABLE : Kernel::THE_FALSE_VARIABLE;
402 if( strcmp( fieldID, "special?" ) == 0 )
404 gsl_matrix * A = gsl_matrix_alloc( N, N );
405 gsl_permutation * perm = gsl_permutation_alloc( N );
406 int signum;
407 write_gsl_matrix( A );
408 gsl_linalg_LU_decomp( A, perm, & signum );
409 bool res = gsl_linalg_LU_det( A, signum ) > 0;
410 gsl_matrix_free( A );
411 gsl_permutation_free( perm );
412 return res ? Kernel::THE_TRUE_VARIABLE : Kernel::THE_FALSE_VARIABLE;
414 if( strcmp( fieldID, "Euclidean?" ) == 0 )
416 gsl_matrix * A = gsl_matrix_alloc( N, N );
417 gsl_vector * SVD_work = gsl_vector_alloc( N );
418 gsl_vector * sigma = gsl_vector_alloc( N );
419 gsl_matrix * V = gsl_matrix_alloc( N, N );
420 write_gsl_matrix( A );
421 gsl_linalg_SV_decomp( A, V, sigma, SVD_work );
422 const double tol = 1e-4;
423 bool res = 1 - tol < gsl_vector_get( sigma, N - 1 ) && gsl_vector_get( sigma, 0 ) < 1 + tol;
424 gsl_matrix_free( V );
425 gsl_vector_free( sigma );
426 gsl_vector_free( SVD_work );
427 gsl_matrix_free( A );
428 return res ? Kernel::THE_TRUE_VARIABLE : Kernel::THE_FALSE_VARIABLE;
431 return TypeID->getMethod( selfRef, fieldID ); /* This will throw if there is no such method. */
434 Lang::Transform3D *
435 Lang::Transform3D::clone( ) const
437 return new Transform3D( xx_, yx_, zx_,
438 xy_, yy_, zy_,
439 xz_, yz_, zz_,
440 xt_, yt_, zt_ );
443 bool
444 Lang::Transform3D::isIdentity( ) const
446 return
447 xt_ == Concrete::ZERO_LENGTH && yt_ == Concrete::ZERO_LENGTH && zt_ == Concrete::ZERO_LENGTH &&
448 xx_ == 1 && yy_ == 1 && zz_ == 1 &&
449 xy_ == 0 && xz_ == 0 && yx_ == 0 && yz_ == 0 && zx_ == 0 && zy_ == 0;
452 bool
453 Lang::Transform3D::isTranslation( ) const
455 return
456 xx_ == 1 && yy_ == 1 && zz_ == 1 &&
457 xy_ == 0 && xz_ == 0 &&
458 yx_ == 0 && yz_ == 0 &&
459 zx_ == 0 && zy_ == 0;
462 void
463 Lang::Transform3D::write_gsl_matrix( gsl_matrix * matrix_3_3 ) const
465 gsl_matrix_set( matrix_3_3, 0, 0, xx_ );
466 gsl_matrix_set( matrix_3_3, 1, 0, yx_ );
467 gsl_matrix_set( matrix_3_3, 2, 0, zx_ );
468 gsl_matrix_set( matrix_3_3, 0, 1, xy_ );
469 gsl_matrix_set( matrix_3_3, 1, 1, yy_ );
470 gsl_matrix_set( matrix_3_3, 2, 1, zy_ );
471 gsl_matrix_set( matrix_3_3, 0, 2, xz_ );
472 gsl_matrix_set( matrix_3_3, 1, 2, yz_ );
473 gsl_matrix_set( matrix_3_3, 2, 2, zz_ );
476 void
477 Lang::Transform3D::write_gsl_vector( gsl_vector * vec_3 ) const
479 gsl_vector_set( vec_3, 0, Concrete::Length::offtype( xt_ ) );
480 gsl_vector_set( vec_3, 1, Concrete::Length::offtype( yt_ ) );
481 gsl_vector_set( vec_3, 2, Concrete::Length::offtype( zt_ ) );
484 Concrete::UnitFloatTriple
485 Lang::Transform3D::transformPlaneUnitNormal( const Concrete::UnitFloatTriple & n ) const
487 const int N = 3;
488 // These statically allocated matrices will leak memory. They could be removed by using a static automaitc
489 // deallocator object. However, since they shall not be deleted by delete (but by gsl_matrix_free), we cannot
490 // us RefCountPtr< gsl_matrix >.
491 static gsl_matrix * a = gsl_matrix_alloc( N, N );
492 static gsl_matrix * v = gsl_matrix_alloc( N, N );
493 static gsl_vector * s = gsl_vector_alloc( N );
494 static gsl_vector * work = gsl_vector_alloc( N );
497 // static __CLPK_integer mn = N;
498 // static char jobuvt = 'A';
500 // static double a[ N * N ];
501 // static double u[ N * N ];
502 // static double vt[ N * N ];
503 // __CLPK_integer ldauvt = N;
504 // static double s[ N ];
505 // __CLPK_integer lwork;
506 // __CLPK_integer info;
508 // static __CLPK_doublereal * work = 0;
509 // static RefCountPtr< __CLPK_doublereal > workCleaner;
511 // if( work == 0 )
512 // {
513 // // Then we ask LAPACK how much workspace it wants, and then we assume that this number will not change
514 // // as we call DGESVD with other arguments.
516 // double tmpwork;
517 // lwork = -1;
518 // dgesvd_( & jobuvt, & jobuvt,
519 // & mn, & mn,
520 // reinterpret_cast< __CLPK_doublereal * >( & a ), & ldauvt,
521 // reinterpret_cast< __CLPK_doublereal * >( & s ),
522 // reinterpret_cast< __CLPK_doublereal * >( & u ), & ldauvt,
523 // reinterpret_cast< __CLPK_doublereal * >( & vt ), & ldauvt,
524 // reinterpret_cast< __CLPK_doublereal * >( & tmpwork ), & lwork,
525 // & info );
526 // lwork = static_cast< __CLPK_integer >( tmpwork );
527 // work = new __CLPK_doublereal[ lwork ];
528 // workCleaner = RefCountPtr< __CLPK_doublereal >( work );
529 // }
532 if( planeNormalTransformData_ == 0 )
534 // This is the first time this transform is used to transform a unit plane normal.
535 // The linear part of this transform must then be computed, and we use the singular
536 // value decomposition for this.
538 planeNormalTransformData_ = gsl_matrix_alloc( N, N );
540 write_gsl_matrix( a );
542 // std::cerr << "Here's a:" << std::endl ;
543 // displayArray( std::cerr, a );
546 int status = gsl_linalg_SV_decomp( a, v, s, work );
547 if( status != 0 )
549 throw Exceptions::ExternalError( "Gnu Scientific Library SVD routine failed." );
553 // a[ 0 ] = xx_;
554 // a[ 1 ] = yx_;
555 // a[ 2 ] = zx_;
556 // a[ 3 ] = xy_;
557 // a[ 4 ] = yy_;
558 // a[ 5 ] = zy_;
559 // a[ 6 ] = xz_;
560 // a[ 7 ] = yz_;
561 // a[ 8 ] = zz_;
563 // dgesvd_( & jobuvt, & jobuvt,
564 // & mn, & mn,
565 // reinterpret_cast< __CLPK_doublereal * >( & a ), & ldauvt,
566 // reinterpret_cast< __CLPK_doublereal * >( & s ),
567 // reinterpret_cast< __CLPK_doublereal * >( & u ), & ldauvt,
568 // reinterpret_cast< __CLPK_doublereal * >( & vt ), & ldauvt,
569 // reinterpret_cast< __CLPK_doublereal * >( work ), & lwork,
570 // & info );
572 // if( info != 0 )
573 // {
574 // throw Exceptions::ExternalError( "LAPACK routine DGESVD failed." );
575 // }
577 if( gsl_vector_get( s, 1 ) < 1e-5 )
579 throw Exceptions::AffineTransformKillsPlane( gsl_vector_get( s, 1 ) );
582 // std::cerr << "Here's s:" << std::endl ;
583 // gsl_vector_fprintf( stderr, s, "%f" );
585 gsl_vector_set( s, 0, gsl_vector_get( s, 2 ) / gsl_vector_get( s, 0 ) );
586 gsl_vector_set( s, 1, gsl_vector_get( s, 2 ) / gsl_vector_get( s, 1 ) );
587 // s[ 2 ] = 1;
589 // std::cerr << "Here's the modified s:" << std::endl ;
590 // gsl_vector_fprintf( stderr, s, "%f" );
593 // if( s[ 1 ] < 1e-5 )
594 // {
595 // throw Exceptions::AffineTransformKillsPlane( s[ 1 ] );
596 // }
598 // s[ 0 ] = s[ 2 ] / s[ 0 ];
599 // s[ 1 ] = s[ 2 ] / s[ 1 ];
600 // // s[ 2 ] = 1;
602 // We will now compute " u * diag( s ) * vt ".
604 // Note that "u" is stored in a when gsl_linalg_SV_decomp is used.
606 // std::cerr << "Here's u:" << std::endl ;
607 // displayArray( std::cerr, a );
609 gsl_matrix_set( a, 0, 0, gsl_matrix_get( a, 0, 0 ) * gsl_vector_get( s, 0 ) );
610 gsl_matrix_set( a, 1, 0, gsl_matrix_get( a, 1, 0 ) * gsl_vector_get( s, 0 ) );
611 gsl_matrix_set( a, 2, 0, gsl_matrix_get( a, 2, 0 ) * gsl_vector_get( s, 0 ) );
612 gsl_matrix_set( a, 0, 1, gsl_matrix_get( a, 0, 1 ) * gsl_vector_get( s, 1 ) );
613 gsl_matrix_set( a, 1, 1, gsl_matrix_get( a, 1, 1 ) * gsl_vector_get( s, 1 ) );
614 gsl_matrix_set( a, 2, 1, gsl_matrix_get( a, 2, 1 ) * gsl_vector_get( s, 1 ) );
615 // Note that s[ 2 ] == 1
617 // u[ 0 ] *= s[ 0 ];
618 // u[ 1 ] *= s[ 0 ];
619 // u[ 2 ] *= s[ 0 ];
620 // u[ 3 ] *= s[ 1 ];
621 // u[ 4 ] *= s[ 1 ];
622 // u[ 5 ] *= s[ 1 ];
623 // // Note that s[ 2 ] == 1
625 // std::cerr << "Here's the modified a:" << std::endl ;
626 // displayArray( std::cerr, a );
628 // std::cerr << "Here's v:" << std::endl ;
629 // displayArray( std::cerr, v );
631 gsl_blas_dgemm( CblasNoTrans,
632 CblasTrans,
637 planeNormalTransformData_ );
639 // std::cerr << "Here's the matrix:" << std::endl ;
640 // displayArray( std::cerr, planeNormalTransformData_ );
642 // cblas_dgemm( CblasColMajor, CblasNoTrans, CblasNoTrans,
643 // N, N, N,
644 // 1.,
645 // u, N,
646 // vt, N,
647 // 0., planeNormalTransformData_, N );
650 // Now that the linear, not too singular, transform has been computed, we just apply it and normalize the result.
651 // The normalization is made by the UnitFloatTriple constructor.
653 static gsl_vector * _n = gsl_vector_alloc( N );
654 static gsl_vector * res = gsl_vector_alloc( N );
656 // static double _n[ N ];
657 // static double res[ N ];
659 gsl_vector_set( _n, 0, n.x_ );
660 gsl_vector_set( _n, 1, n.y_ );
661 gsl_vector_set( _n, 2, n.z_ );
663 // _n[ 0 ] = n.x_;
664 // _n[ 1 ] = n.y_;
665 // _n[ 2 ] = n.z_;
667 // std::cerr << "Input vector: " << std::endl ;
668 // gsl_vector_fprintf( stderr, _n, "%f" );
669 // std::cerr << std::endl ;
671 gsl_blas_dgemv( CblasNoTrans,
673 planeNormalTransformData_,
676 res );
678 // std::cerr << "Result: " << std::endl ;
679 // gsl_vector_fprintf( stderr, res, "%f" );
680 // std::cerr << std::endl ;
682 // cblas_dgemv( CblasColMajor, CblasNoTrans,
683 // N, N,
684 // 1.,
685 // planeNormalTransformData_, N,
686 // reinterpret_cast< double * >( & _n ), 1,
687 // 0., reinterpret_cast< double * >( & res ), 1 );
689 return Concrete::UnitFloatTriple( gsl_vector_get( res, 0 ),
690 gsl_vector_get( res, 1 ),
691 gsl_vector_get( res, 2 ) );
692 // return Concrete::UnitFloatTriple( res[0], res[1], res[2] );
696 // First we compute a unit vector in the plane
697 static const Concrete::UnitFloatTriple xHat( 1, 0, 0 );
698 static const Concrete::UnitFloatTriple yHat( 0, 1, 0 );
699 Concrete::UnitFloatTriple r1 = Shapes::cross( unitNormal_, xHat );
700 Concrete::UnitFloatTriple r2 = Shapes::cross( unitNormal_, yHat );
701 Concrete::UnitFloatTriple r( 0, 0, 0 );
702 if( r1.norm( ) > r2.norm( ) )
704 r = r1.normalized( );
706 else
708 r = r2.normalized( );
711 // Then we find one point that is in the plane
712 double ax = fabs( unitNormal_.x_ );
713 double ay = fabs( unitNormal_.y_ );
714 double az = fabs( unitNormal_.z_ );
716 Concrete::Coords3D x0( 0, 0, 0 );
717 if( ax >= ay && ax >= az )
719 x0 = Concrete::Coords3D( m_ / unitNormal_.x_, 0, 0 );
721 else if( ay >= az )
723 x0 = Concrete::Coords3D( 0, m_ / unitNormal_.y_, 0 );
725 else
727 x0 = Concrete::Coords3D( 0, 0, m_ / unitNormal_.z_ );
730 // Now it is easy to find two more points that span the plane together with x0
731 Concrete::Coords3D x1 = x0 + r;
732 Concrete::Coords3D x2 = x0 + Shapes::cross( unitNormal_, r );
734 // Now we see where these points go...
735 Concrete::Coords3D Tx0 = x0.transformed( tf );
736 Concrete::Coords3D Tx1 = x1.transformed( tf );
737 Concrete::Coords3D Tx2 = x2.transformed( tf );
739 // ... from which the new equation may be computed.
740 Concrete::UnitFloatTriple Tnormal = Shapes::cross( Tx1 - Tx0, Tx2 - Tx0 );
741 double TnormalNorm = Tnormal.norm( );
742 if( TnormalNorm == 0 )
744 // A polygon of lower dimension is invisible, so we may just return without pushing any triangles.
745 return;
747 Concrete::UnitFloatTriple TunitNormal = Tnormal * ( 1 / TnormalNorm );
751 void
752 Lang::Transform3D::show( std::ostream & os ) const
754 os << "[ ("
755 << xx_ << ", " << yx_ << ", " << zx_ << ") ("
756 << xy_ << ", " << yy_ << ", " << zy_ << ") ("
757 << xz_ << ", " << yz_ << ", " << zz_ << ") ("
758 << Lang::Length( xt_ ) << ", " << Lang::Length( yt_ ) << ", " << Lang::Length( zt_ ) << ") ]" ;
762 Kernel::Arguments::Arguments( const Kernel::EvaluatedFormals * formals )
763 : formals_( formals ), variables_( new Environment::ValueVector::ValueType ), dst_( 0 ),
764 hasSink_( formals_->formals_->hasSink( ) ),
765 dstEnd_( formals_->formals_->defaultExprs_.size( ) ),
766 isSink_( formals_->isSink_ ),
767 sinkArgList_( 0 ), sinkValues_( NullPtr< const Lang::SingleList >( ) ),
768 states_( new Environment::StateVector::ValueType ), stateDst_( 0 ),
769 mutatorSelf_( 0 )
771 if( hasSink_ )
773 sinkArgList_ = new Ast::ArgListExprs( false ); // This is not an expression-owner.
774 sinkValues_ = RefCountPtr< const Lang::SingleList >( new Lang::SingleListNull( ) );
775 if( formals_->formals_->argumentOrder_->empty( ) )
777 // All arguments go in the sink.
778 dst_ = INT_MAX;
781 // Thinking of all the evaluated cuts, it actually makes some sense not to reserve memory here.
782 // variables_.reserve( formals_->argumentOrder_->size( ) );
783 // states_.reserve( formals_->stateOrder_->size( ) );
786 Kernel::Arguments::~Arguments( )
789 Kernel::Arguments
790 Kernel::Arguments::clone( ) const
792 CHECK(
793 if( ! states_->empty( ) )
795 throw Exceptions::InternalError( "Arguments with states may not be cloned." );
799 Kernel::Arguments res( formals_ );
801 res.variables_->reserve( variables_->size( ) );
803 typedef typeof *variables_ ListType;
804 for( ListType::const_iterator i = variables_->begin( ); i != variables_->end( ); ++i )
806 res.variables_->push_back( *i );
809 res.locations_ = locations_;
810 res.dst_ = dst_;
811 if( sinkArgList_ != 0 )
813 throw Exceptions::NotImplemented( "Cloning of arguments with sink." );
814 //res.sinkArgList_ = sinkArgList_->clone( );
815 res.sinkValues_ = sinkValues_;
818 return res;
822 void
823 Kernel::Arguments::addOrderedArgument( const Kernel::VariableHandle & arg, Ast::Expression * loc )
825 /* Recall that if there's a sink, this will be the last argument.
827 if( ! isSink_ &&
828 dst_ >= dstEnd_ )
830 /* If there is a sink, put it there. Otherwise, we have detected an arity mismatch, but to generate a good
831 * error message we don't throw the message from here, but rest assured that an error will be delivered in
832 * due time when applyDefaults is invoked.
834 if( hasSink_ )
836 sinkArgList_->orderedExprs_->push_back( loc );
837 sinkValues_ = RefCountPtr< Lang::SingleList >( new Lang::SingleListPair( arg, sinkValues_ ) );
839 else
841 variables_->push_back( arg );
842 locations_.push_back( loc );
843 ++dst_; // I'm not sure this is meaningful here...
846 else if( dst_ == variables_->size( ) )
848 variables_->push_back( arg );
849 locations_.push_back( loc );
850 ++dst_;
852 else
854 (*variables_)[ dst_ ] = arg;
855 locations_[ dst_ ] = loc;
856 while( dst_ < variables_->size( ) &&
857 (*variables_)[ dst_ ] != Kernel::THE_SLOT_VARIABLE )
859 ++dst_;
864 void
865 Kernel::Arguments::addNamedArgument( const char * id, const Kernel::VariableHandle & arg, Ast::Expression * loc )
867 if( formals_ == 0 )
869 throw Exceptions::CoreNoNamedFormals( "???" );
872 typedef typeof *(formals_->formals_->argumentOrder_) FormalsMapType;
873 FormalsMapType & formalsMap = *(formals_->formals_->argumentOrder_);
875 /* Note that the name of the sink is invisible, so referring to it is just another arguments which is
876 * put in the sink. This variable happens to have the same name as the sink.
878 FormalsMapType::const_iterator j = formalsMap.find( id );
879 if( j == formalsMap.end( ) ||
880 ( hasSink_ &&
881 j->second == dstEnd_ ) )
883 if( hasSink_ )
885 if( sinkArgList_->namedExprs_->find( id ) != sinkArgList_->namedExprs_->end( ) )
887 throw Exceptions::InternalError( "It is a surprise that the sink got a repeated formal." );
889 sinkArgList_->namedExprs_->insert( std::pair< const char *, Ast::Expression * >( id, loc ) );
890 sinkValues_ = RefCountPtr< Lang::SingleList >( new Lang::SingleListPair( arg, sinkValues_ ) );
891 return;
893 throw Exceptions::NamedFormalMismatch( formals_->formals_->loc( ), strrefdup( id ), Exceptions::NamedFormalMismatch::VARIABLE );
895 size_t pos = j->second;
897 if( pos < dst_ )
899 throw Exceptions::NamedFormalAlreadySpecified( formals_->formals_->loc( ), strrefdup( id ), pos, Exceptions::NamedFormalAlreadySpecified::VARIABLE );
902 if( pos >= variables_->size( ) )
904 while( variables_->size( ) < pos )
906 variables_->push_back( Kernel::THE_SLOT_VARIABLE );
907 locations_.push_back( 0 );
909 variables_->push_back( arg );
910 locations_.push_back( loc );
912 else
914 if( (*variables_)[ pos ] != Kernel::THE_SLOT_VARIABLE )
916 throw Exceptions::NamedFormalAlreadySpecified( formals_->formals_->loc( ), strrefdup( id ), pos, Exceptions::NamedFormalAlreadySpecified::VARIABLE );
918 (*variables_)[ pos ] = arg;
919 locations_[ pos ] = loc;
921 if( pos == dst_ )
923 while( dst_ < variables_->size( ) &&
924 (*variables_)[ dst_ ] != Kernel::THE_SLOT_VARIABLE )
926 ++dst_;
931 void
932 Kernel::Arguments::addOrderedState( const Kernel::StateHandle & state, Ast::Node * loc )
934 if( stateDst_ == states_->size( ) )
936 states_->push_back( state );
937 stateLocations_.push_back( loc );
938 ++stateDst_;
940 else
942 (*states_)[ stateDst_ ] = state;
943 stateLocations_[ stateDst_ ] = loc;
944 while( stateDst_ < states_->size( ) &&
945 (*states_)[ stateDst_ ] != Kernel::THE_SLOT_STATE )
947 ++stateDst_;
952 void
953 Kernel::Arguments::addNamedState( const char * id, const Kernel::StateHandle & state, Ast::Node * loc )
955 if( formals_ == 0 )
957 throw Exceptions::CoreNoNamedFormals( "???" );
960 typedef typeof *(formals_->formals_->stateOrder_) FormalsMapType;
961 FormalsMapType & formalsMap = *(formals_->formals_->stateOrder_);
963 FormalsMapType::const_iterator j = formalsMap.find( id );
964 if( j == formalsMap.end( ) )
966 throw Exceptions::NamedFormalMismatch( formals_->formals_->loc( ), strrefdup( id ), Exceptions::NamedFormalMismatch::STATE );
968 size_t pos = j->second;
970 if( pos < stateDst_ )
972 throw Exceptions::NamedFormalAlreadySpecified( formals_->formals_->loc( ), strrefdup( id ), pos, Exceptions::NamedFormalAlreadySpecified::STATE );
975 if( pos >= states_->size( ) )
977 while( states_->size( ) < pos )
979 states_->push_back( Kernel::THE_SLOT_STATE );
980 stateLocations_.push_back( 0 );
982 states_->push_back( state );
983 stateLocations_.push_back( loc );
985 else
987 if( (*states_)[ pos ] != Kernel::THE_SLOT_STATE )
989 throw Exceptions::NamedFormalAlreadySpecified( formals_->formals_->loc( ), strrefdup( id ), pos, Exceptions::NamedFormalAlreadySpecified::STATE );
991 (*states_)[ pos ] = state;
992 stateLocations_[ pos ] = loc;
994 if( pos == stateDst_ )
996 while( stateDst_ < states_->size( ) &&
997 (*states_)[ stateDst_ ] != Kernel::THE_SLOT_STATE )
999 ++stateDst_;
1004 void
1005 Kernel::Arguments::applyDefaults( )
1007 if( formals_ == 0 )
1009 return;
1012 size_t numberOfArguments = variables_->size( );
1013 size_t formalsSize = formals_->defaults_.size( );
1015 if( numberOfArguments > formalsSize &&
1016 ! hasSink_ )
1018 /* The location of the ball must be set by the caller. */
1019 throw Exceptions::UserArityMismatch( formals_->formals_->loc( ), formalsSize, numberOfArguments, Exceptions::UserArityMismatch::VARIABLE );
1022 size_t numberOfStates = states_->size( );
1023 size_t formalsStateSize = formals_->formals_->stateOrder_->size( );
1024 if( numberOfStates > formalsStateSize )
1026 /* The location of the ball must be set by the caller. */
1027 throw Exceptions::UserArityMismatch( formals_->formals_->loc( ), formalsStateSize, numberOfStates, Exceptions::UserArityMismatch::STATE );
1030 /* First the easy part: All states must be specified.
1032 std::map< size_t, RefCountPtr< const char > > * missingStates = 0;
1034 size_t pos = 0;
1035 typedef typeof *states_ ListType;
1036 for( ListType::const_iterator i = states_->begin( ); i != states_->end( ); ++i, ++pos )
1038 if( *i == Kernel::THE_SLOT_STATE )
1040 if( missingStates == 0 )
1042 missingStates = new typeof *missingStates;
1044 typedef typeof *(formals_->formals_->stateOrder_) FormalsMapType;
1045 FormalsMapType & formalsMap = *(formals_->formals_->stateOrder_);
1046 for( FormalsMapType::const_iterator i = formalsMap.begin( ); ; )
1048 if( i->second == pos )
1050 missingStates->insert( missingStates->begin( ), std::pair< size_t, RefCountPtr< const char > >( pos, strrefdup( i->first ) ) );
1051 break;
1053 ++i;
1054 if( i == formalsMap.end( ) )
1056 throw Exceptions::InternalError( "Failed to find position of missing state." );
1063 if( numberOfStates < formalsStateSize )
1065 if( missingStates == 0 )
1067 missingStates = new typeof *missingStates;
1069 typedef typeof *(formals_->formals_->stateOrder_) FormalsMapType;
1070 FormalsMapType & formalsMap = *(formals_->formals_->stateOrder_);
1071 FormalsMapType::const_iterator i = formalsMap.begin( );
1072 for( size_t j = 0; j < numberOfStates; ++j )
1074 ++i;
1077 for( ; i != formalsMap.end( ); ++i, ++pos)
1079 missingStates->insert( missingStates->begin( ), std::pair< size_t, RefCountPtr< const char > >( pos, strrefdup( i->first ) ) );
1085 /* Allocate positions in the vector for all arguments.
1087 variables_->reserve( hasSink_ ? formalsSize + 1 : formalsSize );
1088 while( variables_->size( ) < formalsSize )
1090 variables_->push_back( Kernel::THE_SLOT_VARIABLE );
1092 locations_.resize( formalsSize );
1094 typedef typeof *variables_ MyListType;
1095 typedef typeof formals_->defaults_ DefaultListType;
1096 typedef typeof formals_->locations_ LocationListType;
1097 DefaultListType::const_iterator src = formals_->defaults_.begin( );
1098 LocationListType::const_iterator srcLoc = formals_->locations_.begin( );
1099 std::map< size_t, RefCountPtr< const char > > * missingArgs = 0;
1100 size_t pos = 0;
1101 typedef typeof locations_ MyLocationsType;
1102 for( MyListType::iterator dst = variables_->begin( ); dst != variables_->end( ); ++dst, ++src, ++srcLoc, ++pos )
1104 if( *dst == Kernel::THE_SLOT_VARIABLE )
1106 /* Handle error situation.
1108 if( *src == Kernel::THE_SLOT_VARIABLE )
1110 if( missingArgs == 0 )
1112 missingArgs = new typeof *missingArgs;
1114 typedef typeof *(formals_->formals_->argumentOrder_) FormalsMapType;
1115 FormalsMapType & formalsMap = *(formals_->formals_->argumentOrder_);
1116 for( FormalsMapType::const_iterator i = formalsMap.begin( ); ; )
1118 if( i->second == pos )
1120 missingArgs->insert( missingArgs->begin( ), std::pair< size_t, RefCountPtr< const char > >( pos, strrefdup( i->first ) ) );
1121 break;
1123 ++i;
1124 if( i == formalsMap.end( ) )
1126 throw Exceptions::InternalError( "Failed to find position of missing argument." );
1131 /* Normal case.
1133 *dst = *src;
1134 locations_[ pos ] = *srcLoc;
1138 if( missingArgs != 0 || missingStates != 0 )
1140 throw Exceptions::MissingArguments( formals_->formals_->loc( ), missingArgs, missingStates );
1143 if( hasSink_ )
1145 variables_->push_back
1146 ( Helpers::newValHandle
1147 ( new Lang::Structure( sinkArgList_,
1148 sinkValues_,
1149 true ) ) ); // true means that the sinkArgList_ gets owned by the Structure.
1150 sinkArgList_ = 0;
1155 Kernel::VariableHandle &
1156 Kernel::Arguments::getHandle( size_t i )
1158 return (*variables_)[ i ];
1161 RefCountPtr< const Lang::Value > &
1162 Kernel::Arguments::getValue( size_t i )
1164 return (*variables_)[ i ]->getUntyped( );
1167 const Ast::SourceLocation &
1168 Kernel::Arguments::getLoc( size_t i ) const
1170 return locations_[ i ]->loc( );
1173 const Ast::Node *
1174 Kernel::Arguments::getNode( size_t i ) const
1176 return locations_[ i ];
1179 Kernel::Thunk *
1180 Kernel::Arguments::getThunk( size_t i )
1182 return (*variables_)[ i ]->copyThunk( );
1185 bool
1186 Kernel::Arguments::isSlot( size_t i ) const
1188 return (*variables_)[ i ] == Kernel::THE_SLOT_VARIABLE;
1191 Kernel::StateHandle
1192 Kernel::Arguments::getState( size_t i )
1194 return (*states_)[ i ];
1197 const Ast::SourceLocation &
1198 Kernel::Arguments::getStateLoc( size_t i ) const
1200 return stateLocations_[ i ]->loc( );
1203 size_t
1204 Kernel::Arguments::size( ) const
1206 return variables_->size( );
1209 bool
1210 Kernel::Arguments::empty( ) const
1212 return variables_->empty( );
1215 void
1216 Kernel::Arguments::setMutatorSelf( Kernel::StateHandle mutatorSelf )
1218 mutatorSelf_ = mutatorSelf;
1221 Kernel::StateHandle
1222 Kernel::Arguments::getMutatorSelf( )
1224 if( mutatorSelf_ == 0 )
1226 throw Exceptions::InternalError( "Kernel::Arguments::getMutatorSelf: self is null." );
1228 return mutatorSelf_;
1231 void
1232 Kernel::Arguments::gcMark( Kernel::GCMarkedSet & marked )
1235 typedef typeof *variables_ ListType;
1236 for( ListType::const_iterator i = variables_->begin( ); i != variables_->end( ); ++i )
1238 const_cast< Kernel::Variable * >( i->getPtr( ) )->gcMark( marked );
1243 Kernel::Environment::ValueVector
1244 Kernel::Arguments::getVariables( )
1246 return variables_;
1249 Kernel::Environment::StateVector
1250 Kernel::Arguments::getStates( )
1252 return states_;
1256 namespace Shapes
1258 namespace Kernel
1261 class FunctionOneHandleCont : public Kernel::Continuation
1263 RefCountPtr< const Lang::Function > fun_;
1264 Kernel::PassedDyn dyn_;
1265 Kernel::ContRef cont_;
1266 public:
1267 FunctionOneHandleCont( const RefCountPtr< const Lang::Function > & fun, const Kernel::PassedDyn & dyn, Kernel::ContRef cont, const Ast::SourceLocation & traceLoc )
1268 : Kernel::Continuation( traceLoc ), fun_( fun ), dyn_( dyn ), cont_( cont )
1270 virtual ~FunctionOneHandleCont( ) { }
1271 virtual void takeHandle( Kernel::VariableHandle val, Kernel::EvalState * evalState, bool dummy ) const
1273 /* This continuation really seeks forced arguments, for otherwise a thunk would have been generated directly.
1274 * However, this continuation takes handles anyway, since handles is what goes into the argument list.
1277 if( val->isThunk( ) )
1279 val->force( val, evalState );
1280 return;
1283 Kernel::Arguments args = fun_->newCurriedArguments( );
1284 args.addOrderedArgument( val, & Ast::THE_INTERNAL_VALUE_EXPRESSION );
1286 evalState->dyn_ = dyn_;
1287 evalState->cont_ = cont_;
1288 fun_->call( evalState, args, traceLoc_ );
1290 virtual Kernel::ContRef up( ) const
1292 return cont_;
1294 virtual RefCountPtr< const char > description( ) const
1296 return strrefdup( "internal function call with one handle" );
1298 virtual void gcMark( Kernel::GCMarkedSet & marked )
1300 const_cast< Lang::Function * >( fun_.getPtr( ) )->gcMark( marked );
1301 dyn_->gcMark( marked );
1302 cont_->gcMark( marked );
1306 class FunctionTwoHandlesCont_2 : public Kernel::Continuation
1308 RefCountPtr< const Lang::Function > fun_;
1309 Kernel::VariableHandle arg1_;
1310 Kernel::PassedDyn dyn_;
1311 Kernel::ContRef cont_;
1312 public:
1313 FunctionTwoHandlesCont_2( const RefCountPtr< const Lang::Function > & fun, const Kernel::VariableHandle & arg1, const Kernel::PassedDyn & dyn, Kernel::ContRef cont, const Ast::SourceLocation & traceLoc )
1314 : Kernel::Continuation( traceLoc ), fun_( fun ), arg1_( arg1 ), dyn_( dyn ), cont_( cont )
1316 virtual ~FunctionTwoHandlesCont_2( ) { }
1317 virtual void takeHandle( Kernel::VariableHandle arg2, Kernel::EvalState * evalState, bool dummy ) const
1319 /* This continuation really seeks forced arguments, for otherwise a thunk would have been generated directly.
1320 * However, this continuation takes handles anyway, since handles is what goes into the argument list.
1323 if( arg2->isThunk( ) )
1325 arg2->force( arg2, evalState );
1326 return;
1329 Kernel::Arguments args = fun_->newCurriedArguments( );
1330 args.addOrderedArgument( arg1_, & Ast::THE_INTERNAL_VALUE_EXPRESSION );
1331 args.addOrderedArgument( arg2, & Ast::THE_INTERNAL_VALUE_EXPRESSION );
1332 evalState->dyn_ = dyn_;
1333 evalState->cont_ = cont_;
1334 fun_->call( evalState, args, traceLoc_ );
1336 virtual Kernel::ContRef up( ) const
1338 return cont_;
1340 virtual RefCountPtr< const char > description( ) const
1342 return strrefdup( "internal function call with two handles, second" );
1344 virtual void gcMark( Kernel::GCMarkedSet & marked )
1346 const_cast< Lang::Function * >( fun_.getPtr( ) )->gcMark( marked );
1347 dyn_->gcMark( marked );
1348 cont_->gcMark( marked );
1352 class FunctionTwoHandlesCont_1 : public Kernel::Continuation
1354 RefCountPtr< const Lang::Function > fun_;
1355 Kernel::VariableHandle arg2_;
1356 bool forceArg2_;
1357 Kernel::PassedDyn dyn_;
1358 Kernel::ContRef cont_;
1359 public:
1360 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 )
1361 : Kernel::Continuation( traceLoc ), fun_( fun ), arg2_( arg2 ), forceArg2_( forceArg2 ), dyn_( dyn ), cont_( cont )
1363 virtual ~FunctionTwoHandlesCont_1( ) { }
1364 virtual void takeHandle( Kernel::VariableHandle arg1, Kernel::EvalState * evalState, bool dummy ) const
1366 /* This continuation really seeks forced arguments, for otherwise a thunk would have been generated directly.
1367 * However, this continuation takes handles anyway, since handles is what goes into the argument list.
1370 if( arg1->isThunk( ) )
1372 arg1->force( arg1, evalState );
1373 return;
1376 if( forceArg2_ )
1378 Kernel::ContRef newCont = Kernel::ContRef( new Kernel::FunctionTwoHandlesCont_2( fun_, arg1, dyn_, cont_, traceLoc_ ) );
1379 evalState->cont_ = newCont;
1380 newCont->takeHandle( arg2_, evalState );
1381 return;
1384 /* The second handle need not be forced
1386 Kernel::Arguments args = fun_->newCurriedArguments( );
1387 args.addOrderedArgument( arg1, & Ast::THE_INTERNAL_VALUE_EXPRESSION );
1388 args.addOrderedArgument( arg2_, & Ast::THE_INTERNAL_VALUE_EXPRESSION );
1389 evalState->dyn_ = dyn_;
1390 evalState->cont_ = cont_;
1391 fun_->call( evalState, args, traceLoc_ );
1393 virtual Kernel::ContRef up( ) const
1395 return cont_;
1397 virtual RefCountPtr< const char > description( ) const
1399 return strrefdup( "internal function call with two handles, first" );
1401 virtual void gcMark( Kernel::GCMarkedSet & marked )
1403 const_cast< Lang::Function * >( fun_.getPtr( ) )->gcMark( marked );
1404 dyn_->gcMark( marked );
1405 cont_->gcMark( marked );
1409 class FunctionTwoHandlesOneStateCont_2 : public Kernel::Continuation
1411 RefCountPtr< const Lang::Function > fun_;
1412 Kernel::VariableHandle arg1_;
1413 Kernel::StateHandle state_;
1414 Kernel::PassedDyn dyn_;
1415 Kernel::ContRef cont_;
1416 public:
1417 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 )
1418 : Kernel::Continuation( traceLoc ), fun_( fun ), arg1_( arg1 ), state_( state ), dyn_( dyn ), cont_( cont )
1420 virtual ~FunctionTwoHandlesOneStateCont_2( ) { }
1421 virtual void takeHandle( Kernel::VariableHandle arg2, Kernel::EvalState * evalState, bool dummy ) const
1423 /* This continuation really seeks forced arguments, for otherwise a thunk would have been generated directly.
1424 * However, this continuation takes handles anyway, since handles is what goes into the argument list.
1427 if( arg2->isThunk( ) )
1429 arg2->force( arg2, evalState );
1430 return;
1433 Kernel::Arguments args = fun_->newCurriedArguments( );
1434 args.addOrderedArgument( arg1_, & Ast::THE_INTERNAL_VALUE_EXPRESSION );
1435 args.addOrderedArgument( arg2, & Ast::THE_INTERNAL_VALUE_EXPRESSION );
1436 args.addOrderedState( state_, & Ast::THE_INTERNAL_VALUE_EXPRESSION );
1437 evalState->dyn_ = dyn_;
1438 evalState->cont_ = cont_;
1439 fun_->call( evalState, args, traceLoc_ );
1441 virtual Kernel::ContRef up( ) const
1443 return cont_;
1445 virtual RefCountPtr< const char > description( ) const
1447 return strrefdup( "internal function call with two handles and one state, second" );
1449 virtual void gcMark( Kernel::GCMarkedSet & marked )
1451 const_cast< Lang::Function * >( fun_.getPtr( ) )->gcMark( marked );
1452 state_->gcMark( marked );
1453 dyn_->gcMark( marked );
1454 cont_->gcMark( marked );
1458 class FunctionTwoHandlesOneStateCont_1 : public Kernel::Continuation
1460 RefCountPtr< const Lang::Function > fun_;
1461 Kernel::VariableHandle arg2_;
1462 bool forceArg2_;
1463 Kernel::StateHandle state_;
1464 Kernel::PassedDyn dyn_;
1465 Kernel::ContRef cont_;
1466 public:
1467 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 )
1468 : Kernel::Continuation( traceLoc ), fun_( fun ), arg2_( arg2 ), forceArg2_( forceArg2 ), state_( state ), dyn_( dyn ), cont_( cont )
1470 virtual ~FunctionTwoHandlesOneStateCont_1( ) { }
1471 virtual void takeHandle( Kernel::VariableHandle arg1, Kernel::EvalState * evalState, bool dummy ) const
1473 /* This continuation really seeks forced arguments, for otherwise a thunk would have been generated directly.
1474 * However, this continuation takes handles anyway, since handles is what goes into the argument list.
1477 if( arg1->isThunk( ) )
1479 arg1->force( arg1, evalState );
1480 return;
1483 if( forceArg2_ )
1485 Kernel::ContRef newCont = Kernel::ContRef( new Kernel::FunctionTwoHandlesOneStateCont_2( fun_, arg1, state_, dyn_, cont_, traceLoc_ ) );
1486 evalState->cont_ = newCont;
1487 newCont->takeHandle( arg2_, evalState );
1488 return;
1491 /* The second handle need not be forced
1493 Kernel::Arguments args = fun_->newCurriedArguments( );
1494 args.addOrderedArgument( arg1, & Ast::THE_INTERNAL_VALUE_EXPRESSION );
1495 args.addOrderedArgument( arg2_, & Ast::THE_INTERNAL_VALUE_EXPRESSION );
1496 args.addOrderedState( state_, & Ast::THE_INTERNAL_VALUE_EXPRESSION );
1497 evalState->dyn_ = dyn_;
1498 evalState->cont_ = cont_;
1499 fun_->call( evalState, args, traceLoc_ );
1501 virtual Kernel::ContRef up( ) const
1503 return cont_;
1505 virtual RefCountPtr< const char > description( ) const
1507 return strrefdup( "internal function call with two handles and one state, first" );
1509 virtual void gcMark( Kernel::GCMarkedSet & marked )
1511 const_cast< Lang::Function * >( fun_.getPtr( ) )->gcMark( marked );
1512 dyn_->gcMark( marked );
1513 cont_->gcMark( marked );
1514 state_->gcMark( marked );
1522 Lang::Function::Function( Kernel::EvaluatedFormals * formals )
1523 : formals_( formals )
1526 DISPATCHIMPL( Function );
1528 Lang::Function::~Function( )
1530 if( formals_ != 0 )
1532 delete formals_->formals_;
1533 delete formals_;
1537 Kernel::ValueRef
1538 Lang::Function::transformed( const Lang::Transform2D & tf, Kernel::ValueRef self ) const
1540 return Kernel::ValueRef( new Lang::TransformedFunction2D( tf, self.down_cast< const Lang::Function >( ) ) );
1543 void
1544 Lang::Function::call( Kernel::EvalState * evalState, const Kernel::ValueRef & arg1, const Ast::SourceLocation & callLoc ) const
1546 Kernel::Arguments args = this->newCurriedArguments( );
1548 args.addOrderedArgument( Kernel::VariableHandle( new Kernel::Variable( arg1 ) ), & Ast::THE_INTERNAL_VALUE_EXPRESSION );
1550 this->call( evalState, args, callLoc );
1553 void
1554 Lang::Function::analyze( Ast::Node * parent, Ast::AnalysisEnvironment * env )
1556 Ast::StateIDSet * freeStates = new Ast::StateIDSet;
1557 this->analyze_impl( parent, env, freeStates );
1558 if( ! freeStates->empty( ) )
1560 Ast::theAnalysisErrorsList.push_back( new Exceptions::IllegalFreeStates( parent->loc( ), freeStates, "this is a function" ) );
1562 else
1564 delete freeStates;
1568 void
1569 Lang::Function::analyze_impl( Ast::Node * parent, Ast::AnalysisEnvironment * env, Ast::StateIDSet * freeStatesDst )
1571 throw Exceptions::InternalError( "A syntax function is not overriding the analyze method." );
1574 void
1575 Lang::Function::call( Kernel::EvalState * evalState, const Kernel::ValueRef & arg1, const Kernel::ValueRef & arg2, const Ast::SourceLocation & callLoc ) const
1577 Kernel::Arguments args = this->newCurriedArguments( );
1579 args.addOrderedArgument( Kernel::VariableHandle( new Kernel::Variable( arg1 ) ), & Ast::THE_INTERNAL_VALUE_EXPRESSION );
1580 args.addOrderedArgument( Kernel::VariableHandle( new Kernel::Variable( arg2 ) ), & Ast::THE_INTERNAL_VALUE_EXPRESSION );
1582 this->call( evalState, args, callLoc );
1585 Ast::ArgListExprs * Lang::Function::oneExprArgList = new Ast::ArgListExprs( static_cast< size_t >( 1 ) );
1586 Ast::ArgListExprs * Lang::Function::twoExprsArgList = new Ast::ArgListExprs( static_cast< size_t >( 2 ) );
1588 void
1589 Lang::Function::call( const RefCountPtr< const Lang::Function > & selfRef, Kernel::EvalState * evalState, const Kernel::VariableHandle & arg1, const Ast::SourceLocation & callLoc ) const
1591 const RefCountPtr< const Kernel::CallContInfo > info = this->newCallContInfo( Lang::Function::oneExprArgList, *evalState );
1593 if( info->force( 0 ) )
1595 Kernel::ContRef cont = Kernel::ContRef( new Kernel::FunctionOneHandleCont( selfRef, evalState->dyn_, evalState->cont_, callLoc ) );
1596 evalState->cont_ = cont;
1597 cont->takeHandle( arg1, evalState );
1598 return;
1601 /* The handle need not be forced
1603 Kernel::Arguments args = this->newCurriedArguments( );
1604 args.addOrderedArgument( arg1, & Ast::THE_INTERNAL_VALUE_EXPRESSION );
1605 this->call( evalState, args, callLoc );
1608 void
1609 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
1611 const RefCountPtr< const Kernel::CallContInfo > info = this->newCallContInfo( Lang::Function::twoExprsArgList, *evalState );
1613 /* Remember that arguments are ordered backwards!
1616 if( info->force( 1 ) )
1618 Kernel::ContRef cont = Kernel::ContRef( new Kernel::FunctionTwoHandlesCont_1( selfRef, arg2, info->force( 0 ), evalState->dyn_, evalState->cont_, callLoc ) );
1619 evalState->cont_ = cont;
1620 cont->takeHandle( arg1, evalState );
1621 return;
1624 if( info->force( 0 ) )
1626 Kernel::ContRef cont = Kernel::ContRef( new Kernel::FunctionTwoHandlesCont_2( selfRef, arg1, evalState->dyn_, evalState->cont_, callLoc ) );
1627 evalState->cont_ = cont;
1628 cont->takeHandle( arg2, evalState );
1629 return;
1632 /* None of the handles need to be forced
1634 Kernel::Arguments args = this->newCurriedArguments( );
1635 args.addOrderedArgument( arg1, & Ast::THE_INTERNAL_VALUE_EXPRESSION );
1636 args.addOrderedArgument( arg2, & Ast::THE_INTERNAL_VALUE_EXPRESSION );
1637 this->call( evalState, args, callLoc );
1640 void
1641 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
1643 /* I'm not quite sure if we should also put a dummy state argument in info...
1645 const RefCountPtr< const Kernel::CallContInfo > info = this->newCallContInfo( Lang::Function::twoExprsArgList, *evalState );
1647 /* Remember that arguments are ordered backwards!
1650 if( info->force( 1 ) )
1652 Kernel::ContRef cont = Kernel::ContRef( new Kernel::FunctionTwoHandlesOneStateCont_1( selfRef, arg2, info->force( 0 ), state, evalState->dyn_, evalState->cont_, callLoc ) );
1653 evalState->cont_ = cont;
1654 cont->takeHandle( arg1, evalState );
1655 return;
1658 if( info->force( 0 ) )
1660 Kernel::ContRef cont = Kernel::ContRef( new Kernel::FunctionTwoHandlesOneStateCont_2( selfRef, arg1, state, evalState->dyn_, evalState->cont_, callLoc ) );
1661 evalState->cont_ = cont;
1662 cont->takeHandle( arg2, evalState );
1663 return;
1666 /* None of the handles need to be forced
1668 Kernel::Arguments args = this->newCurriedArguments( );
1669 args.addOrderedArgument( arg1, & Ast::THE_INTERNAL_VALUE_EXPRESSION );
1670 args.addOrderedArgument( arg2, & Ast::THE_INTERNAL_VALUE_EXPRESSION );
1671 args.addOrderedState( state, & Ast::THE_INTERNAL_VALUE_EXPRESSION );
1672 this->call( evalState, args, callLoc );
1676 RefCountPtr< Kernel::CallContInfo >
1677 Lang::Function::newCallContInfo( const Ast::ArgListExprs * argList, const Kernel::EvalState & evalState ) const
1679 return formals_->newCallContInfo( argList, evalState );
1682 RefCountPtr< Kernel::CallContInfo >
1683 Lang::Function::newCallContInfo( const Ast::ArgListExprs * argList, const Kernel::EvalState & evalState, const Kernel::Arguments & curryArgs ) const
1685 return formals_->newCallContInfo( argList, evalState, curryArgs );
1688 Kernel::Arguments
1689 Lang::Function::newCurriedArguments( ) const
1691 return Kernel::Arguments( formals_ );
1695 RefCountPtr< const Lang::Class > Lang::Function::TypeID( new Lang::SystemFinalClass( strrefdup( "Function" ) ) );
1696 TYPEINFOIMPL( Function );
1698 Kernel::EvaluatedFormals::EvaluatedFormals( Kernel::Formals * formals )
1699 : selectiveForcing_( false ), forceAll_( false ), formals_( formals ), isSink_( true )
1702 Kernel::EvaluatedFormals::EvaluatedFormals( const Ast::FileID * locationFileID )
1703 : selectiveForcing_( true ), formals_( 0 ), isSink_( true )
1705 Kernel::Formals * formals( new Kernel::Formals( ) );
1706 formals->setLoc( Ast::SourceLocation( locationFileID ) );
1707 formals_ = formals;
1710 Kernel::EvaluatedFormals::EvaluatedFormals( const Ast::FileID * locationFileID, bool forceAll)
1711 : selectiveForcing_( false ), forceAll_( forceAll ), formals_( 0 ), isSink_( true )
1713 Kernel::Formals * formals( new Kernel::Formals( ) );
1714 formals->setLoc( Ast::SourceLocation( locationFileID ) );
1715 formals_ = formals;
1718 Kernel::EvaluatedFormals::~EvaluatedFormals( )
1720 /* Don't delete the orderedFormals, since we don't own it. A case for reference counting? */
1723 RefCountPtr< Kernel::CallContInfo >
1724 Kernel::EvaluatedFormals::newCallContInfo( const Ast::ArgListExprs * argList, const Kernel::EvalState & evalState ) const
1726 if( selectiveForcing_ )
1728 return RefCountPtr< Kernel::CallContInfo >( new Kernel::CallContInfo( argList, evalState, formals_->newArgListForcePos( argList ) ) );
1730 else
1732 return RefCountPtr< Kernel::CallContInfo >( new Kernel::CallContInfo( argList, evalState, forceAll_ ) );
1736 RefCountPtr< Kernel::CallContInfo >
1737 Kernel::EvaluatedFormals::newCallContInfo( const Ast::ArgListExprs * argList, const Kernel::EvalState & evalState, const Kernel::Arguments & curryArgs ) const
1739 if( selectiveForcing_ )
1741 return RefCountPtr< Kernel::CallContInfo >( new Kernel::CallContInfo( argList, evalState, formals_->newArgListForcePos( argList, curryArgs ) ) );
1743 else
1745 return RefCountPtr< Kernel::CallContInfo >( new Kernel::CallContInfo( argList, evalState, forceAll_ ) );
1749 void
1750 Kernel::EvaluatedFormals::appendEvaluatedFormal( const char * id, const Kernel::VariableHandle & defaultVal, const Ast::Node * loc, bool force )
1752 if( ! selectiveForcing_ )
1754 throw Exceptions::InternalError( "EvaluatedFormals::appendEvaluatedFormal: Function does not have selective forcing." );
1756 (*(formals_->argumentOrder_))[ id ] = defaults_.size( );
1757 formals_->forcePos_.push_back( force );
1758 defaults_.push_back( defaultVal );
1759 locations_.push_back( loc );
1762 void
1763 Kernel::EvaluatedFormals::appendEvaluatedFormal( const char * id, const Kernel::VariableHandle & defaultVal, const Ast::Node * loc )
1765 if( selectiveForcing_ )
1767 throw Exceptions::InternalError( "EvaluatedFormals::appendEvaluatedFormal: Function requires individual forcing specification." );
1769 (*(formals_->argumentOrder_))[ id ] = defaults_.size( );
1770 formals_->forcePos_.push_back( forceAll_ );
1771 defaults_.push_back( defaultVal );
1772 locations_.push_back( loc );
1775 void
1776 Kernel::EvaluatedFormals::appendEvaluatedCoreFormal( const char * id, const Kernel::VariableHandle & defaultVal, bool force )
1778 appendEvaluatedFormal( id, defaultVal, & Ast::THE_CORE_DEFAULT_VALUE_EXPRESSION, force );
1781 void
1782 Kernel::EvaluatedFormals::appendEvaluatedCoreFormal( const char * id, const Kernel::VariableHandle & defaultVal )
1784 appendEvaluatedFormal( id, defaultVal, & Ast::THE_CORE_DEFAULT_VALUE_EXPRESSION );
1787 void
1788 Kernel::EvaluatedFormals::appendCoreStateFormal( const char * id )
1790 (*(formals_->stateOrder_))[ id ] = formals_->stateOrder_->size( );
1793 void
1794 Kernel::EvaluatedFormals::gcMark( Kernel::GCMarkedSet & marked )
1796 typedef typeof defaults_ ListType;
1797 for( ListType::const_iterator i = defaults_.begin( ); i != defaults_.end( ); ++i )
1799 if( *i != NullPtr< Kernel::Variable >( ) )
1801 const_cast< Kernel::Variable * >( i->getPtr( ) )->gcMark( marked );
1807 Lang::CuteFunction::CuteFunction( RefCountPtr< const Lang::Function > callee, const Kernel::Arguments & someArgs )
1808 : Lang::Function( 0 ), callee_( callee), someArgs_( someArgs.clone( ) )
1811 Lang::CuteFunction::~CuteFunction( )
1814 RefCountPtr< Kernel::CallContInfo >
1815 Lang::CuteFunction::newCallContInfo( const Ast::ArgListExprs * argList, const Kernel::EvalState & evalState ) const
1817 return callee_->newCallContInfo( argList, evalState, someArgs_ );
1820 RefCountPtr< Kernel::CallContInfo >
1821 Lang::CuteFunction::newCallContInfo( const Ast::ArgListExprs * argList, const Kernel::EvalState & evalState, const Kernel::Arguments & curryArgs ) const
1823 /* when we are the callee of a CuteFunction, our someArgs are part of that CuteFunction's someArgs, and hence curryArgs
1824 * contains everything that is to be passed to our callee.
1826 return callee_->newCallContInfo( argList, evalState, curryArgs );
1829 Kernel::Arguments
1830 Lang::CuteFunction::newCurriedArguments( ) const
1832 return someArgs_.clone( );
1835 void
1836 Lang::CuteFunction::call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1838 /* Note that curruying "takes place" in newCurriedArguments. Other than that, this is the same as the original function.
1839 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.
1841 callee_->call( evalState, args, callLoc );
1844 bool
1845 Lang::CuteFunction::isTransforming( ) const
1847 return callee_->isTransforming( );
1850 void
1851 Lang::CuteFunction::gcMark( Kernel::GCMarkedSet & marked )
1853 const_cast< Lang::Function * >( callee_.getPtr( ) )->gcMark( marked );
1854 someArgs_.gcMark( marked );
1857 void
1858 Lang::CuteFunction::show( std::ostream & os ) const
1860 os << "< evaluated cut of: " ;
1861 callee_->show( os );
1862 os << " >" ;
1866 Lang::ComposedFunction::ComposedFunction( const RefCountPtr< const Lang::Function > & second, const RefCountPtr< const Lang::Function > & first )
1867 : Lang::Function( 0 ), second_( second ), first_( first )
1870 Lang::ComposedFunction::~ComposedFunction( )
1873 void
1874 Lang::ComposedFunction::call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1876 /* Note that curruying "takes place" in newCurriedArguments. Other than that, this is the same as the original function.
1877 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.
1879 evalState->cont_ = Kernel::ContRef( new Kernel::ComposedFunctionCall_cont( second_, evalState->dyn_, evalState->cont_, callLoc ) );
1880 first_->call( evalState, args, callLoc );
1883 RefCountPtr< Kernel::CallContInfo >
1884 Lang::ComposedFunction::newCallContInfo( const Ast::ArgListExprs * argList, const Kernel::EvalState & evalState ) const
1886 return first_->newCallContInfo( argList, evalState );
1889 RefCountPtr< Kernel::CallContInfo >
1890 Lang::ComposedFunction::newCallContInfo( const Ast::ArgListExprs * argList, const Kernel::EvalState & evalState, const Kernel::Arguments & curryArgs ) const
1892 return first_->newCallContInfo( argList, evalState, curryArgs );
1895 Kernel::Arguments
1896 Lang::ComposedFunction::newCurriedArguments( ) const
1898 return first_->newCurriedArguments( );
1901 bool
1902 Lang::ComposedFunction::isTransforming( ) const
1904 return second_->isTransforming( );
1907 void
1908 Lang::ComposedFunction::gcMark( Kernel::GCMarkedSet & marked )
1910 const_cast< Lang::Function * >( second_.getPtr( ) )->gcMark( marked );
1911 const_cast< Lang::Function * >( first_.getPtr( ) )->gcMark( marked );
1914 void
1915 Lang::ComposedFunction::show( std::ostream & os ) const
1917 os << "< composition: " ;
1918 second_->show( os );
1919 os << " () " ;
1920 first_->show( os );
1921 os << " >" ;
1925 Lang::UserFunction::UserFunction( Kernel::EvaluatedFormals * formals, Ast::Expression * body, Kernel::PassedEnv env, const Ast::FunctionMode & functionMode )
1926 : Lang::Function( formals ), body_( body ), env_( env ), functionMode_( functionMode )
1929 // DISPATCHIMPL( UserFunction );
1931 Lang::UserFunction::~UserFunction( )
1933 // Note that we don't delete the things that we most likely share with other objects
1934 // Reference counting could be used here, but there will never be more such things than there are function expressions in the source
1936 // This prevents formals->formals from being deleted by Lang::Function::~Function
1937 delete formals_;
1938 formals_ = 0;
1941 void
1942 Lang::UserFunction::call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1944 args.applyDefaults( );
1945 evalState->env_ = new Kernel::Environment( Kernel::theEnvironmentList, env_, formals_->formals_->argumentOrder_, args.getVariables( ), formals_->formals_->stateOrder_, args.getStates( ), "Closure" );
1946 evalState->env_->activateFunctionBoundary( );
1947 evalState->expr_ = body_;
1950 bool
1951 Lang::UserFunction::isTransforming( ) const
1953 return ( functionMode_ & Ast::FUNCTION_TRANSFORMING ) != 0;
1956 void
1957 Lang::UserFunction::gcMark( Kernel::GCMarkedSet & marked )
1959 env_->gcMark( marked );
1962 Ast::Expression *
1963 Lang::UserFunction::body( )
1965 return body_;
1968 void
1969 Lang::UserFunction::show( std::ostream & os ) const
1971 os << "< user function with body at " << body_->loc( ) << " >" ;
1975 Lang::TransformedFunction2D::TransformedFunction2D( const Lang::Transform2D & tf, const RefCountPtr< const Lang::Function > & fun )
1976 : Lang::Function( 0 ), tf_( tf ), fun_( fun )
1979 Lang::TransformedFunction2D::~TransformedFunction2D( )
1982 void
1983 Lang::TransformedFunction2D::call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1985 evalState->cont_ = Kernel::ContRef( new Kernel::Transform2DCont( tf_, evalState->cont_, 0 ) );
1986 fun_->call( evalState, args, callLoc );
1989 bool
1990 Lang::TransformedFunction2D::isTransforming( ) const
1992 return fun_->isTransforming( );
1995 void
1996 Lang::TransformedFunction2D::gcMark( Kernel::GCMarkedSet & marked )
1998 const_cast< Lang::Function * >( fun_.getPtr( ) )->gcMark( marked );
2001 void
2002 Lang::TransformedFunction2D::show( std::ostream & os ) const
2004 os << "< transformed function >" ;
2009 Lang::VectorFunction::VectorFunction( const std::vector< Kernel::ValueRef > * mem )
2010 : Lang::Function( new Kernel::EvaluatedFormals( Ast::FileID::build_internal( "<vector>" ), true ) ), mem_( mem ),
2011 memNumeric_( NullPtr< const std::vector< double > >( ) )
2013 formals_->appendEvaluatedCoreFormal( "index", Kernel::THE_SLOT_VARIABLE );
2016 // DISPATCHIMPL( VectorFunction );
2018 Lang::VectorFunction::~VectorFunction( )
2021 Kernel::VariableHandle
2022 Lang::VectorFunction::getField( const char * fieldID, const RefCountPtr< const Lang::Value > & selfRef ) const
2024 if( strcmp( fieldID, "size" ) == 0 )
2026 return Helpers::newValHandle( new Lang::Integer( mem_->size( ) ) );
2028 throw Exceptions::NonExistentMember( getTypeName( ), fieldID );
2031 const char * Lang::VectorFunction::title_ = "<vector>";
2033 void
2034 Lang::VectorFunction::call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
2036 const size_t ARITY = 1;
2037 if( args.size( ) != ARITY )
2039 throw Exceptions::CoreArityMismatch( title_, ARITY, args.size( ) );
2042 typedef const Lang::Integer ArgType;
2043 RefCountPtr< ArgType > arg = Helpers::down_cast_CoreArgument< ArgType >( title_, args, 0, callLoc );
2045 if( arg->val_ < 0 )
2047 throw Exceptions::CoreOutOfRange( title_, args, 0, "Index is negative." );
2050 if( arg->val_ >= static_cast< int >( mem_->size( ) ) )
2052 throw Exceptions::CoreOutOfRange( title_, args, 0, "Index exceeds vector size." );
2055 Kernel::ContRef cont = evalState->cont_;
2056 cont->takeValue( (*mem_)[ arg->val_ ],
2057 evalState );
2060 bool
2061 Lang::VectorFunction::isTransforming( ) const
2063 return false;
2066 void
2067 Lang::VectorFunction::gcMark( Kernel::GCMarkedSet & marked )
2069 for( std::vector< Kernel::ValueRef >::const_iterator i = mem_->begin( ); i != mem_->end( ); ++i )
2071 const_cast< Lang::Value * >( i->getPtr( ) )->gcMark( marked );
2075 void
2076 Lang::VectorFunction::show( std::ostream & os ) const
2078 os << "< vector function >" ;
2081 RefCountPtr< const std::vector< double > >
2082 Lang::VectorFunction::getNumeric( const Ast::SourceLocation & callLoc ) const
2084 if( memNumeric_ == NullPtr< const std::vector< double > >( ) )
2086 RefCountPtr< std::vector< double > > res( new std::vector< double > ); // Note that this is not const, so far...
2087 res->reserve( mem_->size( ) );
2088 typedef typeof *mem_ SrcType;
2089 for( SrcType::const_iterator src = mem_->begin( ); src != mem_->end( ); ++src )
2091 res->push_back( Helpers::down_cast< const Lang::Float >( *src, callLoc )->val_ );
2094 memNumeric_ = res;
2096 return memNumeric_;
2100 const char * Lang::ColorInterpolator::title_ = "<color-interpolator>";
2102 Lang::ColorInterpolator::ColorInterpolator( const RefCountPtr< KeyContainer > & key,
2103 const RefCountPtr< RGBContainer > & RGBcolor,
2104 const RefCountPtr< GrayContainer > & graycolor,
2105 const RefCountPtr< CMYKContainer > & CMYKcolor,
2106 ColorType colorType)
2107 : Lang::Function( new Kernel::EvaluatedFormals( Ast::FileID::build_internal( Lang::ColorInterpolator::title_ ), true ) ),
2108 key_( key ), RGBcolor_ ( RGBcolor ), graycolor_ ( graycolor ), CMYKcolor_ ( CMYKcolor ), colorType_(colorType)
2110 formals_->appendEvaluatedCoreFormal( "key", Kernel::THE_SLOT_VARIABLE );
2113 Lang::ColorInterpolator::~ColorInterpolator( )
2116 Kernel::VariableHandle
2117 Lang::ColorInterpolator::getField( const char * fieldID, const RefCountPtr< const Lang::Value > & selfRef ) const
2119 if( strcmp( fieldID, "low" ) == 0 )
2121 return Helpers::newValHandle( new Lang::Float( key_->front( ) ) );
2123 if( strcmp( fieldID, "high" ) == 0 )
2125 return Helpers::newValHandle( new Lang::Float( key_->back( ) ) );
2127 throw Exceptions::NonExistentMember( getTypeName( ), fieldID );
2131 template <class COLOR_TYPE, class COLOR_CONTAINER>
2132 void
2133 Lang::ColorInterpolator::callHelper( Kernel::EvalState * evalState,
2134 const RefCountPtr< COLOR_CONTAINER > & colorContainer,
2135 double key, KeyContainer::const_iterator keyHi ) const
2137 if( keyHi == key_->end( ) )
2139 Kernel::ContRef cont = evalState->cont_;
2140 cont->takeValue( RefCountPtr< const::Lang::Value >( new COLOR_TYPE( colorContainer->back( ) ) ),
2141 evalState );
2142 return;
2145 if( keyHi == key_->begin( ) )
2147 Kernel::ContRef cont = evalState->cont_;
2148 cont->takeValue( RefCountPtr< const::Lang::Value >( new COLOR_TYPE( colorContainer->front( ) ) ),
2149 evalState );
2150 return;
2153 KeyContainer::const_iterator keyLo = keyHi - 1;
2154 double rem = ( key - *keyLo ) / ( *keyHi - *keyLo );
2156 Kernel::ContRef cont = evalState->cont_;
2158 typename COLOR_CONTAINER::const_iterator colorHi = colorContainer->begin( ) + ( keyHi - key_->begin( ) );
2159 typename COLOR_CONTAINER::const_iterator colorLo = colorHi - 1;
2161 cont->takeValue( RefCountPtr< const::Lang::Value >( new COLOR_TYPE( colorLo->mulNoCheck( 1 - rem ).addNoCheck( colorHi->mulNoCheck( rem ) ) ) ),
2162 evalState );
2166 void
2167 Lang::ColorInterpolator::call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
2169 const size_t ARITY = 1;
2170 if( args.size( ) != ARITY )
2172 throw Exceptions::CoreArityMismatch( title_, ARITY, args.size( ) );
2175 typedef const Lang::Float ArgType;
2176 double key = Helpers::down_cast_CoreArgument< ArgType >( title_, args, 0, callLoc )->val_;
2178 KeyContainer::const_iterator keyHi = lower_bound( key_->begin( ), key_->end( ), key );
2179 switch( colorType_ )
2181 case RGB:
2182 callHelper< Lang::RGB >( evalState, RGBcolor_, key, keyHi );
2183 break;
2184 case GRAY:
2185 callHelper< Lang::Gray >( evalState, graycolor_, key, keyHi );
2186 break;
2187 case CMYK:
2188 callHelper< Lang::CMYK >( evalState, CMYKcolor_, key, keyHi );
2189 break;
2190 case UNDEFINED:
2191 throw Exceptions::InternalError( "ColorInterpolator::call: Did not expect UNDEFINED in ennum switch." );
2195 bool
2196 Lang::ColorInterpolator::isTransforming( ) const
2198 return false;
2201 void
2202 Lang::ColorInterpolator::gcMark( Kernel::GCMarkedSet & marked )
2205 void
2206 Lang::ColorInterpolator::show( std::ostream & os ) const
2208 os << "< color interpolator in " ;
2209 switch( colorType_ )
2211 case RGB:
2212 os << "RGB" ;
2213 break;
2214 case GRAY:
2215 os << "Gray" ;
2216 break;
2217 case CMYK:
2218 os << "CMYK" ;
2219 break;
2220 case UNDEFINED:
2221 throw Exceptions::InternalError( "ColorInterpolator::show: Did not expect UNDEFINED in ennum switch." );
2223 os << " mode >" ;
2226 Lang::BinaryOperatorFunction::BinaryOperatorFunction( Ast::BinaryInfixExpr * opExpr, const char * title )
2227 : Lang::Function( new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title ), true ) ), opExpr_( opExpr ), title_( title )
2229 formals_->appendEvaluatedCoreFormal( "first", Kernel::THE_SLOT_VARIABLE );
2230 formals_->appendEvaluatedCoreFormal( "second", Kernel::THE_SLOT_VARIABLE );
2233 Lang::BinaryOperatorFunction::~BinaryOperatorFunction( )
2235 delete opExpr_;
2238 void
2239 Lang::BinaryOperatorFunction::call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
2241 const size_t ARITY = 2;
2242 CHECK_ARITY( args, ARITY, title_ );
2243 RefCountPtr< const Lang::Value > arg1 = args.getValue( 0 );
2244 RefCountPtr< const Lang::Value > arg2 = args.getValue( 1 );
2248 Kernel::ContRef cont = evalState->cont_;
2249 cont->takeValue( arg1->binaryDispatch1( arg1, arg2, evalState->dyn_, opExpr_ ),
2250 evalState );
2252 catch( Exceptions::BinaryInfixNotApplicable & ball )
2254 ball.setOperatorSymbol( title_ );
2255 throw;
2259 bool
2260 Lang::BinaryOperatorFunction::isTransforming( ) const
2262 return false;
2265 void
2266 Lang::BinaryOperatorFunction::show( std::ostream & os ) const
2268 os << "< binary operator function for " << title_ << " >" ;
2272 Lang::UnaryOperatorFunction::UnaryOperatorFunction( Ast::UnaryExpr * opExpr, const char * title )
2273 : Lang::Function( new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title ), true ) ), opExpr_( opExpr ), title_( title )
2275 formals_->appendEvaluatedCoreFormal( "only", Kernel::THE_SLOT_VARIABLE );
2278 Lang::UnaryOperatorFunction::~UnaryOperatorFunction( )
2280 delete opExpr_;
2283 void
2284 Lang::UnaryOperatorFunction::call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
2286 const size_t ARITY = 1;
2287 CHECK_ARITY( args, ARITY, title_ );
2289 RefCountPtr< const Lang::Value > arg = args.getValue( 0 );
2293 Kernel::ContRef cont = evalState->cont_;
2294 cont->takeValue( arg->unaryDispatch( arg, evalState->dyn_, opExpr_ ),
2295 evalState );
2297 catch( Exceptions::UnaryPrefixNotApplicable & ball )
2299 ball.setOperatorSymbol( title_ );
2300 throw;
2302 catch( Exceptions::UnaryPostfixNotApplicable & ball )
2304 ball.setOperatorSymbol( title_ );
2305 throw;
2309 bool
2310 Lang::UnaryOperatorFunction::isTransforming( ) const
2312 return false;
2315 void
2316 Lang::UnaryOperatorFunction::show( std::ostream & os ) const
2318 os << "< unary operator function for " << title_ << " >" ;
2322 Lang::Transform2DMethod_chop::Transform2DMethod_chop( RefCountPtr< const Lang::Transform2D > self, const Ast::FileID * fullMethodID )
2323 : Lang::MethodBase< class_type >( self, fullMethodID, false, true )
2325 formals_->appendEvaluatedCoreFormal( "L", Kernel::THE_SLOT_VARIABLE );
2326 formals_->appendEvaluatedCoreFormal( "p", Kernel::THE_SLOT_VARIABLE );
2329 Lang::Transform2DMethod_chop::~Transform2DMethod_chop( )
2332 void
2333 Lang::Transform2DMethod_chop::call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
2335 args.applyDefaults( );
2337 size_t argsi = 0;
2338 double Ltol = Helpers::down_cast_CoreArgument< const Lang::Float >( title_, args, argsi, callLoc )->val_;
2339 if( Ltol < 0 )
2341 throw Exceptions::CoreOutOfRange( title_, args, argsi, "Tolerances must not be negative." );
2344 ++argsi;
2345 Concrete::Length ptol = Helpers::down_cast_CoreArgument< const Lang::Length >( title_, args, argsi, callLoc )->get( );
2346 if( ptol < Concrete::ZERO_LENGTH )
2348 throw Exceptions::CoreOutOfRange( title_, args, argsi, "Tolerances must not be negative." );
2351 Lang::Transform2D * res = self_->clone( );
2353 CHOP_Ltol( res->xx_ );
2354 CHOP_Ltol( res->yx_ );
2356 CHOP_Ltol( res->xy_ );
2357 CHOP_Ltol( res->yy_ );
2359 CHOP_ptol( res->xt_ );
2360 CHOP_ptol( res->yt_ );
2362 Kernel::ContRef cont = evalState->cont_;
2363 cont->takeValue( RefCountPtr< const Lang::Value >( res ),
2364 evalState );
2368 Lang::Transform3DMethod_chop::Transform3DMethod_chop( RefCountPtr< const Lang::Transform3D > self, const Ast::FileID * fullMethodID )
2369 : Lang::MethodBase< class_type >( self, fullMethodID, false, true )
2371 formals_->appendEvaluatedCoreFormal( "L", Kernel::THE_SLOT_VARIABLE );
2372 formals_->appendEvaluatedCoreFormal( "p", Kernel::THE_SLOT_VARIABLE );
2375 Lang::Transform3DMethod_chop::~Transform3DMethod_chop( )
2378 void
2379 Lang::Transform3DMethod_chop::call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
2381 args.applyDefaults( );
2383 size_t argsi = 0;
2384 double Ltol = Helpers::down_cast_CoreArgument< const Lang::Float >( title_, args, argsi, callLoc )->val_;
2385 if( Ltol < 0 )
2387 throw Exceptions::CoreOutOfRange( title_, args, argsi, "Tolerances must not be negative." );
2390 ++argsi;
2391 Concrete::Length ptol = Helpers::down_cast_CoreArgument< const Lang::Length >( title_, args, argsi, callLoc )->get( );
2392 if( ptol < Concrete::ZERO_LENGTH )
2394 throw Exceptions::CoreOutOfRange( title_, args, argsi, "Tolerances must not be negative." );
2397 Lang::Transform3D * res = self_->clone( );
2399 CHOP_Ltol( res->xx_ );
2400 CHOP_Ltol( res->yx_ );
2401 CHOP_Ltol( res->zx_ );
2403 CHOP_Ltol( res->xy_ );
2404 CHOP_Ltol( res->yy_ );
2405 CHOP_Ltol( res->zy_ );
2407 CHOP_Ltol( res->xz_ );
2408 CHOP_Ltol( res->yz_ );
2409 CHOP_Ltol( res->zz_ );
2411 CHOP_ptol( res->xt_ );
2412 CHOP_ptol( res->yt_ );
2413 CHOP_ptol( res->zt_ );
2415 Kernel::ContRef cont = evalState->cont_;
2416 cont->takeValue( RefCountPtr< const Lang::Value >( res ),
2417 evalState );