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
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
21 #include "shapestypes.h"
22 #include "shapesexceptions.h"
25 #include "angleselect.h"
29 #include "continuations.h"
30 #include "methodbase.h"
33 //#include "clapack.h"
35 #include <gsl/gsl_matrix.h>
36 #include <gsl/gsl_linalg.h>
37 #include <gsl/gsl_blas.h>
42 #define CHOP_Ltol( x )\
43 if( fabs( x ) < Ltol )\
47 else if( fabs( x - 1 ) < Ltol )\
51 else if( fabs( x + 1 ) < Ltol )\
56 #define CHOP_ptol( x )\
57 if( x.abs( ) < ptol )\
59 x = Concrete::ZERO_LENGTH;\
62 using namespace Shapes
;
65 void displayArray( std::ostream
& os
, const double * pr
, size_t m
, size_t n
)
70 for( r
= 0; r
< m
; ++r
)
72 for( c
= 0; c
< n
; ++c
)
74 sprintf( buf
, "%14.5e", *( pr
+ ( r
+ c
* m
) ) );
81 void displayArray( std::ostream
& os
, const gsl_matrix
* m
)
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
) );
101 class Transform2DMethod_chop
: public Lang::MethodBase
< Lang::Transform2D
>
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
>
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"; }
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
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
);
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. */
218 Lang::Transform2D::clone( ) const
220 return new Transform2D( xx_
, yx_
,
226 Lang::Transform2D::isIdentity( ) const
229 xt_
== Concrete::ZERO_LENGTH
&& yt_
== Concrete::ZERO_LENGTH
&&
230 xx_
== 1 && yy_
== 1 &&
231 xy_
== 0 && yx_
== 0;
235 Lang::Transform2D::isTranslation( ) const
238 xx_
== 1 && yy_
== 1 &&
239 xy_
== 0 && yx_
== 0;
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_
);
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_
) );
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
267 Lang::Transform2D::replaceBy( const Lang::Transform2D
& newtf
)
277 // to be used by text newline commands
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
289 Lang::Transform2D::prependXShift( const Concrete::Length
& dx
)
291 // Think of d as tf1 when composing transforms.
298 Lang::Transform2D::show( std::ostream
& os
) const
301 << xx_
<< ", " << yx_
<< ") ("
302 << xy_
<< ", " << yy_
<< ") ("
303 << Lang::Length( xt_
) << ", " << Lang::Length( yt_
) << ") ]" ;
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
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
);
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. */
435 Lang::Transform3D::clone( ) const
437 return new Transform3D( xx_
, yx_
, zx_
,
444 Lang::Transform3D::isIdentity( ) const
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;
453 Lang::Transform3D::isTranslation( ) const
456 xx_
== 1 && yy_
== 1 && zz_
== 1 &&
457 xy_
== 0 && xz_
== 0 &&
458 yx_
== 0 && yz_
== 0 &&
459 zx_
== 0 && zy_
== 0;
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_
);
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
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;
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.
518 // dgesvd_( & jobuvt, & jobuvt,
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,
526 // lwork = static_cast< __CLPK_integer >( tmpwork );
527 // work = new __CLPK_doublereal[ lwork ];
528 // workCleaner = RefCountPtr< __CLPK_doublereal >( work );
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
);
549 throw Exceptions::ExternalError( "Gnu Scientific Library SVD routine failed." );
563 // dgesvd_( & jobuvt, & jobuvt,
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,
574 // throw Exceptions::ExternalError( "LAPACK routine DGESVD failed." );
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 ) );
589 // std::cerr << "Here's the modified s:" << std::endl ;
590 // gsl_vector_fprintf( stderr, s, "%f" );
593 // if( s[ 1 ] < 1e-5 )
595 // throw Exceptions::AffineTransformKillsPlane( s[ 1 ] );
598 // s[ 0 ] = s[ 2 ] / s[ 0 ];
599 // s[ 1 ] = s[ 2 ] / s[ 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
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
,
637 planeNormalTransformData_
);
639 // std::cerr << "Here's the matrix:" << std::endl ;
640 // displayArray( std::cerr, planeNormalTransformData_ );
642 // cblas_dgemm( CblasColMajor, CblasNoTrans, CblasNoTrans,
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_
);
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_
,
678 // std::cerr << "Result: " << std::endl ;
679 // gsl_vector_fprintf( stderr, res, "%f" );
680 // std::cerr << std::endl ;
682 // cblas_dgemv( CblasColMajor, CblasNoTrans,
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( );
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 );
723 x0 = Concrete::Coords3D( 0, m_ / unitNormal_.y_, 0 );
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.
747 Concrete::UnitFloatTriple TunitNormal = Tnormal * ( 1 / TnormalNorm );
752 Lang::Transform3D::show( std::ostream
& os
) const
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 ),
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.
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( )
790 Kernel::Arguments::clone( ) const
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_
;
811 if( sinkArgList_
!= 0 )
813 throw Exceptions::NotImplemented( "Cloning of arguments with sink." );
814 //res.sinkArgList_ = sinkArgList_->clone( );
815 res
.sinkValues_
= sinkValues_
;
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.
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.
836 sinkArgList_
->orderedExprs_
->push_back( loc
);
837 sinkValues_
= RefCountPtr
< Lang::SingleList
>( new Lang::SingleListPair( arg
, sinkValues_
) );
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
);
854 (*variables_
)[ dst_
] = arg
;
855 locations_
[ dst_
] = loc
;
856 while( dst_
< variables_
->size( ) &&
857 (*variables_
)[ dst_
] != Kernel::THE_SLOT_VARIABLE
)
865 Kernel::Arguments::addNamedArgument( const char * id
, const Kernel::VariableHandle
& arg
, Ast::Expression
* loc
)
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( ) ||
881 j
->second
== dstEnd_
) )
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_
) );
893 throw Exceptions::NamedFormalMismatch( formals_
->formals_
->loc( ), strrefdup( id
), Exceptions::NamedFormalMismatch::VARIABLE
);
895 size_t pos
= j
->second
;
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
);
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
;
923 while( dst_
< variables_
->size( ) &&
924 (*variables_
)[ dst_
] != Kernel::THE_SLOT_VARIABLE
)
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
);
942 (*states_
)[ stateDst_
] = state
;
943 stateLocations_
[ stateDst_
] = loc
;
944 while( stateDst_
< states_
->size( ) &&
945 (*states_
)[ stateDst_
] != Kernel::THE_SLOT_STATE
)
953 Kernel::Arguments::addNamedState( const char * id
, const Kernel::StateHandle
& state
, Ast::Node
* loc
)
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
);
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
)
1005 Kernel::Arguments::applyDefaults( )
1012 size_t numberOfArguments
= variables_
->size( );
1013 size_t formalsSize
= formals_
->defaults_
.size( );
1015 if( numberOfArguments
> formalsSize
&&
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;
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
) ) );
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
)
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;
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
) ) );
1124 if( i
== formalsMap
.end( ) )
1126 throw Exceptions::InternalError( "Failed to find position of missing argument." );
1134 locations_
[ pos
] = *srcLoc
;
1138 if( missingArgs
!= 0 || missingStates
!= 0 )
1140 throw Exceptions::MissingArguments( formals_
->formals_
->loc( ), missingArgs
, missingStates
);
1145 variables_
->push_back
1146 ( Helpers::newValHandle
1147 ( new Lang::Structure( sinkArgList_
,
1149 true ) ) ); // true means that the sinkArgList_ gets owned by the Structure.
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( );
1174 Kernel::Arguments::getNode( size_t i
) const
1176 return locations_
[ i
];
1180 Kernel::Arguments::getThunk( size_t i
)
1182 return (*variables_
)[ i
]->copyThunk( );
1186 Kernel::Arguments::isSlot( size_t i
) const
1188 return (*variables_
)[ i
] == Kernel::THE_SLOT_VARIABLE
;
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( );
1204 Kernel::Arguments::size( ) const
1206 return variables_
->size( );
1210 Kernel::Arguments::empty( ) const
1212 return variables_
->empty( );
1216 Kernel::Arguments::setMutatorSelf( Kernel::StateHandle mutatorSelf
)
1218 mutatorSelf_
= mutatorSelf
;
1222 Kernel::Arguments::getMutatorSelf( )
1224 if( mutatorSelf_
== 0 )
1226 throw Exceptions::InternalError( "Kernel::Arguments::getMutatorSelf: self is null." );
1228 return mutatorSelf_
;
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( )
1249 Kernel::Environment::StateVector
1250 Kernel::Arguments::getStates( )
1261 class FunctionOneHandleCont
: public Kernel::Continuation
1263 RefCountPtr
< const Lang::Function
> fun_
;
1264 Kernel::PassedDyn dyn_
;
1265 Kernel::ContRef cont_
;
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
);
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
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_
;
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
);
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
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_
;
1357 Kernel::PassedDyn dyn_
;
1358 Kernel::ContRef cont_
;
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
);
1378 Kernel::ContRef newCont
= Kernel::ContRef( new Kernel::FunctionTwoHandlesCont_2( fun_
, arg1
, dyn_
, cont_
, traceLoc_
) );
1379 evalState
->cont_
= newCont
;
1380 newCont
->takeHandle( arg2_
, evalState
);
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
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_
;
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
);
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
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_
;
1463 Kernel::StateHandle state_
;
1464 Kernel::PassedDyn dyn_
;
1465 Kernel::ContRef cont_
;
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
);
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
);
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
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( )
1532 delete formals_
->formals_
;
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
>( ) ) );
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
);
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" ) );
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." );
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 ) );
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
) );
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
) );
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
) ) );
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
) ) );
1745 return RefCountPtr
< Kernel::CallContInfo
>( new Kernel::CallContInfo( argList
, evalState
, forceAll_
) );
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
);
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
);
1776 Kernel::EvaluatedFormals::appendEvaluatedCoreFormal( const char * id
, const Kernel::VariableHandle
& defaultVal
, bool force
)
1778 appendEvaluatedFormal( id
, defaultVal
, & Ast::THE_CORE_DEFAULT_VALUE_EXPRESSION
, force
);
1782 Kernel::EvaluatedFormals::appendEvaluatedCoreFormal( const char * id
, const Kernel::VariableHandle
& defaultVal
)
1784 appendEvaluatedFormal( id
, defaultVal
, & Ast::THE_CORE_DEFAULT_VALUE_EXPRESSION
);
1788 Kernel::EvaluatedFormals::appendCoreStateFormal( const char * id
)
1790 (*(formals_
->stateOrder_
))[ id
] = formals_
->stateOrder_
->size( );
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
);
1830 Lang::CuteFunction::newCurriedArguments( ) const
1832 return someArgs_
.clone( );
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
);
1845 Lang::CuteFunction::isTransforming( ) const
1847 return callee_
->isTransforming( );
1851 Lang::CuteFunction::gcMark( Kernel::GCMarkedSet
& marked
)
1853 const_cast< Lang::Function
* >( callee_
.getPtr( ) )->gcMark( marked
);
1854 someArgs_
.gcMark( marked
);
1858 Lang::CuteFunction::show( std::ostream
& os
) const
1860 os
<< "< evaluated cut of: " ;
1861 callee_
->show( 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( )
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
);
1896 Lang::ComposedFunction::newCurriedArguments( ) const
1898 return first_
->newCurriedArguments( );
1902 Lang::ComposedFunction::isTransforming( ) const
1904 return second_
->isTransforming( );
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
);
1915 Lang::ComposedFunction::show( std::ostream
& os
) const
1917 os
<< "< composition: " ;
1918 second_
->show( 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
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_
;
1951 Lang::UserFunction::isTransforming( ) const
1953 return ( functionMode_
& Ast::FUNCTION_TRANSFORMING
) != 0;
1957 Lang::UserFunction::gcMark( Kernel::GCMarkedSet
& marked
)
1959 env_
->gcMark( marked
);
1963 Lang::UserFunction::body( )
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( )
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
);
1990 Lang::TransformedFunction2D::isTransforming( ) const
1992 return fun_
->isTransforming( );
1996 Lang::TransformedFunction2D::gcMark( Kernel::GCMarkedSet
& marked
)
1998 const_cast< Lang::Function
* >( fun_
.getPtr( ) )->gcMark( marked
);
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>";
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
);
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_
],
2061 Lang::VectorFunction::isTransforming( ) const
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
);
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_
);
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
>
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( ) ) ),
2145 if( keyHi
== key_
->begin( ) )
2147 Kernel::ContRef cont
= evalState
->cont_
;
2148 cont
->takeValue( RefCountPtr
< const::Lang::Value
>( new COLOR_TYPE( colorContainer
->front( ) ) ),
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
) ) ) ),
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_
)
2182 callHelper
< Lang::RGB
>( evalState
, RGBcolor_
, key
, keyHi
);
2185 callHelper
< Lang::Gray
>( evalState
, graycolor_
, key
, keyHi
);
2188 callHelper
< Lang::CMYK
>( evalState
, CMYKcolor_
, key
, keyHi
);
2191 throw Exceptions::InternalError( "ColorInterpolator::call: Did not expect UNDEFINED in ennum switch." );
2196 Lang::ColorInterpolator::isTransforming( ) const
2202 Lang::ColorInterpolator::gcMark( Kernel::GCMarkedSet
& marked
)
2206 Lang::ColorInterpolator::show( std::ostream
& os
) const
2208 os
<< "< color interpolator in " ;
2209 switch( colorType_
)
2221 throw Exceptions::InternalError( "ColorInterpolator::show: Did not expect UNDEFINED in ennum switch." );
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( )
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_
),
2252 catch( Exceptions::BinaryInfixNotApplicable
& ball
)
2254 ball
.setOperatorSymbol( title_
);
2260 Lang::BinaryOperatorFunction::isTransforming( ) const
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( )
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_
),
2297 catch( Exceptions::UnaryPrefixNotApplicable
& ball
)
2299 ball
.setOperatorSymbol( title_
);
2302 catch( Exceptions::UnaryPostfixNotApplicable
& ball
)
2304 ball
.setOperatorSymbol( title_
);
2310 Lang::UnaryOperatorFunction::isTransforming( ) const
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( )
2333 Lang::Transform2DMethod_chop::call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
2335 args
.applyDefaults( );
2338 double Ltol
= Helpers::down_cast_CoreArgument
< const Lang::Float
>( title_
, args
, argsi
, callLoc
)->val_
;
2341 throw Exceptions::CoreOutOfRange( title_
, args
, argsi
, "Tolerances must not be negative." );
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
),
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( )
2379 Lang::Transform3DMethod_chop::call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
2381 args
.applyDefaults( );
2384 double Ltol
= Helpers::down_cast_CoreArgument
< const Lang::Float
>( title_
, args
, argsi
, callLoc
)->val_
;
2387 throw Exceptions::CoreOutOfRange( title_
, args
, argsi
, "Tolerances must not be negative." );
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
),