ammend merge: now compiles
[shapes.git] / source / coreconstruct.cc
blobfcb49fb913aea2f6387e604eb620c156e6ea7495
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, 2009, 2010, 2013, 2014 Henrik Tidefelt
19 #include <cmath>
21 #include "Shapes_Helpers_decls.h"
23 #include "coreconstruct_impl.h"
24 #include "singlelistrange.h"
25 #include "shapescore.h"
26 #include "globals.h"
27 #include "shapesexceptions.h"
28 #include "consts.h"
29 #include "simplepdfi.h"
30 #include "simplepdfo.h"
31 #include "astfun.h"
32 #include "tagtypes.h"
33 #include "multipage.h"
34 #include "charconverters.h"
35 #include "pagecontentstates.h"
36 #include "texlabelmanager.h"
37 #include "autoonoff.h"
38 #include "timetypes.h"
39 #include "graphtypes.h"
40 #include "shapesscanner.h"
41 #include "rasterloaders.h"
42 #include "glyphlist.h"
43 #include "warn.h"
44 #include "config.h"
46 #ifdef HAVE_FT2
47 #include <ft2build.h>
48 #include FT_FREETYPE_H
49 #endif
50 #ifdef HAVE_FONTCONFIG
51 #include <fontconfig/fontconfig.h>
52 #endif
54 #include <iostream>
55 #include <sstream>
56 #include <fstream>
57 #include <vector>
58 #include <stdio.h>
59 #include <ctime>
61 using namespace Shapes;
64 namespace Shapes
66 namespace Helpers
68 RasterLoader_PNG theRasterLoader_PNG;
69 RasterLoader_JPEG theRasterLoader_JPEG;
70 #ifdef HAVE_FONTCONFIG
71 class AutoDestroyFcPattern
73 FcPattern * pat_;
74 public:
75 AutoDestroyFcPattern( FcPattern * pat )
76 : pat_( pat )
77 { }
78 ~AutoDestroyFcPattern( )
80 if( pat_ != 0 )
82 FcPatternDestroy( pat_ );
85 void deactivate( )
87 pat_ = 0;
90 class AutoDestroyFcFontSet
92 FcFontSet * set_;
93 public:
94 AutoDestroyFcFontSet( FcFontSet * set )
95 : set_( set )
96 { }
97 ~AutoDestroyFcFontSet( )
99 if( set_ != 0 )
101 FcFontSetDestroy( set_ );
104 void deactivate( )
106 set_ = 0;
109 #endif
112 namespace Lang
115 class Core_tag : public Lang::CoreFunction
117 public:
118 Core_tag( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name )
119 : CoreFunction( ns, name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), true ) )
121 formals_->appendEvaluatedCoreFormal( "key", Kernel::THE_SLOT_VARIABLE );
122 formals_->appendEvaluatedCoreFormal( "obj", Kernel::THE_SLOT_VARIABLE );
123 formals_->appendEvaluatedCoreFormal( "transform", Kernel::THE_TRUE_VARIABLE ); /* this argument means "transform if applicable" */
124 formals_->appendEvaluatedCoreFormal( "draw", Kernel::THE_TRUE_VARIABLE ); /* this argument means "draw if applicable" */
127 virtual void
128 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
130 args.applyDefaults( callLoc );
132 typedef const Lang::Symbol KeyType;
133 RefCountPtr< KeyType > key = Helpers::down_cast_CoreArgument< KeyType >( id_, args, 0, callLoc );
134 bool tryTransform = Helpers::down_cast_CoreArgument< const Lang::Boolean >( id_, args, 2, callLoc )->val_;
135 bool tryDraw = Helpers::down_cast_CoreArgument< const Lang::Boolean >( id_, args, 3, callLoc )->val_;
137 if( tryDraw && ! tryTransform )
139 throw Exceptions::CoreOutOfRange( id_, args, 3, "A tagged object which does not transform cannot be drawn." );
142 size_t argsi = 1;
144 if( tryDraw )
148 typedef const Lang::Drawable2D ArgType;
150 RefCountPtr< ArgType > obj = Helpers::try_cast_CoreArgument< ArgType >( args.getValue( argsi ) );
152 Kernel::ContRef cont = evalState->cont_;
153 cont->takeValue( RefCountPtr< const Lang::Value >( new Lang::TaggedDrawable2D( key, obj ) ),
154 evalState );
155 return;
157 catch( const NonLocalExit::NotThisType & ball )
159 /* Never mind, see below. */
164 typedef const Lang::Drawable3D ArgType;
166 RefCountPtr< ArgType > obj = Helpers::try_cast_CoreArgument< ArgType >( args.getValue( argsi ) );
168 Kernel::ContRef cont = evalState->cont_;
169 cont->takeValue( RefCountPtr< const Lang::Value >( new Lang::TaggedDrawable3D( key, obj ) ),
170 evalState );
171 return;
173 catch( const NonLocalExit::NotThisType & ball )
175 /* Never mind, see below. */
179 if( tryTransform )
183 typedef const Lang::Geometric2D ArgType;
185 RefCountPtr< ArgType > obj = Helpers::try_cast_CoreArgument< ArgType >( args.getValue( argsi ) );
187 Kernel::ContRef cont = evalState->cont_;
188 cont->takeValue( RefCountPtr< const Lang::Value >( new Lang::TaggedGeometric2D( key, obj ) ),
189 evalState );
190 return;
192 catch( const NonLocalExit::NotThisType & ball )
194 /* Never mind, see below. */
199 typedef const Lang::Geometric3D ArgType;
201 RefCountPtr< ArgType > obj = Helpers::try_cast_CoreArgument< ArgType >( args.getValue( argsi ) );
203 Kernel::ContRef cont = evalState->cont_;
204 cont->takeValue( RefCountPtr< const Lang::Value >( new Lang::TaggedGeometric3D( key, obj ) ),
205 evalState );
206 return;
208 catch( const NonLocalExit::NotThisType & ball )
210 /* Never mind, see below. */
215 // As a last resort, we tag any value.
216 // We return a Drawable2D. Use immerse to make it 3D.
217 Kernel::ContRef cont = evalState->cont_;
218 cont->takeValue( RefCountPtr< const Lang::Value >( new Lang::TaggedValue2D( key, args.getValue( argsi ) ) ),
219 evalState );
224 // This function is in this file just because it i so related to Core_tag.
225 class Core_find : public Lang::CoreFunction
227 public:
228 Core_find( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name )
229 : CoreFunction( ns, name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), true ) )
231 formals_->appendEvaluatedCoreFormal( "container", Kernel::THE_SLOT_VARIABLE );
232 formals_->appendEvaluatedCoreFormal( "key", Kernel::THE_SLOT_VARIABLE );
235 virtual void
236 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
238 args.applyDefaults( callLoc );
240 typedef const Lang::Symbol KeyType;
241 RefCountPtr< KeyType > key = Helpers::down_cast_CoreArgument< KeyType >( id_, args, 1, callLoc );
243 size_t argsi = 0;
247 typedef const Lang::Drawable2D ContainerType;
249 RefCountPtr< ContainerType > container = Helpers::try_cast_CoreArgument< ContainerType >( args.getValue( argsi ) );
251 if( ! container->findOneTag( evalState, key->getKey( ), Lang::THE_2D_IDENTITY ) )
253 throw Exceptions::CoreOutOfRange( id_, args, 1, "Key not found." );
255 return;
257 catch( const NonLocalExit::NotThisType & ball )
259 /* Never mind, see below. */
264 typedef const Lang::Drawable3D ContainerType;
266 RefCountPtr< ContainerType > container = Helpers::try_cast_CoreArgument< ContainerType >( args.getValue( argsi ) );
268 if( ! container->findOneTag( evalState, key->getKey( ), Lang::THE_3D_IDENTITY ) )
270 throw Exceptions::CoreOutOfRange( id_, args, 1, "Key not found." );
272 return;
274 catch( const NonLocalExit::NotThisType & ball )
276 /* Never mind, see below. */
279 throw Exceptions::CoreTypeMismatch( callLoc, id_, args, argsi, Helpers::typeSetString( Lang::Drawable2D::staticTypeName( ), Lang::Drawable3D::staticTypeName( ) ) );
283 // This function is in this file just because it i so related to Core_tag.
284 class Core_findall : public Lang::CoreFunction
286 public:
287 Core_findall( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name )
288 : CoreFunction( ns, name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), true ) )
290 formals_->appendEvaluatedCoreFormal( "container", Kernel::THE_SLOT_VARIABLE );
291 formals_->appendEvaluatedCoreFormal( "key", Kernel::THE_SLOT_VARIABLE );
294 virtual void
295 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
297 args.applyDefaults( callLoc );
299 typedef const Lang::Symbol KeyType;
300 RefCountPtr< KeyType > key = Helpers::down_cast_CoreArgument< KeyType >( id_, args, 1, callLoc );
302 size_t argsi = 0;
306 typedef const Lang::Drawable2D ContainerType;
308 RefCountPtr< ContainerType > container = Helpers::try_cast_CoreArgument< ContainerType >( args.getValue( argsi ) );
310 std::vector< Kernel::ValueRef > * dst = new std::vector< Kernel::ValueRef >;
311 container->findTags( dst, evalState->dyn_, key->getKey( ), Lang::THE_2D_IDENTITY );
313 Kernel::ContRef cont = evalState->cont_;
314 cont->takeValue( RefCountPtr< const Lang::Value >( new Lang::VectorFunction( dst ) ),
315 evalState );
316 return;
318 catch( const NonLocalExit::NotThisType & ball )
320 /* Never mind, see below. */
325 typedef const Lang::Drawable3D ContainerType;
327 RefCountPtr< ContainerType > container = Helpers::try_cast_CoreArgument< ContainerType >( args.getValue( argsi ) );
329 std::vector< Kernel::ValueRef > * dst = new std::vector< Kernel::ValueRef >;
330 container->findTags( dst, evalState->dyn_, key->getKey( ), Lang::THE_3D_IDENTITY );
332 Kernel::ContRef cont = evalState->cont_;
333 cont->takeValue( RefCountPtr< const Lang::Value >( new Lang::VectorFunction( dst ) ),
334 evalState );
335 return;
337 catch( const NonLocalExit::NotThisType & ball )
339 /* Never mind, see below. */
342 throw Exceptions::CoreTypeMismatch( callLoc, id_, args, argsi, Helpers::typeSetString( Lang::Drawable2D::staticTypeName( ), Lang::Drawable3D::staticTypeName( ) ) );
346 class Core_phong : public Lang::CoreFunction
348 public:
349 Core_phong( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name ) : CoreFunction( ns, name ) { }
350 virtual void
351 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
353 const size_t ARITY = 1;
354 CHECK_ARITY( args, ARITY, id_ );
356 typedef const Lang::Float ArgType;
357 double exponent = Helpers::down_cast_CoreArgument< ArgType >( id_, args, 0, callLoc )->val_;
358 if( exponent < 0 )
360 throw Exceptions::CoreOutOfRange( id_, args, 0, "The Phong exponent should be greater than 0." );
363 Kernel::ContRef cont = evalState->cont_;
364 cont->takeValue( Kernel::ValueRef( new Lang::SpecularReflectionTerm( 1., exponent ) ),
365 evalState );
369 class Core_cons : public Lang::CoreFunction
371 public:
372 Core_cons( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name )
373 : CoreFunction( ns, name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), false ) )
375 formals_->appendEvaluatedCoreFormal( "car", Kernel::THE_SLOT_VARIABLE );
376 formals_->appendEvaluatedCoreFormal( "cdr", Kernel::THE_SLOT_VARIABLE );
378 virtual void
379 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
381 const size_t ARITY = 2;
382 CHECK_ARITY( args, ARITY, id_ );
384 Kernel::VariableHandle cdr = args.getHandle( 1 );
385 if( ! cdr->isThunk( ) ){
386 RefCountPtr< const Lang::Value > cdrVal = cdr->getUntyped( );
387 RefCountPtr< const Lang::SingleList > cdrValTyped = cdrVal.down_cast< const Lang::SingleList >( );
388 if( cdrValTyped != NullPtr< const Lang::SingleList >( ) ){
389 Kernel::ContRef cont = evalState->cont_;
390 cont->takeValue( Kernel::ValueRef( new Lang::SingleListPair( args.getHandle( 0 ),
391 cdrValTyped ) ),
392 evalState );
393 return;
397 Kernel::ContRef cont = evalState->cont_;
398 cont->takeValue( Kernel::ValueRef( new Lang::ConsPair( args.getHandle( 0 ),
399 cdr ) ),
400 evalState );
404 class Core_list : public Lang::CoreFunction
406 public:
407 Core_list( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name ) : CoreFunction( ns, name ) { }
408 virtual void
409 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
411 RefCountPtr< const Lang::SingleList > res = Lang::THE_CONS_NULL;
412 if( ! args.empty( ) )
414 for( size_t i = args.size( ) - 1; ; --i )
416 res = RefCountPtr< const Lang::SingleList >( new Lang::SingleListPair( args.getHandle( i ), res ) );
417 if( i == 0 )
419 break;
424 Kernel::ContRef cont = evalState->cont_;
425 cont->takeValue( res,
426 evalState );
430 class Core_unlist : public Lang::CoreFunction
432 Kernel::UnnamedStructureFactory argListFactory_;
433 public:
434 Core_unlist( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name ) : CoreFunction( ns, name ) { }
435 virtual void
436 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
438 const size_t ARITY = 1;
439 CHECK_ARITY( args, ARITY, id_ );
441 typedef const Lang::SingleList ArgType;
443 Kernel::ContRef cont = evalState->cont_;
444 cont->takeValue( argListFactory_.build( Helpers::down_cast_CoreArgument< ArgType >( id_, args, 0, callLoc ) ),
445 evalState );
449 class Core_isnil : public Lang::CoreFunction
451 public:
452 Core_isnil( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name ) : CoreFunction( ns, name ) { }
453 virtual void
454 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
456 const size_t ARITY = 1;
457 CHECK_ARITY( args, ARITY, id_ );
459 RefCountPtr< const Lang::Value > aUntyped = args.getValue( 0 );
461 Kernel::ContRef cont = evalState->cont_;
462 cont->takeValue( RefCountPtr< const Lang::Value >( new Lang::Boolean( dynamic_cast< const Lang::SingleListNull * >( args.getValue( 0 ).getPtr( ) ) != 0 ) ),
463 evalState );
467 class Core_span : public Lang::CoreFunction
469 public:
470 Core_span( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name )
471 : CoreFunction( ns, name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), false ) )
473 formals_->appendEvaluatedCoreFormal( "begin", Kernel::THE_VOID_VARIABLE );
474 formals_->appendEvaluatedCoreFormal( "end", Kernel::THE_VOID_VARIABLE );
475 formals_->appendEvaluatedCoreFormal( "step", Kernel::THE_VOID_VARIABLE );
476 formals_->appendEvaluatedCoreFormal( "count", Kernel::THE_VOID_VARIABLE );
478 virtual void
479 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
481 args.applyDefaults( callLoc );
483 Kernel::ContRef cont = evalState->cont_;
484 cont->takeValue( Kernel::ValueRef( new Lang::Span( args.getHandle( 0 ), args.getHandle( 1 ), args.getHandle( 2 ), args.getHandle( 3 ) ) ),
485 evalState );
489 class Core_affinetransform : public Lang::CoreFunction
491 public:
492 Core_affinetransform( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name ) : CoreFunction( ns, name ) { }
493 virtual void
494 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
496 const size_t ARITY = 3;
497 CHECK_ARITY( args, ARITY, id_ );
499 typedef const Lang::FloatPair ArgType0;
500 typedef const Lang::FloatPair ArgType1;
501 typedef const Lang::Coords2D ArgType2;
503 RefCountPtr< ArgType0 > argx = Helpers::down_cast_CoreArgument< ArgType0 >( id_, args, 0, callLoc );
504 RefCountPtr< ArgType1 > argy = Helpers::down_cast_CoreArgument< ArgType1 >( id_, args, 1, callLoc );
505 RefCountPtr< ArgType2 > arg1 = Helpers::down_cast_CoreArgument< ArgType2 >( id_, args, 2, callLoc );
507 Kernel::ContRef cont = evalState->cont_;
508 cont->takeValue( Kernel::ValueRef( new Lang::Transform2D( argx->x_, argx->y_, argy->x_, argy->y_, arg1->x_.get( ), arg1->y_.get( ) ) ),
509 evalState );
513 class Core_affinetransform3d : public Lang::CoreFunction
515 public:
516 Core_affinetransform3d( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name ) : CoreFunction( ns, name ) { }
517 virtual void
518 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
520 const size_t ARITY = 4;
521 CHECK_ARITY( args, ARITY, id_ );
523 typedef const Lang::FloatTriple ArgType0;
524 typedef const Lang::FloatTriple ArgType1;
525 typedef const Lang::FloatTriple ArgType2;
526 typedef const Lang::Coords3D ArgType3;
528 RefCountPtr< ArgType0 > argx = Helpers::down_cast_CoreArgument< ArgType0 >( id_, args, 0, callLoc );
529 RefCountPtr< ArgType1 > argy = Helpers::down_cast_CoreArgument< ArgType1 >( id_, args, 1, callLoc );
530 RefCountPtr< ArgType2 > argz = Helpers::down_cast_CoreArgument< ArgType2 >( id_, args, 2, callLoc );
531 RefCountPtr< ArgType3 > arg1 = Helpers::down_cast_CoreArgument< ArgType3 >( id_, args, 3, callLoc );
533 Kernel::ContRef cont = evalState->cont_;
534 cont->takeValue( Kernel::ValueRef( new Lang::Transform3D( argx->x_, argx->y_, argx->z_,
535 argy->x_, argy->y_, argy->z_,
536 argz->x_, argz->y_, argz->z_,
537 arg1->x_.get( ), arg1->y_.get( ), arg1->z_.get( ) ) ),
538 evalState );
542 class Core_shift : public Lang::CoreFunction
544 public:
545 Core_shift( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name ) : CoreFunction( ns, name ) { }
546 virtual void
547 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
549 const size_t ARITY = 1;
550 CHECK_ARITY( args, ARITY, id_ );
552 Kernel::ContRef cont = evalState->cont_;
554 size_t i = 0;
556 typedef const Lang::Coords2D ArgType1;
557 RefCountPtr< ArgType1 > arg1 = Helpers::down_cast_CoreArgument< ArgType1 >( id_, args, i, callLoc );
558 cont->takeValue( Kernel::ValueRef( new Lang::Transform2D( 1, 0, 0, 1, arg1->x_.get( ), arg1->y_.get( ) ) ),
559 evalState );
563 class Core_shift3d : public Lang::CoreFunction
565 public:
566 Core_shift3d( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name ) : CoreFunction( ns, name ) { }
567 virtual void
568 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
570 const size_t ARITY = 1;
571 CHECK_ARITY( args, ARITY, id_ );
573 Kernel::ContRef cont = evalState->cont_;
575 size_t i = 0;
577 typedef const Lang::Coords3D ArgType1;
578 RefCountPtr< ArgType1 > arg1 = Helpers::down_cast_CoreArgument< ArgType1 >( id_, args, i, callLoc );
579 cont->takeValue( Kernel::ValueRef( new Lang::Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, arg1->x_.get( ), arg1->y_.get( ), arg1->z_.get( ) ) ),
580 evalState );
584 class Core_rotate : public Lang::CoreFunction
586 public:
587 Core_rotate( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name )
588 : CoreFunction( ns, name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), true ) )
590 formals_->appendEvaluatedCoreFormal( "angle", Kernel::THE_SLOT_VARIABLE );
592 virtual void
593 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
595 args.applyDefaults( callLoc );
597 size_t i = 0;
599 typedef const Lang::Float ArgType1;
600 RefCountPtr< ArgType1 > arg1 = Helpers::down_cast_CoreArgument< ArgType1 >( id_, args, i, callLoc );
602 double c = cos( arg1->val_ );
603 double s = sin( arg1->val_ );
604 Kernel::ContRef cont = evalState->cont_;
605 cont->takeValue( Kernel::ValueRef( new Lang::Transform2D( c, s, -s, c, 0, 0 ) ),
606 evalState );
610 class Core_rotate3d : public Lang::CoreFunction
612 public:
613 Core_rotate3d( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name )
614 : CoreFunction( ns, name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), true ) )
616 formals_->appendEvaluatedCoreFormal( "dir", Kernel::THE_SLOT_VARIABLE );
617 formals_->appendEvaluatedCoreFormal( "angle", Kernel::THE_SLOT_VARIABLE );
619 virtual void
620 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
622 args.applyDefaults( callLoc );
624 size_t i = 0;
626 typedef const Lang::FloatTriple ArgType1;
627 RefCountPtr< ArgType1 > dir = Helpers::down_cast_CoreArgument< ArgType1 >( id_, args, i, callLoc );
628 if( dir->x_ == 0 && dir->y_ == 0 && dir->z_ == 0 )
630 throw Exceptions::CoreOutOfRange( id_, args, i, "The rotation direction is degenerate, that is (0,0,0)." );
633 ++i;
635 typedef const Lang::Float ArgType2;
636 RefCountPtr< ArgType2 > angle = Helpers::down_cast_CoreArgument< ArgType2 >( id_, args, i, callLoc );
638 double r = sqrt( dir->x_ * dir->x_ + dir->y_ * dir->y_ + dir->z_ * dir->z_ );
639 double x = dir->x_ / r;
640 double y = dir->y_ / r;
641 double z = dir->z_ / r;
642 double x2 = x * x;
643 double y2 = y * y;
644 double z2 = z * z;
645 double c = cos( angle->val_ );
646 double s = sin( angle->val_ );
647 Kernel::ContRef cont = evalState->cont_;
648 cont->takeValue( Kernel::ValueRef( new Lang::Transform3D( x2+(y2+z2)*c, x*y*(1-c)+z*s, x*z*(1-c)-y*s,
649 x*y*(1-c)-z*s, y2+(x2+z2)*c, y*z*(1-c)+x*s,
650 x*z*(1-c)+y*s, y*z*(1-c)-x*s, z2+(x2+y2)*c,
651 0, 0, 0 ) ),
652 evalState );
656 class Core_scale : public Lang::CoreFunction
658 public:
659 Core_scale( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name )
660 : CoreFunction( ns, name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), true ) )
662 Kernel::VariableHandle one( new Kernel::Variable( RefCountPtr< const Lang::Value >( new Lang::Float( 1 ) ) ) );
664 formals_->appendEvaluatedCoreFormal( "r", one );
665 formals_->appendEvaluatedCoreFormal( "x", one );
666 formals_->appendEvaluatedCoreFormal( "y", one );
668 virtual void
669 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
671 args.applyDefaults( callLoc );
673 typedef const Lang::Float ArgType;
674 RefCountPtr< ArgType > argr = Helpers::down_cast_CoreArgument< ArgType >( id_, args, 0, callLoc );
675 RefCountPtr< ArgType > argx = Helpers::down_cast_CoreArgument< ArgType >( id_, args, 1, callLoc );
676 RefCountPtr< ArgType > argy = Helpers::down_cast_CoreArgument< ArgType >( id_, args, 2, callLoc );
678 Kernel::ContRef cont = evalState->cont_;
679 cont->takeValue( Kernel::ValueRef( new Lang::Transform2D( argr->val_ * argx->val_, 0,
680 0, argr->val_ * argy->val_,
681 0, 0 ) ),
682 evalState );
686 class Core_scale3d : public Lang::CoreFunction
688 public:
689 Core_scale3d( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name )
690 : CoreFunction( ns, name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), true ) )
692 Kernel::VariableHandle one( new Kernel::Variable( RefCountPtr< const Lang::Value >( new Lang::Float( 1 ) ) ) );
694 formals_->appendEvaluatedCoreFormal( "r", one );
695 formals_->appendEvaluatedCoreFormal( "x", one );
696 formals_->appendEvaluatedCoreFormal( "y", one );
697 formals_->appendEvaluatedCoreFormal( "z", one );
699 virtual void
700 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
702 args.applyDefaults( callLoc );
704 typedef const Lang::Float ArgType;
705 RefCountPtr< ArgType > argr = Helpers::down_cast_CoreArgument< ArgType >( id_, args, 0, callLoc );
706 RefCountPtr< ArgType > argx = Helpers::down_cast_CoreArgument< ArgType >( id_, args, 1, callLoc );
707 RefCountPtr< ArgType > argy = Helpers::down_cast_CoreArgument< ArgType >( id_, args, 2, callLoc );
708 RefCountPtr< ArgType > argz = Helpers::down_cast_CoreArgument< ArgType >( id_, args, 3, callLoc );
710 Kernel::ContRef cont = evalState->cont_;
711 cont->takeValue( Kernel::ValueRef( new Lang::Transform3D( argr->val_ * argx->val_, 0, 0,
712 0, argr->val_ * argy->val_, 0,
713 0, 0, argr->val_ * argz->val_,
714 0, 0, 0 ) ),
715 evalState );
719 class Core_inverse : public Lang::CoreFunction
721 public:
722 Core_inverse( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name ) : CoreFunction( ns, name ) { }
723 virtual void
724 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
726 const size_t ARITY = 1;
727 CHECK_ARITY( args, ARITY, id_ );
729 size_t i = 0;
731 typedef const Lang::Transform2D ArgType1;
732 RefCountPtr< ArgType1 > tf = Helpers::down_cast_CoreArgument< ArgType1 >( id_, args, i, callLoc );
733 double det = tf->xx_ * tf->yy_ - tf->xy_ * tf->yx_;
734 if( fabs( det ) < Computation::SINGULAR_TRANSFORM_LIMIT )
736 throw Exceptions::CoreOutOfRange( id_, args, 0, "Singular transforms cannot be inverted." );
738 double idet = 1 / det;
739 double ixx = idet * tf->yy_;
740 double ixy = - idet * tf->xy_;
741 double iyx = - idet * tf->yx_;
742 double iyy = idet * tf->xx_;
743 Kernel::ContRef cont = evalState->cont_;
744 cont->takeValue( Kernel::ValueRef( new Lang::Transform2D( ixx, iyx,
745 ixy, iyy,
746 -( ixx * tf->xt_ + ixy * tf->yt_ ), -( iyx * tf->xt_ + iyy * tf->yt_ ) ) ),
747 evalState );
751 class Core_inverse3d : public Lang::CoreFunction
753 public:
754 Core_inverse3d( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name ) : CoreFunction( ns, name ) { }
755 virtual void
756 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
758 const size_t ARITY = 1;
759 CHECK_ARITY( args, ARITY, id_ );
761 size_t i = 0;
763 typedef const Lang::Transform3D ArgType1;
764 RefCountPtr< ArgType1 > tf = Helpers::down_cast_CoreArgument< ArgType1 >( id_, args, i, callLoc );
765 double det =
766 tf->xx_ * ( tf->yy_ * tf->zz_ - tf->yz_ * tf->zy_ )
767 - tf->xy_ * ( tf->yx_ * tf->zz_ - tf->yz_ * tf->zx_ )
768 + tf->xz_ * ( tf->yx_ * tf->zy_ - tf->yy_ * tf->zx_ );
769 if( fabs( det ) < Computation::SINGULAR_TRANSFORM_LIMIT )
771 throw Exceptions::CoreOutOfRange( id_, args, 0, "Singular transforms cannot be inverted." );
773 double idet = 1 / det;
774 double ixx = idet * ( tf->yy_ * tf->zz_ - tf->yz_ * tf->zy_ );
775 double ixy = - idet * ( tf->xy_ * tf->zz_ - tf->xz_ * tf->zy_ );
776 double ixz = idet * ( tf->xy_ * tf->yz_ - tf->xz_ * tf->yy_ );
777 double iyx = - idet * ( tf->yx_ * tf->zz_ - tf->yz_ * tf->zx_ );
778 double iyy = idet * ( tf->xx_ * tf->zz_ - tf->xz_ * tf->zx_ );
779 double iyz = - idet * ( tf->xx_ * tf->yz_ - tf->xz_ * tf->yx_ );
780 double izx = idet * ( tf->yx_ * tf->zy_ - tf->yy_ * tf->zx_ );
781 double izy = - idet * ( tf->xx_ * tf->zy_ - tf->xy_ * tf->zx_ );
782 double izz = idet * ( tf->xx_ * tf->yy_ - tf->xy_ * tf->yx_ );
783 Kernel::ContRef cont = evalState->cont_;
784 cont->takeValue( Kernel::ValueRef( new Lang::Transform3D( ixx, iyx, izx,
785 ixy, iyy, izy,
786 ixz, iyz, izz,
787 -( ixx * tf->xt_ + ixy * tf->yt_ + ixz * tf->zt_ ),
788 -( iyx * tf->xt_ + iyy * tf->yt_ + iyz * tf->zt_ ),
789 -( izx * tf->xt_ + izy * tf->yt_ + izz * tf->zt_ ) ) ),
790 evalState );
794 class Core_formxo : public Lang::CoreFunction
796 public:
797 Core_formxo( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name ) : CoreFunction( ns, name ) { }
798 virtual void
799 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
801 const size_t ARITY = 1;
802 CHECK_ARITY( args, ARITY, id_ );
804 typedef const Lang::Drawable2D ArgType;
805 RefCountPtr< ArgType > arg = Helpers::down_cast_CoreArgument< ArgType >( id_, args, 0, callLoc );
807 RefCountPtr< const Lang::ElementaryPath2D > theBBox = arg->bbox( Lang::Drawable2D::BOUNDING );
808 Concrete::Coords2D llcorner( 0, 0 );
809 Concrete::Coords2D urcorner( 0, 0 );
810 if( ! theBBox->boundingRectangle( & llcorner, & urcorner ) )
812 throw Exceptions::InternalErrorIn( id_, "The object has no bounding box." );
816 RefCountPtr< SimplePDF::PDF_Stream_out > form;
817 RefCountPtr< SimplePDF::PDF_Object > indirection = SimplePDF::indirect( form, & Kernel::theIndirectObjectCount );
819 RefCountPtr< SimplePDF::PDF_Resources > resources;
820 (*form)[ "Resources" ] = SimplePDF::indirect( resources, & Kernel::theIndirectObjectCount );
822 (*form)[ "Subtype" ] = SimplePDF::newName( "Form" );
823 (*form)[ "FormType" ] = SimplePDF::newInt( 1 );
824 (*form)[ "BBox" ] = RefCountPtr< SimplePDF::PDF_Vector >( new SimplePDF::PDF_Vector( llcorner.x_.offtype< 1, 0 >( ), llcorner.y_.offtype< 1, 0 >( ),
825 urcorner.x_.offtype< 1, 0 >( ), urcorner.y_.offtype< 1, 0 >( ) ) );
827 /* There's a possibility of adding a transformation matrix entry in the dictionary here, but it is not used, not even
828 * for transformed drawables.
830 // (*markForm)[ "Matrix" ] = RefCountPtr<PDF_Object>( new PDF_Vector( 1, 0, 0, 1, -30, -30 ) );
832 Kernel::PageContentStates pdfState( resources );
833 arg->shipout( form->data, & pdfState, Lang::Transform2D( 1, 0, 0, 1, 0, 0 ) );
836 Lang::XObject * res = new Lang::XObject( indirection,
837 theBBox );
838 res->setDebugStr( "user form" );
839 Kernel::ContRef cont = evalState->cont_;
840 cont->takeValue( Kernel::ValueRef( res ),
841 evalState );
845 class Core_transparencygroup : public Lang::CoreFunction
847 public:
848 Core_transparencygroup( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name )
849 : CoreFunction( ns, name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), true ) )
851 formals_->appendEvaluatedCoreFormal( "content", Kernel::THE_SLOT_VARIABLE );
852 formals_->appendEvaluatedCoreFormal( "isolated", Kernel::THE_FALSE_VARIABLE );
853 formals_->appendEvaluatedCoreFormal( "knockout", Kernel::THE_FALSE_VARIABLE );
855 virtual void
856 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
858 args.applyDefaults( callLoc );
860 typedef const Lang::Group2D ArgType0;
861 typedef const Lang::Boolean ArgType1;
862 typedef const Lang::Boolean ArgType2;
863 RefCountPtr< ArgType0 > content = Helpers::down_cast_CoreArgument< ArgType0 >( id_, args, 0, callLoc );
864 RefCountPtr< ArgType1 > isolated = Helpers::down_cast_CoreArgument< ArgType1 >( id_, args, 1, callLoc );
865 RefCountPtr< ArgType2 > knockout = Helpers::down_cast_CoreArgument< ArgType2 >( id_, args, 2, callLoc );
867 RefCountPtr< const Lang::ColorSpace > blendSpace = evalState->dyn_->getBlendSpace( );
869 Kernel::ContRef cont = evalState->cont_;
870 cont->takeValue( Helpers::newTransparencyGroup( content, isolated->val_, knockout->val_, blendSpace ),
871 evalState );
875 class Core_importRasterImage : public Lang::CoreFunction
877 std::map< const char *, const Helpers::RasterLoader *, charPtrLess > loaders_;
878 public:
879 Core_importRasterImage( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name )
880 : CoreFunction( ns, name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), true ) )
882 formals_->appendEvaluatedCoreFormal( "filename", Kernel::THE_SLOT_VARIABLE );
883 formals_->appendEvaluatedCoreFormal( "resolution", Helpers::newValHandle( new Lang::Length( Concrete::Length( 1 ) ) ) );
884 formals_->appendEvaluatedCoreFormal( "override", Kernel::THE_TRUE_VARIABLE );
885 formals_->appendEvaluatedCoreFormal( "kind", Kernel::THE_VOID_VARIABLE );
887 loaders_[ "png" ] = & Helpers::theRasterLoader_PNG;
888 loaders_[ "PNG" ] = & Helpers::theRasterLoader_PNG;
890 loaders_[ "jpg" ] = & Helpers::theRasterLoader_JPEG;
891 loaders_[ "JPG" ] = & Helpers::theRasterLoader_JPEG;
892 loaders_[ "jpeg" ] = & Helpers::theRasterLoader_JPEG;
893 loaders_[ "JPEG" ] = & Helpers::theRasterLoader_JPEG;
895 /* It would seem natural to also support "JIF"-images, but currently the JPEG library we use won't open such files.
898 virtual void
899 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
901 args.applyDefaults( callLoc );
903 size_t argsi = 0;
905 typedef const Lang::String ArgType;
906 RefCountPtr< ArgType > filename = Helpers::down_cast_CoreArgument< ArgType >( id_, args, argsi, callLoc );
907 size_t argsi_filename = argsi;
909 std::string full_filename;
912 full_filename = Ast::theShapesScanner.searchFile( filename->val_.getPtr( ), true ); /* true means that errors should be handled in "runtime mode". */
914 catch( RefCountPtr< const char > & msg )
916 throw Exceptions::CoreOutOfRange( id_, args, argsi_filename, msg );
919 RefCountPtr< std::ifstream > iFile( new std::ifstream( full_filename.c_str( ) ) );
920 if( ! iFile->good( ) )
922 std::ostringstream msg;
923 msg << "Failed to open file for input: " << full_filename.c_str( ) ;
924 throw Exceptions::CoreOutOfRange( id_, args, argsi_filename, strrefdup( msg ) );
927 ++argsi;
928 typedef const Lang::Length ResolutionType;
929 Concrete::Length resolution = Helpers::down_cast_CoreArgument< ResolutionType >( id_, args, argsi, callLoc )->get( );
930 if( resolution <= Concrete::ZERO_LENGTH )
932 throw Exceptions::CoreOutOfRange( id_, args, argsi, strrefdup( "The resolution must be positive." ) );
935 ++argsi;
936 typedef const Lang::Boolean OverrideType;
937 bool override = Helpers::down_cast_CoreArgument< OverrideType >( id_, args, argsi, callLoc )->val_;
939 ++argsi;
940 typedef const Lang::Symbol KindType;
941 RefCountPtr< KindType > kind = Helpers::down_cast_CoreArgument< KindType >( id_, args, argsi, callLoc, true );
942 const Helpers::RasterLoader * loader = 0;
943 if( kind == NullPtr< KindType >( ) )
945 const char * begin = filename->val_.getPtr( );
946 const char * ext = filename->val_.getPtr( ) + filename->bytecount_ - 1;
947 for( ; ext > begin; --ext )
949 if( *ext == '.' )
951 typedef typeof loaders_ MapType;
952 MapType::const_iterator i = loaders_.find( ext + 1 );
953 if( i == loaders_.end( ) )
955 std::ostringstream msg;
956 msg << "Filename extension '" << ext << "' has no associated raster loader." ;
957 throw Exceptions::CoreOutOfRange( id_, args, argsi_filename, strrefdup( msg ) );
959 loader = i->second;
960 break;
963 if( loader == 0 )
965 std::ostringstream msg;
966 msg << "Filename without extension must be combined with explicit file kind: " << filename->val_.getPtr( ) ;
967 throw Exceptions::CoreOutOfRange( id_, args, argsi_filename, strrefdup( msg ) );
970 else
972 static Lang::Symbol PNG( "PNG" );
973 static Lang::Symbol JPEG( "JPEG" );
974 if( *kind == PNG )
976 loader = & Helpers::theRasterLoader_PNG;
978 else if( *kind == JPEG )
980 loader = & Helpers::theRasterLoader_JPEG;
982 else
984 std::ostringstream msg;
985 msg << "The only allowed file kind symbols are { " ;
986 PNG.show( msg );
987 msg << ", " ;
988 JPEG.show( msg );
989 msg << " }." ;
990 throw Exceptions::CoreOutOfRange( id_, args, argsi, strrefdup( msg ) );
994 Kernel::ContRef cont = evalState->cont_;
995 cont->takeValue( loader->load( iFile, full_filename, resolution, override, id_, callLoc ),
996 evalState );
1000 class Core_vector : public Lang::CoreFunction
1002 public:
1003 Core_vector( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name ) : CoreFunction( ns, name ) { }
1004 virtual void
1005 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1007 std::vector< RefCountPtr< const Lang::Value > > * res = new std::vector< RefCountPtr< const Lang::Value > >;
1008 res->reserve( args.size( ) );
1010 for( size_t i = 0; i != args.size( ); ++i )
1012 res->push_back( args.getValue( i ) );
1015 Kernel::ContRef cont = evalState->cont_;
1016 cont->takeValue( Kernel::ValueRef( new Lang::VectorFunction( res ) ),
1017 evalState );
1021 class Core_graph : public Lang::CoreFunction
1023 public:
1024 Core_graph( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name )
1025 : CoreFunction( ns, name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), true ) )
1027 formals_->appendEvaluatedCoreFormal( "nodes", Kernel::THE_NIL_VARIABLE );
1028 formals_->appendEvaluatedCoreFormal( "edges", Kernel::THE_NIL_VARIABLE );
1029 formals_->appendEvaluatedCoreFormal( "directed", Kernel::THE_FALSE_VARIABLE );
1030 formals_->appendEvaluatedCoreFormal( "undirected", Kernel::THE_FALSE_VARIABLE );
1031 formals_->appendEvaluatedCoreFormal( "loops", Kernel::THE_FALSE_VARIABLE );
1032 formals_->appendEvaluatedCoreFormal( "parallel", Kernel::THE_FALSE_VARIABLE );
1033 formals_->appendEvaluatedCoreFormal( "partitions", Kernel::THE_VOID_VARIABLE );
1035 virtual void
1036 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1038 args.applyDefaults( callLoc );
1040 size_t argsi = 0;
1041 size_t nodesi = argsi;
1042 RefCountPtr< const Lang::Value > nodes = args.getValue( argsi );
1043 ++argsi;
1044 size_t edgesi = argsi;
1045 RefCountPtr< const Lang::Value > edges = args.getValue( argsi );
1047 Kernel::GraphDomain * domainPtr = new Kernel::GraphDomain( );
1048 RefCountPtr< const Kernel::GraphDomain > domain = RefCountPtr< const Kernel::GraphDomain >( domainPtr );
1049 typedef const Lang::Boolean FlagType;
1050 ++argsi;
1051 if( Helpers::down_cast_CoreArgument< FlagType >( id_, args, argsi, callLoc )->val_ ){
1052 domainPtr->allowDirected( );
1054 ++argsi;
1055 if( Helpers::down_cast_CoreArgument< FlagType >( id_, args, argsi, callLoc )->val_ ){
1056 domainPtr->allowUndirected( );
1058 ++argsi;
1059 if( Helpers::down_cast_CoreArgument< FlagType >( id_, args, argsi, callLoc )->val_ ){
1060 domainPtr->allowLoops( );
1062 ++argsi;
1063 if( Helpers::down_cast_CoreArgument< FlagType >( id_, args, argsi, callLoc )->val_ ){
1064 domainPtr->allowParallel( );
1067 ++argsi;
1068 size_t partitionsi = argsi;
1069 RefCountPtr< const Lang::Value > partitions = args.getValue( argsi );
1071 if( partitions == Lang::THE_VOID ){
1072 RefCountPtr< const Lang::SingleList > noPartitions = RefCountPtr< const Lang::SingleList >( NullPtr< const Lang::SingleList >( ) );
1073 evalState->cont_ = Kernel::ContRef( new Kernel::ForcingListContinuation
1074 ( Kernel::ContRef( new Kernel::Core_graph_cont_nodes( edges, args.getLoc( edgesi ), domain, noPartitions, evalState->cont_, args.getLoc( partitionsi ), args.getLoc( nodesi ) ) ),
1075 args.getLoc( nodesi ),
1076 true ) );
1077 Kernel::ContRef cont = evalState->cont_;
1078 cont->takeValue( nodes, evalState );
1079 }else{
1080 evalState->cont_ = Kernel::ContRef( new Kernel::ForcingListContinuation
1081 ( Kernel::ContRef( new Kernel::Core_graph_cont_partitions( nodes, args.getLoc( nodesi ), edges, args.getLoc( edgesi ), domain, evalState->cont_, args.getLoc( partitionsi ) ) ),
1082 args.getLoc( partitionsi ),
1083 true ) );
1084 Kernel::ContRef cont = evalState->cont_;
1085 cont->takeValue( partitions, evalState );
1090 class Core_walk : public Lang::CoreFunction
1092 public:
1093 Core_walk( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name )
1094 : CoreFunction( ns, name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), true ) )
1096 formals_->appendEvaluatedCoreFormal( "edges", Kernel::THE_NIL_VARIABLE );
1097 formals_->appendEvaluatedCoreFormal( "start", Kernel::THE_VOID_VARIABLE );
1098 formals_->appendEvaluatedCoreFormal( "end", Kernel::THE_VOID_VARIABLE );
1100 virtual void
1101 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1103 args.applyDefaults( callLoc );
1105 size_t argsi = 0;
1106 typedef const Lang::SingleList ListType;
1107 size_t edgesi = argsi;
1108 RefCountPtr< ListType > edges = Helpers::down_cast_CoreArgument< ListType >( id_, args, argsi, callLoc );
1110 ++argsi;
1111 typedef const Lang::Node NodeType;
1112 /* The start and end may be null pointers, and it is not until the Lang::Graph constructor that
1113 * these will be replaced by automatically determined nodes.
1115 RefCountPtr< NodeType > start = Helpers::down_cast_CoreArgument< NodeType >( id_, args, argsi, callLoc, true );
1117 ++argsi;
1118 size_t endi = argsi;
1119 RefCountPtr< NodeType > end = Helpers::down_cast_CoreArgument< NodeType >( id_, args, argsi, callLoc, true );
1121 RefCountPtr< const Lang::Graph > graph = RefCountPtr< const Lang::Graph >( NullPtr< const Lang::Graph >( ) );
1122 if( start != NullPtr< const Lang::Node >( ) ){
1123 graph = start->graph( );
1124 if( end != NullPtr< const Lang::Node >( ) &&
1125 end->graph( ) != graph ){
1126 throw Exceptions::CoreRequirement( "The end node must belong to the same graph as the start node.", id_, args.getLoc( endi ) );
1128 }else if( end != NullPtr< const Lang::Node >( ) ){
1129 graph = end->graph( );
1130 }else if( const Lang::SingleListPair * ptr = dynamic_cast< const Lang::SingleListPair * >( edges.getPtr( ) ) ){
1131 RefCountPtr< const Lang::Value > firstEdgeVal = ptr->car_->getUntyped( );
1132 const Lang::Edge * firstEdge = dynamic_cast< const Lang::Edge * >( firstEdgeVal.getPtr( ) );
1133 if( firstEdge == 0 ){
1134 throw Exceptions::TypeMismatch( callLoc, "First edge", firstEdgeVal->getTypeName( ), Lang::Edge::staticTypeName( ) );
1136 graph = firstEdge->graph( );
1137 }else{
1138 throw Exceptions::CoreRequirement( "An empty walk must be specified with a start or end node.", id_, callLoc );
1141 evalState->cont_ = Kernel::ContRef( new Kernel::ForcingListContinuation
1142 ( Kernel::ContRef( new Kernel::Core_walk_cont_edges( graph, start, end, args.getLoc( edgesi ), evalState->cont_, callLoc ) ),
1143 args.getLoc( edgesi ),
1144 true ) );
1145 Kernel::ContRef cont = evalState->cont_;
1146 cont->takeValue( edges, evalState );
1150 class Core_interpolate : public Lang::CoreFunction
1152 public:
1153 Core_interpolate( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name )
1154 : CoreFunction( ns, name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), true ) )
1156 formals_->appendEvaluatedCoreFormal( "function", Kernel::THE_SLOT_VARIABLE );
1157 formals_->appendEvaluatedCoreFormal( "domain", Kernel::THE_SLOT_VARIABLE );
1158 formals_->appendEvaluatedCoreFormal( "size", Kernel::THE_SLOT_VARIABLE );
1159 formals_->appendEvaluatedCoreFormal( "range", Kernel::THE_SLOT_VARIABLE );
1160 formals_->appendEvaluatedCoreFormal( "encode", Kernel::THE_VOID_VARIABLE );
1161 formals_->appendEvaluatedCoreFormal( "decode", Kernel::THE_VOID_VARIABLE );
1163 virtual void
1164 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1166 args.applyDefaults( callLoc );
1168 throw Exceptions::NotImplemented( "Core_interpolate::call" );
1172 class Core_importPDFpages : public Lang::CoreFunction
1174 public:
1175 Core_importPDFpages( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name ) : CoreFunction( ns, name ) { }
1176 virtual void
1177 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1179 const size_t ARITY = 1;
1180 CHECK_ARITY( args, ARITY, id_ );
1182 typedef const Lang::String ArgType;
1183 RefCountPtr< ArgType > arg = Helpers::down_cast_CoreArgument< ArgType >( id_, args, 0, callLoc );
1185 std::string filename;
1188 filename = Ast::theShapesScanner.searchFile( arg->val_.getPtr( ), true ); /* true means that errors should be handled in "runtime mode". */
1190 catch( RefCountPtr< const char > & msg )
1192 throw Exceptions::CoreOutOfRange( id_, args, 0, msg );
1195 RefCountPtr< std::ifstream > iFile( new std::ifstream( filename.c_str( ) ) );
1196 if( ! iFile->good( ) )
1198 std::ostringstream msg;
1199 msg << "Failed to open file for input: " << arg->val_.getPtr( ) ;
1200 throw Exceptions::CoreOutOfRange( id_, args, 0, strrefdup( msg ) );
1202 RefCountPtr< SimplePDF::PDF_in > pdfi( new SimplePDF::PDF_in( iFile ) );
1204 RefCountPtr< const std::vector< RefCountPtr< const Lang::XObject > > > typedRes = RefCountPtr< const std::vector< RefCountPtr< const Lang::XObject > > >( NullPtr< std::vector< RefCountPtr< const Lang::XObject > > >( ) );
1207 typedRes = Kernel::thePDFImporter.addPagesAsXObjects( pdfi );
1209 catch( const char * ball )
1211 throw Exceptions::InternalError( strrefdup( ( std::string( "An error occurred while importing " ) + arg->val_.getPtr( ) + ": " + ball ).c_str( ) ) );
1214 std::vector< RefCountPtr< const Lang::Value > > * untypedRes = new std::vector< RefCountPtr< const Lang::Value > >;
1215 untypedRes->reserve( typedRes->size( ) );
1216 typedef typeof *typedRes ListType;
1217 for( ListType::const_iterator i = typedRes->begin( ); i != typedRes->end( ); ++i )
1219 untypedRes->push_back( *i );
1222 Kernel::ContRef cont = evalState->cont_;
1223 cont->takeValue( Kernel::ValueRef( new Lang::VectorFunction( untypedRes ) ),
1224 evalState );
1228 namespace Implementation
1230 double
1231 svg_path_strtod( const char ** src )
1233 const char * start = *src;
1234 char * endp;
1235 double res = strtod( start, & endp );
1236 *src = endp;
1237 if( **src != ' ' )
1239 for( ; *start == ' '; ++start )
1241 throw std::string( start, strchr( start, ' ' ) - start );
1243 return res;
1246 class Core_svg_path : public Lang::CoreFunction
1248 public:
1249 Core_svg_path( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name )
1250 : CoreFunction( ns, name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), true ) )
1252 formals_->appendEvaluatedCoreFormal( "d", Kernel::THE_SLOT_VARIABLE );
1253 formals_->appendEvaluatedCoreFormal( "xunit", Helpers::newValHandle( new Lang::Length( Concrete::Length( 1 ) ) ) );
1254 formals_->appendEvaluatedCoreFormal( "yunit", Helpers::newValHandle( new Lang::Length( Concrete::Length( 1 ) ) ) );
1255 formals_->appendEvaluatedCoreFormal( "multi", Kernel::THE_VOID_VARIABLE );
1256 formals_->appendEvaluatedCoreFormal( "singletons", Kernel::THE_TRUE_VARIABLE );
1258 virtual void
1259 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1261 args.applyDefaults( callLoc );
1263 size_t argsi = 0;
1264 typedef const Lang::String StrType;
1265 RefCountPtr< StrType > arg = Helpers::down_cast_CoreArgument< StrType >( id_, args, argsi, callLoc );
1267 typedef const Lang::Length ScaleType;
1268 ++argsi;
1269 Concrete::Length dx = Helpers::down_cast_CoreArgument< ScaleType >( id_, args, argsi, callLoc )->get( );
1270 ++argsi;
1271 Concrete::Length dy = Helpers::down_cast_CoreArgument< ScaleType >( id_, args, argsi, callLoc )->get( );
1273 typedef const Lang::Boolean FlagType;
1274 ++argsi;
1275 RefCountPtr< FlagType > multi = Helpers::down_cast_CoreArgument< FlagType >( id_, args, argsi, callLoc, true );
1276 ++argsi;
1277 bool singletons = Helpers::down_cast_CoreArgument< FlagType >( id_, args, argsi, callLoc )->val_;
1279 RefCountPtr< char > buf = RefCountPtr< char >( new char[ 2 * strlen( arg->val_.getPtr( ) + 1 ) ] );
1281 /* Get rid of any whitespace that isn't a plain space, and make sure every number is terminated by whitespace.
1283 char * dst = buf.getPtr( );
1284 for( const char * src = arg->val_.getPtr( ); *src != '\0'; ++src, ++dst )
1286 switch( *src )
1288 case '\t':
1289 case '\n':
1290 case ',':
1291 *dst = ' ';
1292 continue;
1294 if( ( 'A' <= *src && *src <= 'Z' ) || ( 'a' <= *src && *src <= 'z' ) )
1296 /* Insert whitespace before command to ensure command is not immediately following number.
1298 *dst = ' ';
1299 ++dst;
1301 *dst = *src;
1303 *dst = ' ';
1304 ++dst;
1305 *dst = '\0';
1308 RefCountPtr< Lang::MultiPath2D > multiPath = RefCountPtr< Lang::MultiPath2D >( new Lang::MultiPath2D );
1309 RefCountPtr< Lang::ElementaryPath2D > elemPath = RefCountPtr< Lang::ElementaryPath2D >( NullPtr< Lang::ElementaryPath2D >( ) );
1313 char cmd = '\0';
1314 Concrete::PathPoint2D originPathPoint( new Concrete::Coords2D( 0, 0 ) );
1315 Concrete::PathPoint2D * first = & originPathPoint;
1316 Concrete::PathPoint2D * last = & originPathPoint;
1317 const char * srcEnd = buf.getPtr( ) + strlen( buf.getPtr( ) );
1318 for( const char * src = buf.getPtr( ); src < srcEnd; ++src )
1320 for( ; *src == ' '; ++src )
1322 if( *src == '\0' )
1324 break;
1326 switch( *src )
1328 case 'M':
1329 case 'm':
1330 case 'Z':
1331 case 'z':
1332 case 'L':
1333 case 'l':
1334 case 'H':
1335 case 'h':
1336 case 'V':
1337 case 'v':
1338 case 'C':
1339 case 'c':
1340 case 'S':
1341 case 's':
1343 cmd = *src;
1344 ++src;
1345 break;
1347 case 'Q':
1348 case 'q':
1349 case 'T':
1350 case 't':
1351 case 'A':
1352 case 'a':
1354 throw Exceptions::CoreOutOfRange( id_, args, 0, strrefdup( std::string( "SVG path command not compatible with cubic splines: " ) + *src ) );
1357 switch( cmd )
1359 case 'M':
1361 if( elemPath != NullPtr< Lang::ElementaryPath2D >( ) && ( singletons || elemPath->duration( ) >= 1 ) )
1363 multiPath->push_back( elemPath );
1365 Concrete::Length x = dx * Implementation::svg_path_strtod( & src );
1366 Concrete::Length y = - dy * Implementation::svg_path_strtod( & src );
1367 first = new Concrete::PathPoint2D( new Concrete::Coords2D( x, y ) );
1368 last = first;
1369 elemPath = RefCountPtr< Lang::ElementaryPath2D >( new Lang::ElementaryPath2D );
1370 elemPath->push_back( last );
1371 cmd = 'L';
1372 break;
1374 case 'm':
1376 if( elemPath != NullPtr< Lang::ElementaryPath2D >( ) && ( singletons || elemPath->duration( ) >= 1 ) )
1378 multiPath->push_back( elemPath );
1380 Concrete::Length x = last->mid_->x_ + dx * Implementation::svg_path_strtod( & src );
1381 Concrete::Length y = last->mid_->y_ - dy * Implementation::svg_path_strtod( & src );
1382 first = new Concrete::PathPoint2D( new Concrete::Coords2D( x, y ) );
1383 last = first;
1384 elemPath = RefCountPtr< Lang::ElementaryPath2D >( new Lang::ElementaryPath2D );
1385 elemPath->push_back( last );
1386 cmd = 'l';
1387 break;
1389 case 'Z':
1391 elemPath->close( );
1392 last = first;
1393 break;
1395 case 'z':
1397 elemPath->close( );
1398 last = first;
1399 break;
1401 case 'L':
1403 Concrete::Length x = dx * Implementation::svg_path_strtod( & src );
1404 Concrete::Length y = - dy * Implementation::svg_path_strtod( & src );
1405 last = new Concrete::PathPoint2D( new Concrete::Coords2D( x, y ) );
1406 elemPath->push_back( last );
1407 break;
1409 case 'l':
1411 Concrete::Length x = last->mid_->x_ + dx * Implementation::svg_path_strtod( & src );
1412 Concrete::Length y = last->mid_->y_ - dy * Implementation::svg_path_strtod( & src );
1413 last = new Concrete::PathPoint2D( new Concrete::Coords2D( x, y ) );
1414 elemPath->push_back( last );
1415 break;
1417 case 'H':
1419 Concrete::Length x = dx * Implementation::svg_path_strtod( & src );
1420 last = new Concrete::PathPoint2D( new Concrete::Coords2D( x, last->mid_->y_ ) );
1421 elemPath->push_back( last );
1422 break;
1424 case 'h':
1426 Concrete::Length x = last->mid_->x_ + dx * Implementation::svg_path_strtod( & src );
1427 last = new Concrete::PathPoint2D( new Concrete::Coords2D( x, last->mid_->y_ ) );
1428 elemPath->push_back( last );
1429 break;
1431 case 'V':
1433 Concrete::Length y = - dy * Implementation::svg_path_strtod( & src );
1434 last = new Concrete::PathPoint2D( new Concrete::Coords2D( last->mid_->x_, y ) );
1435 elemPath->push_back( last );
1436 break;
1438 case 'v':
1440 Concrete::Length y = last->mid_->y_ - dy * Implementation::svg_path_strtod( & src );
1441 last = new Concrete::PathPoint2D( new Concrete::Coords2D( last->mid_->x_, y ) );
1442 elemPath->push_back( last );
1443 break;
1445 case 'C':
1447 Concrete::Length x1 = dx * Implementation::svg_path_strtod( & src );
1448 Concrete::Length y1 = - dy * Implementation::svg_path_strtod( & src );
1449 Concrete::Length x2 = dx * Implementation::svg_path_strtod( & src );
1450 Concrete::Length y2 = - dy * Implementation::svg_path_strtod( & src );
1451 Concrete::Length x3 = dx * Implementation::svg_path_strtod( & src );
1452 Concrete::Length y3 = - dy * Implementation::svg_path_strtod( & src );
1453 last->front_ = new Concrete::Coords2D( x1, y1 );
1454 last = new Concrete::PathPoint2D( new Concrete::Coords2D( x3, y3 ) );
1455 last->rear_ = new Concrete::Coords2D( x2, y2 );
1456 elemPath->push_back( last );
1457 break;
1459 case 'c':
1461 Concrete::Length x1 = last->mid_->x_ + dx * Implementation::svg_path_strtod( & src );
1462 Concrete::Length y1 = last->mid_->y_ - dy * Implementation::svg_path_strtod( & src );
1463 Concrete::Length x2 = last->mid_->x_ + dx * Implementation::svg_path_strtod( & src );
1464 Concrete::Length y2 = last->mid_->y_ - dy * Implementation::svg_path_strtod( & src );
1465 Concrete::Length x3 = last->mid_->x_ + dx * Implementation::svg_path_strtod( & src );
1466 Concrete::Length y3 = last->mid_->y_ - dy * Implementation::svg_path_strtod( & src );
1467 last->front_ = new Concrete::Coords2D( x1, y1 );
1468 last = new Concrete::PathPoint2D( new Concrete::Coords2D( x3, y3 ) );
1469 last->rear_ = new Concrete::Coords2D( x2, y2 );
1470 elemPath->push_back( last );
1471 break;
1473 case 'S':
1475 Concrete::Length x2 = dx * Implementation::svg_path_strtod( & src );
1476 Concrete::Length y2 = - dy * Implementation::svg_path_strtod( & src );
1477 Concrete::Length x3 = dx * Implementation::svg_path_strtod( & src );
1478 Concrete::Length y3 = - dy * Implementation::svg_path_strtod( & src );
1479 last->front_ = new Concrete::Coords2D( 2 * *(last->mid_) - *(last->rear_) );
1480 last = new Concrete::PathPoint2D( new Concrete::Coords2D( x3, y3 ) );
1481 last->rear_ = new Concrete::Coords2D( x2, y2 );
1482 elemPath->push_back( last );
1483 break;
1485 case 's':
1487 Concrete::Length x2 = last->mid_->x_ + dx * Implementation::svg_path_strtod( & src );
1488 Concrete::Length y2 = last->mid_->y_ - dy * Implementation::svg_path_strtod( & src );
1489 Concrete::Length x3 = last->mid_->x_ + dx * Implementation::svg_path_strtod( & src );
1490 Concrete::Length y3 = last->mid_->y_ - dy * Implementation::svg_path_strtod( & src );
1491 last->front_ = new Concrete::Coords2D( 2 * *(last->mid_) - *(last->rear_) );
1492 last = new Concrete::PathPoint2D( new Concrete::Coords2D( x3, y3 ) );
1493 last->rear_ = new Concrete::Coords2D( x2, y2 );
1494 elemPath->push_back( last );
1495 break;
1497 case '\0':
1498 throw Exceptions::CoreOutOfRange( id_, args, 0, "Malformed SVG path string (failed to initialize command character)." );
1499 default:
1501 throw Exceptions::InternalError( "While reading SVG path string: Command character out of range." );
1506 catch( const std::string & badNumber )
1508 throw Exceptions::CoreOutOfRange( id_, args, 0, strrefdup( std::string( "Ill-formed number: " ) + badNumber ) );
1511 if( elemPath != NullPtr< Lang::ElementaryPath2D >( ) && ( singletons || elemPath->duration( ) >= 1 ) )
1513 multiPath->push_back( RefCountPtr< const Lang::Path2D >( elemPath ) );
1516 if( multiPath->size( ) == 0 )
1518 throw Exceptions::CoreOutOfRange( id_, args, 0, "No path was produced." );
1520 if( multiPath->size( ) == 1 )
1522 Kernel::ContRef cont = evalState->cont_;
1523 if( multi != NullPtr< FlagType >( ) && multi->val_ )
1525 cont->takeValue( Kernel::ValueRef( multiPath ),
1526 evalState );
1528 else
1530 cont->takeValue( Kernel::ValueRef( multiPath->front( ) ),
1531 evalState );
1534 else
1536 if( multi != NullPtr< FlagType >( ) && ! multi->val_ )
1538 throw Exceptions::CoreOutOfRange( id_, args, 0, "More than one sub-path conflicts with false for <multi>." );
1540 Kernel::ContRef cont = evalState->cont_;
1541 cont->takeValue( Kernel::ValueRef( multiPath ),
1542 evalState );
1547 class Core_sprintf : public Lang::CoreFunction
1549 public:
1550 Core_sprintf( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name ) : CoreFunction( ns, name ) { }
1551 virtual void
1552 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1554 if( args.empty( ) )
1556 throw Exceptions::CoreArityMismatch( id_, 1, args.size( ) );
1558 size_t i = 0;
1559 typedef const Lang::String Arg1Type;
1560 RefCountPtr< Arg1Type > arg1 = Helpers::down_cast_CoreArgument< Arg1Type >( id_, args, i, callLoc );
1562 /* snprintf( 0, 0, ... ) does not seem to work properly on some systems.
1563 * Therefore, I resort to the use of a dummy string, and "n = 1".
1565 char * res = 0;
1566 int status;
1567 char dummy[1];
1568 switch( args.size( ) )
1570 case 1:
1572 size_t sz = snprintf( dummy, 1, arg1->val_.getPtr( ), 0 ); /* The final 0 is just a dummy argument that makes the compiler relax. */
1573 res = new char[ sz + 1 ];
1574 status = sprintf( res, arg1->val_.getPtr( ), 0 ); /* The final 0 is just a dummy argument that makes the compiler relax. */
1576 break;
1577 case 2:
1579 ++i;
1581 typedef const Lang::String Arg2Type;
1582 Arg2Type * arg2 = dynamic_cast< Arg2Type * >( args.getValue( i ).getPtr( ) );
1583 if( arg2 != 0 )
1585 size_t sz = snprintf( dummy, 1, arg1->val_.getPtr( ), arg2->val_.getPtr( ) );
1586 res = new char[ sz + 1 ];
1587 status = sprintf( res, arg1->val_.getPtr( ), arg2->val_.getPtr( ) );
1588 break;
1592 typedef const Lang::Float Arg2Type;
1593 Arg2Type * arg2 = dynamic_cast< Arg2Type * >( args.getValue( i ).getPtr( ) );
1594 if( arg2 != 0 )
1596 size_t sz = snprintf( dummy, 1, arg1->val_.getPtr( ), arg2->val_ );
1597 res = new char[ sz + 1 ];
1598 status = sprintf( res, arg1->val_.getPtr( ), arg2->val_ );
1599 break;
1603 typedef const Lang::Integer Arg2Type;
1604 Arg2Type * arg2 = dynamic_cast< Arg2Type * >( args.getValue( i ).getPtr( ) );
1605 if( arg2 != 0 )
1607 size_t sz = snprintf( dummy, 1, arg1->val_.getPtr( ), arg2->val_ );
1608 res = new char[ sz + 1 ];
1609 status = sprintf( res, arg1->val_.getPtr( ), arg2->val_ );
1610 break;
1614 typedef const Lang::ChronologicalTime Arg2Type;
1615 Arg2Type * arg2 = dynamic_cast< Arg2Type * >( args.getValue( i ).getPtr( ) );
1616 if( arg2 != 0 )
1618 const char * fmt = arg1->val_.getPtr( );
1619 const struct tm * tmp = arg2->temporary_localtime( );
1620 size_t sz = strlen( fmt ) * 2;
1621 res = new char[ sz ];
1622 while( strftime( res, sz, fmt, tmp ) == 0 )
1624 delete res;
1625 sz *= 2;
1626 res = new char[ sz ];
1628 status = 0; // Here, I'd like to check some error condition instead...
1629 break;
1632 throw Exceptions::CoreTypeMismatch( callLoc, id_, args, i, Interaction::SEVERAL_TYPES );
1634 break;
1635 default:
1636 throw Exceptions::CoreOutOfRange( id_, args, 0, "The number of arguments is out of the implemented range." );
1639 if( res == 0 )
1641 throw Exceptions::InternalError( "Failed to assign to res in sprintf." );
1644 if( status < 0 )
1646 std::ostringstream oss;
1647 oss << "Call to library routine returned negative value indicating an error: " << status << ".";
1648 throw Exceptions::CoreOutOfRange( id_, args, 0, strrefdup( oss ) );
1651 Kernel::ContRef cont = evalState->cont_;
1652 cont->takeValue( Kernel::ValueRef( new Lang::String( res, false ) ),
1653 evalState );
1657 class Core_strftime : public Lang::CoreFunction
1659 public:
1660 Core_strftime( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name ) : CoreFunction( ns, name ) { }
1661 virtual void
1662 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1664 const size_t ARITY = 0;
1665 CHECK_ARITY( args, ARITY, id_ );
1667 time_t t;
1668 tm * timeInfo;
1669 t = time( 0 );
1670 timeInfo = localtime( & t );
1671 std::ostringstream res;
1672 res << timeInfo->tm_hour << ":" << timeInfo->tm_min << ":" << timeInfo->tm_sec ;
1674 Kernel::ContRef cont = evalState->cont_;
1675 cont->takeValue( Kernel::ValueRef( new Lang::String( strrefdup( res ) ) ),
1676 evalState );
1680 class Core_ambient_light : public Lang::CoreFunction
1682 public:
1683 Core_ambient_light( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name )
1684 : CoreFunction( ns, name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), true ) )
1686 formals_->appendEvaluatedCoreFormal( "color", Kernel::THE_SLOT_VARIABLE );
1688 virtual void
1689 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1691 args.applyDefaults( callLoc );
1694 typedef const Lang::Gray ArgType;
1695 ArgType * col = dynamic_cast< ArgType * >( args.getValue( 0 ).getPtr( ) );
1696 if( col != 0 )
1698 Kernel::ContRef cont = evalState->cont_;
1699 cont->takeValue( Kernel::ValueRef( new Lang::AmbientLightGray( col->components( ) ) ),
1700 evalState );
1701 return;
1706 typedef const Lang::RGB ArgType;
1707 ArgType * col = dynamic_cast< ArgType * >( args.getValue( 0 ).getPtr( ) );
1708 if( col != 0 )
1710 Kernel::ContRef cont = evalState->cont_;
1711 cont->takeValue( Kernel::ValueRef( new Lang::AmbientLightRGB( col->components( ) ) ),
1712 evalState );
1713 return;
1717 throw Exceptions::CoreTypeMismatch( callLoc, id_, args, 0, Helpers::typeSetString( Lang::Gray::staticTypeName( ), Lang::RGB::staticTypeName( ) ) );
1721 class Core_specular_light : public Lang::CoreFunction
1723 public:
1724 Core_specular_light( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name )
1725 : CoreFunction( ns, name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), true ) )
1727 formals_->appendEvaluatedCoreFormal( "color", Kernel::THE_SLOT_VARIABLE );
1728 formals_->appendEvaluatedCoreFormal( "radius", Helpers::newValHandle( new Lang::Length( HUGE_VAL ) ) );
1729 formals_->appendEvaluatedCoreFormal( "shadows", Kernel::THE_FALSE_VARIABLE );
1731 virtual void
1732 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1734 args.applyDefaults( callLoc );
1736 typedef const Lang::Length RadiusType;
1737 RefCountPtr< RadiusType > radius = Helpers::down_cast_CoreArgument< RadiusType >( id_, args, 1, callLoc );
1738 typedef const Lang::Boolean ShadowsType;
1739 RefCountPtr< ShadowsType > shadows = Helpers::down_cast_CoreArgument< ShadowsType >( id_, args, 2, callLoc );
1742 typedef const Lang::Gray ArgType;
1743 ArgType * col = dynamic_cast< ArgType * >( args.getValue( 0 ).getPtr( ) );
1744 if( col != 0 )
1746 Kernel::ContRef cont = evalState->cont_;
1747 cont->takeValue( Kernel::ValueRef( new Lang::SpecularLightGray( Concrete::Coords3D( 0, 0, 0 ),
1748 col->components( ),
1749 radius->get( ),
1750 shadows->val_ ) ),
1751 evalState );
1752 return;
1757 typedef const Lang::RGB ArgType;
1758 ArgType * col = dynamic_cast< ArgType * >( args.getValue( 0 ).getPtr( ) );
1759 if( col != 0 )
1761 Kernel::ContRef cont = evalState->cont_;
1762 cont->takeValue( Kernel::ValueRef( new Lang::SpecularLightRGB( Concrete::Coords3D( 0, 0, 0 ),
1763 col->components( ),
1764 radius->get( ),
1765 shadows->val_ ) ),
1766 evalState );
1767 return;
1771 throw Exceptions::CoreTypeMismatch( callLoc, id_, args, 0, Helpers::typeSetString( Lang::Gray::staticTypeName( ), Lang::RGB::staticTypeName( ) ) );
1775 class Core_distant_light : public Lang::CoreFunction
1777 public:
1778 Core_distant_light( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name )
1779 : CoreFunction( ns, name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), true ) )
1781 formals_->appendEvaluatedCoreFormal( "color", Kernel::THE_SLOT_VARIABLE );
1782 formals_->appendEvaluatedCoreFormal( "shadows", Kernel::THE_FALSE_VARIABLE );
1784 virtual void
1785 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1787 args.applyDefaults( callLoc );
1789 typedef const Lang::Boolean ShadowsType;
1790 RefCountPtr< ShadowsType > shadows = Helpers::down_cast_CoreArgument< ShadowsType >( id_, args, 1, callLoc );
1793 typedef const Lang::Gray ArgType;
1794 ArgType * col = dynamic_cast< ArgType * >( args.getValue( 0 ).getPtr( ) );
1795 if( col != 0 )
1797 Kernel::ContRef cont = evalState->cont_;
1798 cont->takeValue( Kernel::ValueRef( new Lang::DistantLightGray( Concrete::UnitFloatTriple( 0., 0., -1. ),
1799 col->components( ),
1800 shadows->val_ ) ),
1801 evalState );
1802 return;
1807 typedef const Lang::RGB ArgType;
1808 ArgType * col = dynamic_cast< ArgType * >( args.getValue( 0 ).getPtr( ) );
1809 if( col != 0 )
1811 Kernel::ContRef cont = evalState->cont_;
1812 cont->takeValue( Kernel::ValueRef( new Lang::DistantLightRGB( Concrete::UnitFloatTriple( 0., 0., -1. ),
1813 col->components( ),
1814 shadows->val_ ) ),
1815 evalState );
1816 return;
1820 throw Exceptions::CoreTypeMismatch( callLoc, id_, args, 0, Helpers::typeSetString( Lang::Gray::staticTypeName( ), Lang::RGB::staticTypeName( ) ) );
1824 class Core_textrenderingmode : public Lang::CoreFunction
1826 public:
1827 Core_textrenderingmode( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name )
1828 : CoreFunction( ns, name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), true ) )
1830 formals_->appendEvaluatedCoreFormal( "fill", Kernel::THE_FALSE_VARIABLE );
1831 formals_->appendEvaluatedCoreFormal( "stroke", Kernel::THE_FALSE_VARIABLE );
1833 virtual void
1834 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1836 args.applyDefaults( callLoc );
1838 typedef const Lang::Boolean FlagType;
1839 RefCountPtr< FlagType > fill = Helpers::down_cast_CoreArgument< FlagType >( id_, args, 0, callLoc );
1840 RefCountPtr< FlagType > stroke = Helpers::down_cast_CoreArgument< FlagType >( id_, args, 1, callLoc );
1842 Kernel::ContRef cont = evalState->cont_;
1843 cont->takeValue( Kernel::ValueRef( new Lang::TextRenderingMode( fill->val_, stroke->val_, false ) ),
1844 evalState );
1848 class Core_manualkern : public Lang::CoreFunction
1850 public:
1851 Core_manualkern( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name ) : CoreFunction( ns, name ) { }
1852 virtual void
1853 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1855 // Note that res is _not_ yet const. We use a RefCountPtr to take care of memory deallocation in case some argument has the wrong type and
1856 // the result is not used.
1857 RefCountPtr< Lang::KernedText > res( new Lang::KernedText( evalState->dyn_->getTextState( ), evalState->dyn_->getGraphicsState( ) ) );
1859 for( size_t i = 0; i != args.size( ); ++i )
1863 typedef const Lang::String ArgType;
1864 res->pushString( Helpers::try_cast_CoreArgument< ArgType >( args.getValue( i ) ) );
1865 continue;
1867 catch( const NonLocalExit::NotThisType & ball )
1869 /* Never mind, see below. */
1874 typedef const Lang::Float ArgType;
1875 res->pushKerning( Helpers::try_cast_CoreArgument< ArgType >( args.getValue( i ) )->val_ );
1876 continue;
1878 catch( const NonLocalExit::NotThisType & ball )
1880 /* Never mind, see below. */
1885 typedef const Lang::KernedText ArgType;
1886 Helpers::try_cast_CoreArgument< ArgType >( args.getValue( i ) )->push( res.getPtr( ) );
1887 continue;
1889 catch( const NonLocalExit::NotThisType & ball )
1891 /* Never mind, see below. */
1894 throw Exceptions::CoreTypeMismatch( callLoc, id_, args, i, Helpers::typeSetString( Lang::String::staticTypeName( ), Lang::Float::staticTypeName( ), Lang::KernedText::staticTypeName( ) ) );
1897 Kernel::ContRef cont = evalState->cont_;
1898 cont->takeValue( res,
1899 evalState );
1903 class Core_automatickern : public Lang::CoreFunction
1905 public:
1906 Core_automatickern( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name ) : CoreFunction( ns, name ) { }
1907 virtual void
1908 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1910 iconv_t converter = Helpers::requireUTF8ToUCS4Converter( );
1911 iconv_t backconverter = Helpers::requireUCS4ToUTF8Converter( );
1913 RefCountPtr< const FontMetrics::FontMetric > metrics = evalState->dyn_->getTextState( )->font_->metrics( );
1914 if( metrics->horizontalMetrics_ == NullPtr< FontMetrics::WritingDirectionMetrics >( ) )
1916 throw Exceptions::FontMetricsError( evalState->dyn_->getTextState( )->font_->fontName( ), strrefdup( "No horizontal metrics defined." ) );
1919 // Note that res is _not_ yet const. We use a RefCountPtr to take care of memory deallocation in case some argument has the wrong type and
1920 // the result is not used.
1921 RefCountPtr< Lang::KernedText > res( new Lang::KernedText( evalState->dyn_->getTextState( ), evalState->dyn_->getGraphicsState( ) ) );
1923 std::ostringstream pendingChars;
1924 Kernel::UnicodeCodePoint prevChar( 0 );
1925 double pendingKerning = 0;
1927 const size_t backbufSize = 5;
1928 char backbuf[ backbufSize ];
1930 for( size_t i = 0; i != args.size( ); ++i )
1934 typedef const Lang::String ArgType;
1935 RefCountPtr< ArgType > str = Helpers::try_cast_CoreArgument< ArgType >( args.getValue( i ) );
1937 const char * inbuf = str->val_.getPtr( );
1938 size_t inbytesleft = strlen( inbuf );
1940 size_t bufSize = 4 * inbytesleft;
1941 char * buf = new char[ bufSize ];
1942 DeleteOnExit< char > bufDeleter( buf );
1944 char * outbuf = buf;
1945 size_t outbytesleft = bufSize;
1946 // The ICONV_CAST macro is defined in config.h.
1947 size_t count = iconv( converter,
1948 ICONV_CAST( & inbuf ), & inbytesleft,
1949 & outbuf, & outbytesleft );
1950 if( count == (size_t)(-1) )
1952 if( errno == EILSEQ )
1954 throw Exceptions::MiscellaneousRequirement( "It is suspected that one of the UFT-8 characters used in showed text has no UCS-4 representation." );
1956 else if( errno == EINVAL )
1958 throw Exceptions::MiscellaneousRequirement( "It is suspected that showed text ended with an incomplete multibyte character." );
1960 else if( errno == E2BIG )
1962 throw Exceptions::InternalError( "Core_automatickern: The buffer allocated for UTF-8 to UCS-4 conversion was too small." );
1964 else
1966 std::ostringstream msg;
1967 msg << "iconv failed with an unrecognized error code: " << errno ;
1968 throw Exceptions::InternalError( strrefdup( msg ) );
1971 for( const char * src = buf; src != outbuf; src += 4 )
1973 Kernel::UnicodeCodePoint currentChar;
1974 currentChar.decode_UCS4( src );
1975 double currentKerning = pendingKerning - metrics->getHorizontalKernPairXByCode( prevChar, currentChar );
1976 prevChar = currentChar;
1977 pendingKerning = 0;
1978 if( currentKerning != 0 )
1980 if( ! pendingChars.str( ).empty( ) )
1982 res->pushString( RefCountPtr< const Lang::String >( new Lang::String( strrefdup( pendingChars ) ) ) );
1983 pendingChars.str( "" );
1985 res->pushKerning( currentKerning );
1988 // Copy the current (multibyte) character to the character queue
1990 const char * inbuf = src;
1991 char * outbuf = backbuf;
1992 size_t inbytesleft = 4;
1993 size_t outbytesleft = backbufSize;
1994 // The ICONV_CAST macro is defined in config.h.
1995 size_t count = iconv( backconverter,
1996 ICONV_CAST( & inbuf ), & inbytesleft,
1997 & outbuf, & outbytesleft );
1998 if( count == (size_t)(-1) )
2000 if( errno == EILSEQ )
2002 throw Exceptions::ExternalError( "A character converted from UTF-8 could not be converted back to UFT-8." );
2004 else if( errno == EINVAL )
2006 throw Exceptions::ExternalError( "A character converted from UTF-8 was deemed incomplete." );
2008 else if( errno == E2BIG )
2010 throw Exceptions::InternalError( "The buffer allocated for conversion of a single character back to UTF-8 was too small." );
2012 else
2014 std::ostringstream msg;
2015 msg << "iconv failed with an unrecognized error code: " << errno ;
2016 throw Exceptions::InternalError( strrefdup( msg ) );
2019 *outbuf = '\0';
2020 pendingChars << backbuf ;
2023 continue;
2025 catch( const NonLocalExit::NotThisType & ball )
2027 /* Never mind, see below. */
2032 typedef const Lang::Float ArgType;
2033 pendingKerning += Helpers::try_cast_CoreArgument< ArgType >( args.getValue( i ) )->val_;
2034 continue;
2036 catch( const NonLocalExit::NotThisType & ball )
2038 /* Never mind, see below. */
2041 throw Exceptions::CoreTypeMismatch( callLoc, id_, args, i, Helpers::typeSetString( Lang::String::staticTypeName( ), Lang::Float::staticTypeName( ) ) );
2044 if( ! pendingChars.str( ).empty( ) )
2046 res->pushString( RefCountPtr< const Lang::String >( new Lang::String( strrefdup( pendingChars ) ) ) );
2047 pendingChars.str( "" );
2050 Kernel::ContRef cont = evalState->cont_;
2051 cont->takeValue( res,
2052 evalState );
2056 class Core_newrandom : public Lang::CoreFunction
2058 public:
2059 Core_newrandom( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name )
2060 : CoreFunction( ns, name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), true ) )
2062 formals_->appendEvaluatedCoreFormal( "seed", Kernel::THE_SLOT_VARIABLE );
2063 formals_->appendEvaluatedCoreFormal( "size", Helpers::newValHandle( new Lang::Integer( 32 ) ) );
2065 virtual void
2066 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
2068 args.applyDefaults( callLoc );
2070 typedef const Lang::Integer SizeType;
2071 Lang::Integer::ValueType sz = Helpers::down_cast_CoreArgument< SizeType >( id_, args, 1, callLoc )->val_;
2072 if( sz < 8 )
2074 throw Exceptions::CoreOutOfRange( id_, args, 1, "The size must be at least 8." );
2076 if( sz > 256 )
2078 throw Exceptions::CoreOutOfRange( id_, args, 1, "The size must at most 256." );
2081 size_t argsi = 0;
2085 typedef const Lang::ChronologicalTime SeedType;
2087 RefCountPtr< SeedType > seed = Helpers::try_cast_CoreArgument< SeedType >( args.getValue( argsi ) );
2089 Kernel::ContRef cont = evalState->cont_;
2090 cont->takeValue( RefCountPtr< const Lang::Value >( new Lang::HotRandomSeed( sz, seed->val( ) ) ),
2091 evalState );
2092 return;
2094 catch( const NonLocalExit::NotThisType & ball )
2096 /* Never mind, see below. */
2101 typedef const Lang::Integer SeedType;
2103 RefCountPtr< SeedType > seed = Helpers::try_cast_CoreArgument< SeedType >( args.getValue( argsi ) );
2105 Kernel::ContRef cont = evalState->cont_;
2106 cont->takeValue( RefCountPtr< const Lang::Value >( new Lang::HotRandomSeed( sz, seed->val_ ) ),
2107 evalState );
2108 return;
2110 catch( const NonLocalExit::NotThisType & ball )
2112 /* Never mind, see below. */
2115 throw Exceptions::CoreTypeMismatch( callLoc, id_, args, argsi, Helpers::typeSetString( Lang::Integer::staticTypeName( ), Lang::ChronologicalTime::staticTypeName( ) ) );
2119 class Core_devrandom : public Lang::CoreFunction
2121 public:
2122 Core_devrandom( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name )
2123 : CoreFunction( ns, name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), true ) )
2125 formals_->appendCoreStateFormal( "device" );
2126 formals_->appendEvaluatedCoreFormal( "size", Helpers::newValHandle( new Lang::Integer( 32 ) ) );
2128 virtual void
2129 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
2131 args.applyDefaults( callLoc );
2133 typedef const Lang::Integer SizeType;
2134 Lang::Integer::ValueType sz = Helpers::down_cast_CoreArgument< SizeType >( id_, args, 0, callLoc )->val_;
2135 if( sz < 8 )
2137 throw Exceptions::CoreOutOfRange( id_, args, 0, "The size must be at least 8." );
2139 if( sz > 256 )
2141 throw Exceptions::CoreOutOfRange( id_, args, 0, "The size must at most 256." );
2144 typedef Kernel::WarmRandomDevice GeneratorType;
2145 GeneratorType * gen = Helpers::down_cast_CoreState< GeneratorType >( id_, args, 0, callLoc );
2147 Kernel::ContRef cont = evalState->cont_;
2148 cont->takeValue( RefCountPtr< const Lang::Value >( new Lang::HotRandomSeed( static_cast< size_t >( sz ), gen ) ),
2149 evalState );
2153 class Core_destination : public Lang::CoreFunction
2155 public:
2156 Core_destination( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name )
2157 : CoreFunction( ns, name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), true ) )
2159 formals_->appendEvaluatedCoreFormal( "remote", Kernel::THE_FALSE_VARIABLE );
2160 formals_->appendEvaluatedCoreFormal( "name", Kernel::THE_VOID_VARIABLE );
2161 formals_->appendEvaluatedCoreFormal( "level", Kernel::THE_VOID_VARIABLE );
2162 formals_->appendEvaluatedCoreFormal( "text", Kernel::THE_VOID_VARIABLE );
2163 formals_->appendEvaluatedCoreFormal( "open", Kernel::THE_FALSE_VARIABLE );
2164 formals_->appendEvaluatedCoreFormal( "bold", Kernel::THE_FALSE_VARIABLE );
2165 formals_->appendEvaluatedCoreFormal( "italic", Kernel::THE_FALSE_VARIABLE );
2166 formals_->appendEvaluatedCoreFormal( "color", Helpers::newValHandle( new Lang::RGB( Concrete::RGB( 0, 0, 0 ) ) ) );
2167 formals_->appendEvaluatedCoreFormal( "sides", Kernel::THE_VOID_VARIABLE );
2168 formals_->appendEvaluatedCoreFormal( "target", Kernel::THE_VOID_VARIABLE );
2169 formals_->appendEvaluatedCoreFormal( "fittobbox", Kernel::THE_VOID_VARIABLE );
2170 formals_->appendEvaluatedCoreFormal( "zoom", Kernel::THE_VOID_VARIABLE );
2171 formals_->appendEvaluatedCoreFormal( "transform", Kernel::THE_TRUE_VARIABLE );
2173 virtual void
2174 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
2176 args.applyDefaults( callLoc );
2178 size_t argsi = 0;
2179 const size_t remove_i = argsi;
2180 typedef const Lang::Boolean RemoteType;
2181 bool remote = Helpers::down_cast_CoreArgument< RemoteType >( id_, args, argsi, callLoc )->val_;
2183 ++argsi;
2184 typedef const Lang::String NameType;
2185 RefCountPtr< NameType > nameVal = Helpers::down_cast_CoreArgument< NameType >( id_, args, argsi, callLoc, true );
2186 RefCountPtr< const char > name = RefCountPtr< const char >( NullPtr< const char >( ) );
2187 if( nameVal != NullPtr< NameType >( ) )
2189 const SimplePDF::PDF_Version::Version STRINGDESTS_VERSION = SimplePDF::PDF_Version::PDF_1_2;
2190 if( Kernel::the_PDF_version.greaterOrEqual( STRINGDESTS_VERSION ) )
2192 name = nameVal->val_;
2194 else
2196 Kernel::the_PDF_version.message( STRINGDESTS_VERSION, "The naming of a destination was ignored." );
2197 // Note that this will leave name being null, and hence generate further errors if remote_.
2200 if( nameVal == NullPtr< NameType >( ) ) // Note why this is not an else clause!
2202 if( remote )
2204 throw Exceptions::CoreOutOfRange( id_, args, remove_i, "The destination cannot be remote if no name is given." );
2208 ++argsi;
2209 const size_t outlineLevel_i = argsi;
2210 typedef const Lang::Integer OutlineLevelType;
2211 RefCountPtr< OutlineLevelType > levelVal = Helpers::down_cast_CoreArgument< OutlineLevelType >( id_, args, argsi, callLoc, true );
2212 int outlineLevel = -1; // This will remain negative only if the level is not present.
2213 if( levelVal != NullPtr< OutlineLevelType >( ) )
2215 outlineLevel = levelVal->val_;
2216 if( outlineLevel < 0 )
2218 throw Exceptions::CoreOutOfRange( id_, args, argsi, "The outline level must be non-negative." );
2222 ++argsi;
2223 typedef const Lang::String OutlineTextType;
2224 RefCountPtr< OutlineTextType > textVal = Helpers::down_cast_CoreArgument< OutlineTextType >( id_, args, argsi, callLoc, true );
2225 RefCountPtr< const char > outlineText = RefCountPtr< const char >( NullPtr< const char >( ) );
2226 if( textVal != NullPtr< OutlineTextType >( ) )
2228 outlineText = textVal->val_;
2230 else
2232 if( outlineLevel >= 0 )
2234 throw Exceptions::CoreOutOfRange( id_, args, outlineLevel_i, "Without an outline text, it is not allowed to make an outline item." );
2238 ++argsi;
2239 typedef const Lang::Boolean OutlineOpenType;
2240 bool outlineOpen = Helpers::down_cast_CoreArgument< OutlineOpenType >( id_, args, argsi, callLoc )->val_;
2242 ++argsi;
2243 typedef const Lang::Boolean OutlineBoldType;
2244 bool outlineBold = Helpers::down_cast_CoreArgument< OutlineBoldType >( id_, args, argsi, callLoc )->val_;
2246 ++argsi;
2247 typedef const Lang::Boolean OutlineItalicType;
2248 bool outlineItalic = Helpers::down_cast_CoreArgument< OutlineItalicType >( id_, args, argsi, callLoc )->val_;
2250 ++argsi;
2251 typedef const Lang::RGB OutlineColorType;
2252 Concrete::RGB outlineColor = Helpers::down_cast_CoreArgument< OutlineColorType >( id_, args, argsi, callLoc )->components( );
2254 ++argsi;
2255 const size_t sidesMode_i = argsi;
2256 typedef const Lang::Symbol SidesModeType;
2257 RefCountPtr< SidesModeType > sidesVal = Helpers::down_cast_CoreArgument< SidesModeType >( id_, args, argsi, callLoc, true );
2259 ++argsi;
2260 const size_t target_i = argsi;
2261 typedef const Lang::Drawable2D TargetType;
2262 RefCountPtr< TargetType > target = Helpers::down_cast_CoreArgument< TargetType >( id_, args, argsi, callLoc, true );
2264 Lang::DocumentDestination::Sides sides = Lang::DocumentDestination::PAGE; // Defaults to false, unless a target is given.
2265 if( target != NullPtr< TargetType >( ) )
2267 sides = Lang::DocumentDestination::TOPLEFT;
2268 if( remote )
2270 throw Exceptions::CoreOutOfRange( id_, args, target_i, "The target can not be specified for remote destinations." );
2273 static Lang::Symbol SIDES_TopLeft( "topleft" );
2274 static Lang::Symbol SIDES_Page( "page" );
2275 static Lang::Symbol SIDES_Top( "top" );
2276 static Lang::Symbol SIDES_Left( "left" );
2277 static Lang::Symbol SIDES_Rectangle( "rectangle" );
2278 if( sidesVal != NullPtr< SidesModeType >( ) )
2280 if( *sidesVal == SIDES_TopLeft )
2282 sides = Lang::DocumentDestination::TOPLEFT;
2284 else if( *sidesVal == SIDES_Page )
2286 if( target != NullPtr< TargetType >( ) )
2288 throw Exceptions::CoreOutOfRange( id_, args, sidesMode_i, "The sides mode cannot be page when a target object is present." );
2290 sides = Lang::DocumentDestination::PAGE;
2292 else if( *sidesVal == SIDES_Top )
2294 sides = Lang::DocumentDestination::TOP;
2296 else if( *sidesVal == SIDES_Left )
2298 sides = Lang::DocumentDestination::LEFT;
2300 else if( *sidesVal == SIDES_Rectangle )
2302 sides = Lang::DocumentDestination::RECTANGLE;
2304 else
2306 std::ostringstream oss;
2307 oss << "Valid sides modes are the symbols { "
2308 << SIDES_TopLeft.name( ).getPtr( ) << ", "
2309 << SIDES_Page.name( ).getPtr( ) << ", "
2310 << SIDES_Top.name( ).getPtr( ) << ", "
2311 << SIDES_Left.name( ).getPtr( ) << ", "
2312 << SIDES_Rectangle.name( ).getPtr( )
2313 << " }." ;
2314 throw Exceptions::CoreOutOfRange( id_, args, sidesMode_i, strrefdup( oss ) );
2318 ++argsi;
2319 typedef const Lang::Boolean FitToType;
2320 RefCountPtr< FitToType > fittobboxVal = Helpers::down_cast_CoreArgument< FitToType >( id_, args, argsi, callLoc, true );
2321 bool fittobbox = false;
2322 if( fittobboxVal != NullPtr< FitToType >( ) )
2324 if( remote || sides == Lang::DocumentDestination::TOPLEFT || sides == Lang::DocumentDestination::RECTANGLE )
2326 throw Exceptions::CoreOutOfRange( id_, args, argsi, "The fit-to-bbox flag cannot be specified in this mode." );
2328 fittobbox = fittobboxVal->val_;
2331 ++argsi;
2332 typedef const Lang::Float ZoomType;
2333 RefCountPtr< ZoomType > zoomVal = Helpers::down_cast_CoreArgument< ZoomType >( id_, args, argsi, callLoc, true );
2334 double zoom = 0; // This will remain zero only if the zoom argument is not specified.
2335 if( zoomVal != NullPtr< ZoomType >( ) )
2337 if( remote || sides != Lang::DocumentDestination::TOPLEFT )
2339 throw Exceptions::CoreOutOfRange( id_, args, argsi, "The zoom can only be specified when using the top-left sides." );
2341 zoom = zoomVal->val_;
2342 if( zoom <= 0 )
2344 throw Exceptions::CoreOutOfRange( id_, args, argsi, "The zoom value must be positive." );
2348 ++argsi;
2349 typedef const Lang::Boolean DoTransformType;
2350 bool doTransform = Helpers::down_cast_CoreArgument< DoTransformType >( id_, args, argsi, callLoc )->val_;
2352 Kernel::ContRef cont = evalState->cont_;
2353 if( remote )
2355 RefCountPtr< const Lang::DocumentDestination >
2356 taggedObj( new Lang::DocumentDestination( remote, name, outlineLevel,
2357 outlineText, outlineOpen, outlineBold, outlineItalic, outlineColor ) );
2358 cont->takeValue( RefCountPtr< const Lang::Value >
2359 ( new Lang::TaggedValue2D( Kernel::THE_NAVIGATION_SYMBOL, taggedObj ) ),
2360 evalState );
2362 else
2364 RefCountPtr< const Lang::DocumentDestination >
2365 taggedObj( new Lang::DocumentDestination( name, outlineLevel,
2366 outlineText, outlineOpen, outlineBold, outlineItalic, outlineColor,
2367 sides, target, fittobbox, zoom ) );
2368 if( doTransform )
2370 cont->takeValue( RefCountPtr< const Lang::Value >
2371 ( new Lang::TaggedGeometric2D( Kernel::THE_NAVIGATION_SYMBOL, taggedObj ) ),
2372 evalState );
2374 else
2376 cont->takeValue( RefCountPtr< const Lang::Value >
2377 ( new Lang::TaggedValue2D( Kernel::THE_NAVIGATION_SYMBOL, taggedObj ) ),
2378 evalState );
2384 class Core_importFont : public Lang::CoreFunction
2386 public:
2387 struct CacheKey
2389 bool outline_;
2390 RefCountPtr< const char > filename_;
2391 CacheKey( bool outline, const RefCountPtr< const char > & filename )
2392 : outline_( outline ), filename_( filename )
2394 ~CacheKey( )
2396 bool operator < ( const CacheKey & other ) const
2398 if( ! outline_ && other.outline_ )
2400 return true;
2402 if( outline_ && ! other.outline_ )
2404 return false;
2406 return strcmp( filename_.getPtr( ), other.filename_.getPtr( ) ) < 0;
2409 private:
2410 static std::map< CacheKey, RefCountPtr< const Lang::Value > > cache;
2411 public:
2412 Core_importFont( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name )
2413 : CoreFunction( ns, name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), true ) )
2415 formals_->appendEvaluatedCoreFormal( "family", Kernel::THE_SLOT_VARIABLE );
2416 formals_->appendEvaluatedCoreFormal( "style", Kernel::THE_VOID_VARIABLE );
2417 formals_->appendEvaluatedCoreFormal( "outline", Kernel::THE_FALSE_VARIABLE );
2419 virtual void
2420 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
2422 #ifndef HAVE_FT2
2423 throw Exceptions::BuildRequirement( Interaction::BUILD_REQ_FREETYPE, id_, callLoc );
2424 #else
2425 args.applyDefaults( callLoc );
2427 size_t argsi = 0;
2428 std::string full_filename;
2429 #ifndef HAVE_FONTCONFIG
2430 /* Here, it would be possible to allow the user to point out the font file directly instead of using FontConfig,
2431 * but currently there is no such option.
2433 throw Exceptions::BuildRequirement( Interaction::BUILD_REQ_FONTCONFIG, id_, callLoc );
2434 #else
2435 FcPattern * pat = FcPatternCreate( );
2436 Helpers::AutoDestroyFcPattern destroy_pat( pat );
2438 FcValue fc_fontformat;
2439 fc_fontformat.type = FcTypeString;
2440 fc_fontformat.u.s = reinterpret_cast< const FcChar8 * >( "TrueType" );
2441 FcPatternAdd( pat, "fontformat", fc_fontformat, FcFalse );
2443 size_t argsi_family = argsi;
2444 typedef const Lang::String ArgType;
2445 RefCountPtr< ArgType > family = Helpers::down_cast_CoreArgument< ArgType >( id_, args, argsi_family, callLoc );
2446 FcValue fc_family;
2447 fc_family.type = FcTypeString;
2448 fc_family.u.s = reinterpret_cast< const FcChar8 * >( family->val_.getPtr( ) );
2449 FcPatternAdd( pat, "family", fc_family, FcFalse );
2451 ++argsi;
2452 size_t argsi_style = argsi;
2453 RefCountPtr< ArgType > style = Helpers::down_cast_CoreArgument< ArgType >( id_, args, argsi_style, callLoc, true );
2454 FcValue fc_style;
2455 if( style != NullPtr< ArgType >( ) )
2457 fc_style.type = FcTypeString;
2458 fc_style.u.s = reinterpret_cast< const FcChar8 * >( style->val_.getPtr( ) );
2459 FcPatternAdd( pat, "style", fc_family, FcFalse );
2462 FcFontSet * sysFonts = FcConfigGetFonts( NULL, FcSetSystem );
2464 FcResult fc_res;
2466 FcDefaultSubstitute( pat );
2467 FcConfigSubstitute( NULL, pat, FcMatchPattern ); /* Not sure if FcMatchPattern is the correct value to pass here. There are two more possible values, and no documentation. See fontconfig/fontconfig.h. */
2468 FcPattern * match_res = FcFontSetMatch( NULL, & sysFonts, 1, pat, & fc_res );
2469 if( match_res == 0 )
2471 throw Exceptions::ExternalError( "FontConfig' FcFontSetMatch returned with failure." );
2473 Helpers::AutoDestroyFcPattern destroy_match_res( match_res );
2475 switch( fc_res )
2477 case FcResultMatch:
2478 // OK, just continue;
2479 break;
2480 case FcResultNoMatch:
2481 throw Exceptions::OutOfRange( callLoc, "FontConfig returned no matching font." );
2482 case FcResultOutOfMemory:
2483 throw Exceptions::ExternalError( "FontConfig got out of memory." );
2484 case FcResultTypeMismatch:
2485 // {
2486 // std::ostringstream msg;
2487 // msg << "Unexpected FcResult from FcFontSetMatch: " << "FcResultTypeMismatch" << " (ignored)." ;
2488 // WARN_OR_THROW( Exceptions::InternalError( strrefdup( msg ), true ) );
2489 // }
2490 break;
2491 case FcResultNoId:
2492 // {
2493 // std::ostringstream msg;
2494 // msg << "Unexpected FcResult from FcFontSetMatch: " << "FcResultNoId" << " (ignored)." ;
2495 // WARN_OR_THROW( Exceptions::InternalError( strrefdup( msg ), true ) );
2496 // }
2497 break;
2498 default:
2499 // {
2500 // std::ostringstream msg;
2501 // msg << "Unexpected FcResult from FcFontSetMatch: " << fc_res << " (ignored)." ;
2502 // WARN_OR_THROW( Exceptions::InternalError( strrefdup( msg ), true ) );
2503 // }
2504 // throw Exceptions::InternalError( "Unexpected FcResult from FcFontSetMatch." );
2505 break;
2507 // FcPatternPrint( match_res );
2509 FcChar8 * fc_tmp_string;
2510 switch( FcPatternGetString( match_res, "fontformat", 0, & fc_tmp_string ) )
2512 case FcResultMatch:
2513 // OK, just continue;
2514 break;
2515 case FcResultNoMatch:
2516 throw Exceptions::ExternalError( "FontConfig says that the font does not have a 'fontformat'." );
2517 case FcResultTypeMismatch:
2518 throw Exceptions::ExternalError( "FontConfig says 'fontformat' has the wrong type." );
2519 case FcResultNoId:
2520 throw Exceptions::ExternalError( "FontConfig says 'fontformat' is missing something." );
2521 case FcResultOutOfMemory:
2522 throw Exceptions::ExternalError( "FontConfig got out of memory." );
2524 if( strcmp( reinterpret_cast< const char * >( fc_tmp_string ), "TrueType" ) != 0 ) // This is OK, since "TrueType" is in the ASCII range.
2526 throw Exceptions::OutOfRange( callLoc, "Font file format not supported by Shapes, only TrueType is supported at the moment." );
2529 switch( FcPatternGetString( match_res, "file", 0, & fc_tmp_string ) )
2531 case FcResultMatch:
2532 // OK, just continue;
2533 break;
2534 case FcResultNoMatch:
2535 throw Exceptions::ExternalError( "FontConfig says that the font does not have a 'file' (filename)." );
2536 case FcResultTypeMismatch:
2537 throw Exceptions::ExternalError( "FontConfig says 'file' has the wrong type." );
2538 case FcResultNoId:
2539 throw Exceptions::ExternalError( "FontConfig says 'file' is missing something." );
2540 case FcResultOutOfMemory:
2541 throw Exceptions::ExternalError( "FontConfig got out of memory." );
2543 full_filename = reinterpret_cast< const char * >( fc_tmp_string ); /* Let us hope that this string is in the ASCII range! */
2544 #endif
2546 ++argsi;
2547 size_t argsi_outline = argsi;
2548 bool outline = Helpers::down_cast_CoreArgument< const Lang::Boolean >( id_, args, argsi_outline, callLoc )->val_;
2549 CacheKey cacheKey( outline, strrefdup( full_filename.c_str( ) ) );
2551 typedef typeof cache MapType;
2552 MapType::const_iterator i = cache.find( cacheKey );
2553 if( i != cache.end( ) )
2555 Kernel::ContRef cont = evalState->cont_;
2556 cont->takeValue( i->second,
2557 evalState );
2558 return;
2563 FT_Face face;
2565 FT_Error error = FT_New_Face( Kernel::theFreeType,
2566 full_filename.c_str( ),
2568 & face );
2569 if( error == FT_Err_Unknown_File_Format )
2571 throw Exceptions::ExternalError( "Font file format not supported by FreeType." );
2573 else if( error != 0 )
2575 std::ostringstream msg;
2576 msg << "FreeType failed to open " << full_filename << ", reason: " << Kernel::FreeTypeErrorMessage( error ) ;
2577 throw Exceptions::ExternalError( strrefdup( msg ) );
2580 const char * PostScriptName = FT_Get_Postscript_Name( face ); /* See comment on the next line! */
2581 std::ostringstream baseFontName; /* The PostScriptName pointer shall only be used as long as this object is in scope. */
2582 if( PostScriptName == 0 )
2584 for( const char * src = full_filename.c_str( ); *src != '\0'; ++src )
2586 if( *src == '.' )
2588 break;
2590 if( *src != ' ' )
2592 baseFontName << *src ;
2595 PostScriptName = baseFontName.str( ).c_str( );
2598 if( ! FT_IS_SFNT( face ) )
2600 throw Exceptions::OutOfRange( callLoc, "Font file format not supported by Shapes, only TrueType is supported at the moment." );
2602 if( ! outline )
2604 #ifdef HAVE_FT2_10
2605 FT_UShort fsType = FT_Get_FSType_Flags( face );
2606 if( ( fsType & ( FT_FSTYPE_INSTALLABLE_EMBEDDING |
2607 FT_FSTYPE_PREVIEW_AND_PRINT_EMBEDDING |
2608 FT_FSTYPE_EDITABLE_EMBEDDING ) )
2609 == 0 )
2611 std::ostringstream msg;
2612 msg << "The font " << PostScriptName << " does not permit embedding, and cannot be used with Shapes. Flags: " << std::hex << static_cast< int >( fsType ) << "." ;
2613 throw Exceptions::MiscellaneousRequirement( strrefdup( msg ) );
2615 #else
2616 throw Exceptions::MiscellaneousRequirement( strrefdup( "Shapes does not permit embedding of fonts, since your FreeType library is too old to provide licensing information about your fonts." ) );
2617 #endif
2620 FontMetrics::FreeType2_Metric * newMetrics = new FontMetrics::FreeType2_Metric( face );
2621 RefCountPtr< const FontMetrics::FontMetric > metrics = RefCountPtr< const FontMetrics::FontMetric >( newMetrics );
2623 RefCountPtr< SimplePDF::PDF_Dictionary > dic;
2624 RefCountPtr< SimplePDF::PDF_Object > resource = SimplePDF::indirect( dic, & Kernel::theIndirectObjectCount );
2625 (*dic)[ "Type" ] = SimplePDF::newName( "Font" );
2626 (*dic)[ "Subtype" ] = SimplePDF::newName( "Type0" );
2628 RefCountPtr< SimplePDF::PDF_Dictionary > descendant;
2629 RefCountPtr< SimplePDF::PDF_Vector > descendants;
2630 descendants->vec.push_back( descendant );
2631 (*dic)[ "DescendantFonts" ] = descendants;
2633 RefCountPtr< SimplePDF::PDF_ToUnicode::CharSet > usedChars;
2635 (*descendant)[ "Type" ] = SimplePDF::newName( "Font" );
2636 (*descendant)[ "Subtype" ] = SimplePDF::newName( "CIDFontType2" );
2638 RefCountPtr< SimplePDF::PDF_Name > fontName = RefCountPtr< SimplePDF::PDF_Name >( new SimplePDF::PDF_Name( PostScriptName ) );
2639 (*dic)[ "BaseFont" ] = fontName;
2640 (*descendant)[ "BaseFont" ] = fontName;
2641 (*dic)[ "Encoding" ] = SimplePDF::newName( "Identity-H" );
2642 (*descendant)[ "BaseFont" ] = fontName;
2644 RefCountPtr< SimplePDF::PDF_Dictionary > CIDSystemInfo;
2645 (*CIDSystemInfo)[ "Registry" ] = SimplePDF::newString( "Adobe" );
2646 (*CIDSystemInfo)[ "Ordering" ] = SimplePDF::newString( "Identity" );
2647 (*CIDSystemInfo)[ "Supplement" ] = SimplePDF::newString( "0" );
2648 (*descendant)[ "CIDSystemInfo" ] = CIDSystemInfo;
2649 (*descendant)[ "CIDToGIDMap" ] = SimplePDF::newName( "Identity" );
2651 (*descendant)[ "DW" ] = SimplePDF::newFloat( 0.7 * 1000 ); /* Default width. */
2653 RefCountPtr< SimplePDF::PDF_Dictionary > fontDescriptor;
2654 (*fontDescriptor)[ "Type" ] = SimplePDF::newName( "FontDescriptor" );
2655 (*fontDescriptor)[ "FontName" ] = fontName;
2656 (*fontDescriptor)[ "Flags" ] = SimplePDF::newInt( (size_t)(1) << ( 6 - 1 ) ); // This is the "Nonsymbolic" flag, although we don't know if it really is a non-symbolic font...
2657 (*fontDescriptor)[ "FontBBox" ] =
2658 RefCountPtr< SimplePDF::PDF_Vector >( new SimplePDF::PDF_Vector( newMetrics->fontBBoxXMin_ * 1000, newMetrics->fontBBoxYMin_ * 1000,
2659 newMetrics->fontBBoxXMax_ * 1000, newMetrics->fontBBoxYMax_ * 1000 ) );
2660 (*fontDescriptor)[ "ItalicAngle" ] = SimplePDF::newFloat( 0 );
2661 (*fontDescriptor)[ "Ascent" ] = SimplePDF::newFloat( 1 * 1000 );
2662 (*fontDescriptor)[ "Descent" ] = SimplePDF::newFloat( -0.5 * 1000 );
2664 RefCountPtr< SimplePDF::PDF_Stream_out > fontFile = RefCountPtr< SimplePDF::PDF_Stream_out >( new SimplePDF::PDF_Stream_out( ) );
2665 (*fontFile)[ "Filter" ] = SimplePDF::newName( "FlateDecode" );
2666 std::ifstream iFile( full_filename.c_str( ) );
2667 if( ! iFile.is_open( ) )
2669 throw Exceptions::FileReadOpenError( callLoc, strrefdup( full_filename ), 0, 0 );
2672 iFile.seekg( 0, std::ios::end );
2673 std::streamoff tmp = iFile.tellg( );
2674 std::streamsize size = tmp - static_cast< std::streamoff >( 0 );
2675 (*fontFile)[ "Length1" ] = SimplePDF::newInt( size );
2676 char * buf = new char[ size ];
2677 iFile.seekg( 0, std::ios::beg );
2678 iFile.read( buf, size );
2679 fontFile->data.write( buf, size );
2680 delete buf;
2682 (*fontDescriptor)[ "FontFile2" ] = SimplePDF::indirect( fontFile, & Kernel::theIndirectObjectCount );
2684 (*descendant)[ "FontDescriptor" ] = fontDescriptor;
2686 RefCountPtr< const Lang::Font > res = RefCountPtr< const Lang::Font >( new Lang::FreeTypeFont( face,
2687 newMetrics->fontName_,
2688 outline,
2689 resource,
2690 metrics,
2691 usedChars ) );
2692 RefCountPtr< SimplePDF::PDF_ToUnicode > toUnicode( new SimplePDF::PDF_ToUnicode( usedChars, res ) );
2693 (*dic)[ "ToUnicode" ] = SimplePDF::indirect( toUnicode, & Kernel::theIndirectObjectCount );
2694 RefCountPtr< SimplePDF::PDF_Widths > widths( new SimplePDF::PDF_Widths( usedChars, res ) );
2695 (*descendant)[ "W" ] = SimplePDF::indirect( widths, & Kernel::theIndirectObjectCount );
2698 typedef typeof cache MapType;
2699 cache.insert( MapType::value_type( cacheKey, res ) );
2701 Kernel::ContRef cont = evalState->cont_;
2702 cont->takeValue( res,
2703 evalState );
2704 #endif
2708 std::map< Core_importFont::CacheKey, RefCountPtr< const Lang::Value > > Core_importFont::cache;
2710 class Core_Unicode : public Lang::CoreFunction
2712 public:
2713 Core_Unicode( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name )
2714 : CoreFunction( ns, name )
2716 virtual void
2717 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
2719 const size_t ARITY = 1;
2720 CHECK_ARITY( args, ARITY, id_ );
2722 size_t argsi = 0;
2723 typedef const Lang::Integer ArgType;
2724 ArgType::ValueType arg = Helpers::down_cast_CoreArgument< ArgType >( id_, args, argsi, callLoc )->val_;
2725 if( arg < 0 )
2727 throw Exceptions::CoreOutOfRange( id_, args, argsi, "Unicode code points cannot be negative." );
2730 Kernel::ContRef cont = evalState->cont_;
2731 cont->takeValue( Kernel::ValueRef( new Lang::Character( arg ) ),
2732 evalState );
2736 class Core_AdobeGlyphList : public Lang::CoreFunction
2738 public:
2739 Core_AdobeGlyphList( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name )
2740 : CoreFunction( ns, name )
2742 virtual void
2743 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
2745 const size_t ARITY = 1;
2746 CHECK_ARITY( args, ARITY, id_ );
2748 size_t argsi = 0;
2749 typedef const Lang::Symbol ArgType;
2750 RefCountPtr< ArgType > arg = Helpers::down_cast_CoreArgument< ArgType >( id_, args, argsi, callLoc );
2751 if( arg->isUnique( ) )
2753 throw Exceptions::CoreOutOfRange( id_, args, argsi, "Unique symbols do not correspond to any glyphs." );
2755 FontMetrics::GlyphList::UnicodeType res;
2756 const FontMetrics::GlyphList & glyphList = Helpers::requireGlyphList( );
2757 if( ! glyphList.name_to_UCS4( arg->name( ).getPtr( ), & res ) )
2759 std::ostringstream msg;
2760 msg << "Unrecognized glyph name: " ;
2761 arg->show( msg );
2762 throw Exceptions::CoreOutOfRange( id_, args, argsi, strrefdup( msg ) );
2764 Kernel::ContRef cont = evalState->cont_;
2765 cont->takeValue( Kernel::ValueRef( new Lang::Character( res ) ),
2766 evalState );
2774 Lang::Core_range::Core_range( const RefCountPtr< const Ast::NamespacePath > & ns, const char * name )
2775 : CoreFunction( ns, name, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( name ), true ) )
2777 formals_->appendEvaluatedCoreFormal( "begin", Kernel::THE_VOID_VARIABLE );
2778 formals_->appendEvaluatedCoreFormal( "end", Kernel::THE_VOID_VARIABLE );
2779 formals_->appendEvaluatedCoreFormal( "step", Kernel::THE_VOID_VARIABLE );
2780 formals_->appendEvaluatedCoreFormal( "count", Kernel::THE_VOID_VARIABLE );
2783 void
2784 Lang::Core_range::call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
2786 RefCountPtr< const Interaction::CoreLocation > coreLoc( new Interaction::BoundLocation( id_ ) );
2787 makeRange( coreLoc, evalState, args, callLoc );
2790 void
2791 Lang::Core_range::makeRange( const RefCountPtr< const Interaction::CoreLocation > & coreLoc, Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc, bool isSpan, RefCountPtr< const Lang::Value > lastPtr )
2793 const size_t argsi_begin = 0;
2794 const size_t argsi_end = 1;
2795 const size_t argsi_step = 2;
2796 const size_t argsi_count = 3;
2798 typedef const Lang::Integer CountType;
2800 args.applyDefaults( callLoc );
2804 typedef const Lang::Integer ArgType;
2806 RefCountPtr< ArgType > beginPtr = Helpers::try_cast_CoreArgument< ArgType >( args.getValue( argsi_begin ), true );
2807 RefCountPtr< ArgType > endPtr = Helpers::down_cast_CoreArgument< ArgType >( coreLoc, args, argsi_end, callLoc, true );
2808 if( beginPtr == NullPtr< ArgType >( ) && endPtr == NullPtr< ArgType >( ) )
2810 throw Exceptions::CoreRequirement( "At least one of the arguments <begin> and <end> must be provided.", coreLoc, callLoc );
2812 RefCountPtr< ArgType > stepPtr = Helpers::down_cast_CoreArgument< ArgType >( coreLoc, args, argsi_step, callLoc, true );
2813 RefCountPtr< CountType > countPtr = Helpers::down_cast_CoreArgument< CountType >( coreLoc, args, argsi_count, callLoc, true );
2815 if( beginPtr != NullPtr< ArgType >( ) && endPtr != NullPtr< ArgType >( ) &&
2816 stepPtr != NullPtr< ArgType >( ) && countPtr != NullPtr< CountType >( ) )
2818 throw Exceptions::CoreRequirement( "At least one of the arguments must be omitted.", coreLoc, callLoc );
2821 ArgType::ValueType begin = 0;
2822 ArgType::ValueType step = 1;
2823 ArgType::ValueType last = isSpan ? lastPtr.down_cast< ArgType >( )->val_ : 0;
2824 size_t count = 0;
2826 if( stepPtr != NullPtr< ArgType >( ) )
2828 step = stepPtr->val_;
2830 if( countPtr != NullPtr< CountType >( ) )
2832 if( countPtr->val_ < 0 )
2834 throw Exceptions::CoreOutOfRange( coreLoc, args, argsi_count, "The <count> must not be negative." );
2836 count = countPtr->val_;
2839 if( beginPtr == NullPtr< ArgType >( ) )
2841 if( countPtr == NullPtr< CountType >( ) )
2843 if( isSpan )
2845 if( endPtr->val_ < 0 )
2847 throw Exceptions::CoreRequirement( "The <count> must be provided when constructing a span of integers and <begin> is omitted while <end> is negative.", coreLoc, callLoc );
2849 count = 1 + endPtr->val_ / step;
2851 else
2853 throw Exceptions::CoreRequirement( "The <count> must be provided when constructing a range of integers and <begin> is omitted.", coreLoc, callLoc );
2856 begin = endPtr->val_ - ( count - 1 ) * step;
2858 else if( endPtr == NullPtr< ArgType >( ) )
2860 begin = beginPtr->val_;
2861 if( countPtr == NullPtr< CountType >( ) )
2863 if( isSpan )
2865 if( last < begin )
2867 throw Exceptions::CoreRequirement( "The <count> must be provided when constructing a range of integers and <end> is omitted while <begin> exceeds %last.", coreLoc, callLoc );
2869 count = ( last - begin ) / step + 1;
2871 else
2873 throw Exceptions::CoreRequirement( "The <count> must be provided when constructing a range of integers and <end> is omitted.", coreLoc, callLoc );
2877 else
2879 if( countPtr != NullPtr< CountType >( ) )
2881 throw Exceptions::CoreRequirement( "It is an error to provide the <count> argument when constructing a range of integers from <begin> to <end>.", coreLoc, args.getLoc( argsi_count ) );
2884 begin = beginPtr->val_;
2885 if( ( endPtr->val_ >= begin && step <= 0 )
2887 ( endPtr->val_ <= begin && step >= 0 ) )
2889 throw Exceptions::CoreOutOfRange( coreLoc, args, argsi_step, "When <count> is omitted, the sign of <step> must agree with the order of <begin> and <end>." );
2891 count = 1 + ( endPtr->val_ - begin ) / step;
2894 Kernel::ContRef cont = evalState->cont_;
2895 if( count == 0 )
2897 cont->takeValue( Lang::THE_CONS_NULL,
2898 evalState );
2900 else
2902 cont->takeValue( RefCountPtr< const Lang::SingleList >( new Lang::SingleListRange< ArgType >( begin, step, count ) ),
2903 evalState );
2905 return;
2907 catch( const NonLocalExit::NotThisType & ball )
2909 /* Never mind, see below. */
2914 typedef const Lang::Float ArgType;
2916 RefCountPtr< ArgType > beginPtr = Helpers::try_cast_CoreArgument< ArgType >( args.getValue( argsi_begin ), true );
2917 RefCountPtr< ArgType > endPtr = Helpers::down_cast_CoreArgument< ArgType >( coreLoc, args, argsi_end, callLoc, true );
2918 if( beginPtr == NullPtr< ArgType >( ) && endPtr == NullPtr< ArgType >( ) )
2920 throw Exceptions::CoreRequirement( "At least one of the arguments <begin> and <end> must be provided.", coreLoc, callLoc );
2922 RefCountPtr< ArgType > stepPtr = Helpers::down_cast_CoreArgument< ArgType >( coreLoc, args, argsi_step, callLoc, true );
2923 RefCountPtr< CountType > countPtr = Helpers::down_cast_CoreArgument< CountType >( coreLoc, args, argsi_count, callLoc, true );
2925 if( beginPtr != NullPtr< ArgType >( ) && endPtr != NullPtr< ArgType >( ) &&
2926 stepPtr != NullPtr< ArgType >( ) && countPtr != NullPtr< CountType >( ) )
2928 throw Exceptions::CoreRequirement( "At least one of the arguments must be omitted.", coreLoc, callLoc );
2931 ArgType::ValueType begin = 0;
2932 ArgType::ValueType step = 1;
2933 ArgType::ValueType last = isSpan ? lastPtr.down_cast< ArgType >( )->val_ : 0;
2934 size_t count = 0;
2936 if( stepPtr != NullPtr< ArgType >( ) )
2938 step = stepPtr->val_;
2940 if( countPtr != NullPtr< CountType >( ) )
2942 if( countPtr->val_ < 0 )
2944 throw Exceptions::CoreOutOfRange( coreLoc, args, argsi_count, "The <count> must not be negative." );
2946 count = countPtr->val_;
2949 if( beginPtr == NullPtr< ArgType >( ) )
2951 if( countPtr == NullPtr< CountType >( ) )
2953 if( isSpan )
2955 if( endPtr->val_ < 0 )
2957 throw Exceptions::CoreRequirement( "The <count> must be provided when constructing a span of floats and <begin> is omitted while <end> is negative.", coreLoc, callLoc );
2959 count = 1 + static_cast< size_t >( endPtr->val_ / step );
2961 else
2963 throw Exceptions::CoreRequirement( "The <count> must be provided when constructing a range of floats and <begin> is omitted.", coreLoc, callLoc );
2966 begin = endPtr->val_ - ( count - 1 ) * step;
2968 else if( endPtr == NullPtr< ArgType >( ) )
2970 begin = beginPtr->val_;
2971 if( countPtr == NullPtr< CountType >( ) )
2973 if( isSpan )
2975 if( last < begin )
2977 throw Exceptions::CoreRequirement( "The <count> must be provided when constructing a range of floats and <end> is omitted while <begin> exceeds %last.", coreLoc, callLoc );
2979 count = 1 + static_cast< size_t >( ( last - begin ) / step );
2981 else
2983 throw Exceptions::CoreRequirement( "The <count> must be provided when constructing a range of floats and <end> is omitted.", coreLoc, callLoc );
2987 else
2989 begin = beginPtr->val_;
2990 // When we reach here, we know that at most one of <step> and <count> is provided.
2991 if( countPtr != NullPtr< CountType >( ) )
2993 if( count < 2 )
2995 throw Exceptions::CoreOutOfRange( coreLoc, args, argsi_count, "When <step> is omitted, the <count> be at least 2." );
2997 step = ( endPtr->val_ - begin ) / ( count - 1 );
2999 else
3001 /* If <step> is not provided, it defaults to 1, see above. */
3002 if( step == 0 )
3004 throw Exceptions::CoreOutOfRange( coreLoc, args, argsi_step, "When <count> is omitted, <step> must not be zero." );
3006 ArgType::ValueType tmpCount = 1 + ( endPtr->val_ - begin ) / step;
3007 if( tmpCount < 1 )
3009 count = 0;
3011 else
3013 if( tmpCount > std::numeric_limits< size_t >::max( ) )
3015 throw Exceptions::CoreOutOfRange( coreLoc, args, argsi_step, "When <count> is omitted, too small <step> values cause overflow in the number of elements." );
3017 count = static_cast< size_t >( tmpCount );
3022 Kernel::ContRef cont = evalState->cont_;
3023 if( count == 0 )
3025 cont->takeValue( Lang::THE_CONS_NULL,
3026 evalState );
3028 else
3030 cont->takeValue( RefCountPtr< const Lang::SingleList >( new Lang::SingleListRange< ArgType >( begin, step, count ) ),
3031 evalState );
3033 return;
3035 catch( const NonLocalExit::NotThisType & ball )
3037 /* Never mind, see below. */
3042 typedef const Lang::Length ArgType;
3044 RefCountPtr< ArgType > beginPtr = Helpers::try_cast_CoreArgument< ArgType >( args.getValue( argsi_begin ), true );
3045 RefCountPtr< ArgType > endPtr = Helpers::down_cast_CoreArgument< ArgType >( coreLoc, args, argsi_end, callLoc, true );
3046 if( beginPtr == NullPtr< ArgType >( ) && endPtr == NullPtr< ArgType >( ) )
3048 throw Exceptions::CoreRequirement( "At least one of the arguments <begin> and <end> must be provided.", coreLoc, callLoc );
3050 RefCountPtr< ArgType > stepPtr = Helpers::down_cast_CoreArgument< ArgType >( coreLoc, args, argsi_step, callLoc, true );
3051 RefCountPtr< CountType > countPtr = Helpers::down_cast_CoreArgument< CountType >( coreLoc, args, argsi_count, callLoc, true );
3053 if( beginPtr != NullPtr< ArgType >( ) && endPtr != NullPtr< ArgType >( ) &&
3054 stepPtr != NullPtr< ArgType >( ) && countPtr != NullPtr< CountType >( ) )
3056 throw Exceptions::CoreRequirement( "At least one of the arguments must be omitted.", coreLoc, callLoc );
3059 ArgType::ValueType begin = ArgType::ValueType( 0 );
3060 ArgType::ValueType step = ArgType::ValueType( 1 ); /* This is a "default" value that one is not allowed to use! */
3061 ArgType::ValueType last = isSpan ? lastPtr.down_cast< ArgType >( )->get( ) : Concrete::ZERO_LENGTH;
3062 size_t count = 0;
3064 if( stepPtr != NullPtr< ArgType >( ) )
3066 step = stepPtr->get( );
3068 if( countPtr != NullPtr< CountType >( ) )
3070 if( countPtr->val_ < 0 )
3072 throw Exceptions::CoreOutOfRange( coreLoc, args, argsi_count, "The <count> must not be negative." );
3074 count = countPtr->val_;
3077 if( beginPtr == NullPtr< ArgType >( ) )
3079 if( stepPtr == NullPtr< ArgType >( ) )
3081 throw Exceptions::CoreRequirement( "The <step> must be provided when constructing a range of lengths when <begin> is omitted.", coreLoc, callLoc );
3083 if( countPtr == NullPtr< CountType >( ) )
3085 if( isSpan )
3087 if( endPtr->get( ) < Concrete::ZERO_LENGTH )
3089 throw Exceptions::CoreRequirement( "The <count> must be provided when constructing a span of lengths and <begin> is omitted while <end> is negative.", coreLoc, callLoc );
3091 count = 1 + static_cast< size_t >( endPtr->get( ) / step );
3093 else
3095 throw Exceptions::CoreRequirement( "The <count> must be provided when constructing a range of lengths and <begin> is omitted.", coreLoc, callLoc );
3098 begin = endPtr->get( ) - ( count - 1 ) * step;
3100 else if( endPtr == NullPtr< ArgType >( ) )
3102 begin = beginPtr->get( );
3103 if( stepPtr == NullPtr< ArgType >( ) )
3105 throw Exceptions::CoreRequirement( "The <step> must be provided when constructing a range of lengths when <end> is omitted.", coreLoc, callLoc );
3107 if( countPtr == NullPtr< CountType >( ) )
3109 if( isSpan )
3111 if( last < begin )
3113 throw Exceptions::CoreRequirement( "The <count> must be provided when constructing a range of lengths and <end> is omitted while <begin> exceeds %last.", coreLoc, callLoc );
3115 count = static_cast< size_t >( ( last - begin ) / step ) + 1;
3117 else
3119 throw Exceptions::CoreRequirement( "The <count> must be provided when constructing a range of lengths and <end> is omitted.", coreLoc, callLoc );
3123 else
3125 begin = beginPtr->get( );
3126 if( stepPtr == NullPtr< ArgType >( ) && countPtr == NullPtr< CountType >( ) )
3128 throw Exceptions::CoreRequirement( "Either of the <step> and <count> arguments must be provided when constructing a range of lengths from <begin> to <end>.", coreLoc, callLoc );
3130 // When we reach here, we know that exactly one of <step> and <count> is provided.
3131 if( stepPtr != NullPtr< ArgType >( ) )
3133 if( step == 0 )
3135 throw Exceptions::CoreOutOfRange( coreLoc, args, argsi_step, "When <count> is omitted, <step> must not be zero." );
3137 double tmpCount = 1 + ( endPtr->get( ) - begin ) / step;
3138 if( tmpCount < 1 )
3140 count = 0;
3142 else
3144 if( tmpCount > std::numeric_limits< size_t >::max( ) )
3146 throw Exceptions::CoreOutOfRange( coreLoc, args, argsi_step, "When <count> is omitted, too small <step> values cause overflow in the number of elements." );
3148 count = static_cast< size_t >( tmpCount );
3151 else
3153 if( count < 2 )
3155 throw Exceptions::CoreOutOfRange( coreLoc, args, argsi_count, "When <step> is omitted, the <count> be at least 2." );
3157 step = ( endPtr->get( ) - begin ) / ( count - 1 );
3161 Kernel::ContRef cont = evalState->cont_;
3162 if( count == 0 )
3164 cont->takeValue( Lang::THE_CONS_NULL,
3165 evalState );
3167 else
3169 cont->takeValue( RefCountPtr< const Lang::SingleList >( new Lang::SingleListRange< ArgType >( begin, step, count ) ),
3170 evalState );
3172 return;
3174 catch( const NonLocalExit::NotThisType & ball )
3176 /* Never mind, see below. */
3179 throw Exceptions::CoreTypeMismatch( callLoc, coreLoc, args, 0, Helpers::typeSetString( Lang::Integer::staticTypeName( ), Lang::Float::staticTypeName( ), Lang::Length::staticTypeName( ) ) );
3183 Kernel::Core_graph_cont_partitions::Core_graph_cont_partitions( RefCountPtr< const Lang::Value > nodes, const Ast::SourceLocation & nodesLoc, RefCountPtr< const Lang::Value > edges, const Ast::SourceLocation & edgesLoc, RefCountPtr< const Kernel::GraphDomain > domain, const Kernel::ContRef & cont, const Ast::SourceLocation & partitionsLoc )
3184 : Kernel::Continuation( partitionsLoc ), nodes_( nodes ), nodesLoc_( nodesLoc ), edges_( edges ), edgesLoc_( edgesLoc ), domain_( domain ), cont_( cont )
3187 Kernel::Core_graph_cont_partitions::~Core_graph_cont_partitions( )
3190 void
3191 Kernel::Core_graph_cont_partitions::takeValue( const RefCountPtr< const Lang::Value > & partitionsUntyped, Kernel::EvalState * evalState, bool dummy ) const
3193 typedef const Lang::SingleList ArgType;
3194 RefCountPtr< ArgType > partitions = Helpers::down_cast< ArgType >( partitionsUntyped, "< Internal error situation in Core_graph_cont_partitions >" );
3196 evalState->cont_ = Kernel::ContRef( new Kernel::ForcingListContinuation
3197 ( Kernel::ContRef( new Kernel::Core_graph_cont_nodes( edges_, edgesLoc_, domain_, partitions, cont_, traceLoc_, nodesLoc_ ) ),
3198 nodesLoc_,
3199 true ) );
3200 Kernel::ContRef cont = evalState->cont_;
3201 cont->takeValue( nodes_, evalState );
3204 Kernel::ContRef
3205 Kernel::Core_graph_cont_partitions::up( ) const
3207 return cont_;
3210 RefCountPtr< const char >
3211 Kernel::Core_graph_cont_partitions::description( ) const
3213 return strrefdup( "force list of partitions data" );
3216 void
3217 Kernel::Core_graph_cont_partitions::gcMark( Kernel::GCMarkedSet & marked )
3219 const_cast< Lang::Value * >( nodes_.getPtr( ) )->gcMark( marked );
3220 const_cast< Lang::Value * >( edges_.getPtr( ) )->gcMark( marked );
3221 cont_->gcMark( marked );
3225 Kernel::Core_graph_cont_nodes::Core_graph_cont_nodes( RefCountPtr< const Lang::Value > edges, const Ast::SourceLocation & edgesLoc, RefCountPtr< const Kernel::GraphDomain > domain, const RefCountPtr< const Lang::SingleList > & partitions, const Kernel::ContRef & cont, const Ast::SourceLocation & partitionsLoc, const Ast::SourceLocation & nodesLoc )
3226 : Kernel::Continuation( nodesLoc ), edges_( edges ), edgesLoc_( edgesLoc ), domain_( domain ), partitions_( partitions ), partitionsLoc_( partitionsLoc ), cont_( cont )
3229 Kernel::Core_graph_cont_nodes::~Core_graph_cont_nodes( )
3232 void
3233 Kernel::Core_graph_cont_nodes::takeValue( const RefCountPtr< const Lang::Value > & nodesUntyped, Kernel::EvalState * evalState, bool dummy ) const
3235 typedef const Lang::SingleList ArgType;
3236 RefCountPtr< ArgType > nodes = Helpers::down_cast< ArgType >( nodesUntyped, "< Internal error situation in Core_graph_cont_nodes >" );
3238 evalState->cont_ = Kernel::ContRef( new Kernel::ForcingListContinuation
3239 ( Kernel::ContRef( new Kernel::Core_graph_cont_edges( nodes, domain_, partitions_, cont_, traceLoc_, partitionsLoc_, edgesLoc_ ) ),
3240 edgesLoc_,
3241 true ) );
3242 Kernel::ContRef cont = evalState->cont_;
3243 cont->takeValue( edges_, evalState );
3246 Kernel::ContRef
3247 Kernel::Core_graph_cont_nodes::up( ) const
3249 return cont_;
3252 RefCountPtr< const char >
3253 Kernel::Core_graph_cont_nodes::description( ) const
3255 return strrefdup( "force list of node data" );
3258 void
3259 Kernel::Core_graph_cont_nodes::gcMark( Kernel::GCMarkedSet & marked )
3261 const_cast< Lang::Value * >( edges_.getPtr( ) )->gcMark( marked );
3262 cont_->gcMark( marked );
3266 Kernel::Core_graph_cont_edges::Core_graph_cont_edges( RefCountPtr< const Lang::SingleList > nodes, RefCountPtr< const Kernel::GraphDomain > domain, const RefCountPtr< const Lang::SingleList > & partitions, const Kernel::ContRef & cont, const Ast::SourceLocation & nodesLoc, const Ast::SourceLocation & partitionsLoc, const Ast::SourceLocation & edgesLoc )
3267 : Kernel::Continuation( edgesLoc ), nodes_( nodes ), domain_( domain ), partitions_( partitions ), nodesLoc_( nodesLoc ), partitionsLoc_( partitionsLoc ), cont_( cont )
3270 Kernel::Core_graph_cont_edges::~Core_graph_cont_edges( )
3273 void
3274 Kernel::Core_graph_cont_edges::takeValue( const RefCountPtr< const Lang::Value > & edgesUntyped, Kernel::EvalState * evalState, bool dummy ) const
3276 typedef const Lang::SingleList ArgType;
3277 RefCountPtr< ArgType > edges = Helpers::down_cast< ArgType >( edgesUntyped, "< Internal error situation in Core_graph_cont_edges >" );
3279 RefCountPtr< const Lang::Graph > graph = constructGraph( edges, evalState->env_, evalState->dyn_ );
3281 evalState->cont_ = cont_;
3282 cont_->takeValue( graph,
3283 evalState );
3286 Kernel::ContRef
3287 Kernel::Core_graph_cont_edges::up( ) const
3289 return cont_;
3292 RefCountPtr< const char >
3293 Kernel::Core_graph_cont_edges::description( ) const
3295 return strrefdup( "force list of edge data" );
3298 void
3299 Kernel::Core_graph_cont_edges::gcMark( Kernel::GCMarkedSet & marked )
3301 const_cast< Lang::SingleList * >( nodes_.getPtr( ) )->gcMark( marked );
3302 cont_->gcMark( marked );
3305 namespace Shapes
3307 namespace Kernel
3310 NodeDataReceiverFormals theNodeDataReceiverFormals;
3311 EdgeDataReceiverFormals theEdgeDataReceiverFormals;
3316 RefCountPtr< const Lang::Graph >
3317 Kernel::Core_graph_cont_edges::constructGraph( const RefCountPtr< const Lang::SingleList > & edges, Kernel::PassedEnv env, Kernel::PassedDyn dyn ) const
3319 std::list< Kernel::NodeData > nodeData;
3320 std::list< Kernel::EdgeData > edgeData;
3323 RefCountPtr< const Lang::SingleListPair > p = nodes_.down_cast< const Lang::SingleListPair >( );
3324 while( p != NullPtr< const Lang::SingleListPair >( ) ){
3325 RefCountPtr< const Lang::Value > key = RefCountPtr< const Lang::Value >( NullPtr< const Lang::Value >( ) );
3326 RefCountPtr< const Lang::Value > value = Lang::THE_VOID;
3327 RefCountPtr< const Lang::Value > partition = Lang::THE_VOID;
3331 key = p->car_->tryVal< const Lang::Symbol >( );
3332 goto keyDone;
3334 catch( const NonLocalExit::NotThisType & ball )
3336 /* Never mind, see below. */
3341 key = p->car_->tryVal< const Lang::Integer >( );
3342 goto keyDone;
3344 catch( const NonLocalExit::NotThisType & ball )
3346 /* Never mind, see below. */
3351 RefCountPtr< const Lang::Structure > node = p->car_->tryVal< const Lang::Structure >( );
3352 /* Argument 0: key
3353 * Argument 1: value
3354 * Argument 2: partition
3356 Kernel::Arguments args( & theNodeDataReceiverFormals );
3357 node->argList_->bind( & args, node->values_, env, dyn );
3358 args.applyDefaults( nodesLoc_ );
3359 key = args.getValue( 0 );
3360 value = args.getValue( 1 );
3361 partition = args.getValue( 2 );
3362 goto keyDone;
3364 catch( const NonLocalExit::NotThisType & ball )
3366 /* Never mind, see below. */
3369 throw Exceptions::TypeMismatch( traceLoc_, "Node element in graph construction", p->car_->getUntyped( )->getTypeName( ), Exceptions::GraphKeyTypeMismatch::expectedTypeOrStructure );
3371 keyDone:
3372 nodeData.push_back( Kernel::NodeData( key, value, partition ) );
3373 p = p->cdr_.down_cast< const Lang::SingleListPair >( );
3378 RefCountPtr< const Lang::SingleListPair > p = edges.down_cast< const Lang::SingleListPair >( );
3379 while( p != NullPtr< const Lang::SingleListPair >( ) ){
3380 RefCountPtr< const Lang::Structure > edge = p->car_->getVal< const Lang::Structure >( "EdgeData for graph construction." );
3381 /* Argument 0: source
3382 * Argument 1: target
3383 * Argument 2: value
3384 * Argument 3: directed
3386 Kernel::Arguments args( & theEdgeDataReceiverFormals );
3387 edge->argList_->bind( & args, edge->values_, env, dyn );
3388 args.applyDefaults( traceLoc_ );
3389 bool directed;
3391 RefCountPtr< const Lang::Boolean > directedBoolean = args.getValue( 4 ).down_cast< const Lang::Boolean >( );
3392 if( directedBoolean != NullPtr< const Lang::Boolean >( ) ){
3393 directed = directedBoolean->val_;
3394 }else{
3395 RefCountPtr< const Lang::Void > directedVoid = args.getValue( 4 ).down_cast< const Lang::Void >( );
3396 if( directedVoid != NullPtr< const Lang::Void >( ) ){
3397 if( domain_->directed( ) && not domain_->undirected( ) )
3398 directed = true;
3399 else if( not domain_->directed( ) && domain_->undirected( ) )
3400 directed = false;
3401 else
3402 throw Exceptions::MiscellaneousRequirement( traceLoc_, "The EdgeData field 'directed' must be specified since the graph domain does not determine a default interpretation." );
3403 }else{
3404 throw Exceptions::TypeMismatch( traceLoc_, "EdgeData field 'directed'.", args.getValue( 3 )->getTypeName( ), Helpers::typeSetString( Lang::Boolean::staticTypeName( ), Lang::Void::staticTypeName( ) ) );
3409 RefCountPtr< const Lang::Value > sourceKey = args.getValue( 0 );
3410 RefCountPtr< const Lang::Value > targetKey = args.getValue( 1 );
3411 RefCountPtr< const Lang::Value > value = args.getValue( 2 );
3412 RefCountPtr< const Lang::Value > label = args.getValue( 3 );
3413 edgeData.push_back( Kernel::EdgeData( directed, sourceKey, targetKey, value, label ) );
3414 p = p->cdr_.down_cast< const Lang::SingleListPair >( );
3418 return Helpers::graphFromNodeEdgeData( *domain_, partitions_, nodeData, edgeData, partitionsLoc_, traceLoc_ );
3422 Kernel::Core_walk_cont_edges::Core_walk_cont_edges( const RefCountPtr< const Lang::Graph > & graph, const RefCountPtr< const Lang::Node > & first, const RefCountPtr< const Lang::Node > & last, const Ast::SourceLocation & edgesLoc, const Kernel::ContRef & cont, const Ast::SourceLocation & callLoc )
3423 : Kernel::Continuation( edgesLoc ), graph_( graph ), first_( first ), last_( last ), callLoc_( callLoc ), cont_( cont )
3426 Kernel::Core_walk_cont_edges::~Core_walk_cont_edges( )
3429 void
3430 Kernel::Core_walk_cont_edges::takeValue( const RefCountPtr< const Lang::Value > & edgesUntyped, Kernel::EvalState * evalState, bool dummy ) const
3432 typedef const Lang::SingleList ArgType;
3433 RefCountPtr< ArgType > edges = Helpers::down_cast< ArgType >( edgesUntyped, "< Internal error situation in Core_walk_cont_edges >" );
3435 RefCountPtr< const Lang::Walk > walk( new Lang::Walk( graph_, first_, last_, edges, traceLoc_, callLoc_ ) );
3437 evalState->cont_ = cont_;
3438 cont_->takeValue( walk,
3439 evalState );
3442 Kernel::ContRef
3443 Kernel::Core_walk_cont_edges::up( ) const
3445 return cont_;
3448 RefCountPtr< const char >
3449 Kernel::Core_walk_cont_edges::description( ) const
3451 return strrefdup( "force list of walk edges" );
3454 void
3455 Kernel::Core_walk_cont_edges::gcMark( Kernel::GCMarkedSet & marked )
3457 const_cast< Lang::Graph * >( graph_.getPtr( ) )->gcMark( marked );
3458 const_cast< Lang::Node * >( first_.getPtr( ) )->gcMark( marked );
3459 const_cast< Lang::Node * >( last_.getPtr( ) )->gcMark( marked );
3460 cont_->gcMark( marked );
3465 * To avoid problems with initialization order (Kernel::THE_VOID_VARIABLE has to be initialized first), we first
3466 * initialize with an ugly null value, and then set the correct value when the real function is registered below.
3468 RefCountPtr< const Lang::CoreFunction > Lang::THE_FUNCTION_RANGE = RefCountPtr< const Lang::CoreFunction >( NullPtr< const Lang::CoreFunction >( ) );
3470 void
3471 Kernel::registerCore_construct( Kernel::Environment * env )
3473 Lang::THE_FUNCTION_RANGE = RefCountPtr< const Lang::CoreFunction >( new Lang::Core_range( Lang::THE_NAMESPACE_Shapes_Data, "range" ) );
3475 env->initDefineCoreFunction( new Lang::Core_cons( Lang::THE_NAMESPACE_Shapes_Data, "cons" ) );
3476 env->initDefineCoreFunction( new Lang::Core_list( Lang::THE_NAMESPACE_Shapes_Data, "list" ) );
3477 env->initDefineCoreFunction( new Lang::Core_unlist( Lang::THE_NAMESPACE_Shapes_Data, "unlist" ) );
3478 env->initDefineCoreFunction( new Lang::Core_isnil( Lang::THE_NAMESPACE_Shapes_Data, "nil?" ) );
3479 env->initDefineCoreFunction( Lang::THE_FUNCTION_RANGE );
3480 env->initDefineCoreFunction( new Lang::Core_span( Lang::THE_NAMESPACE_Shapes_Data, "span" ) );
3481 env->initDefineCoreFunction( new Lang::Core_shift( Lang::THE_NAMESPACE_Shapes_Geometry, "shift" ) );
3482 env->initDefineCoreFunction( new Lang::Core_shift3d( Lang::THE_NAMESPACE_Shapes_Geometry3D, "shift" ) );
3483 env->initDefineCoreFunction( new Lang::Core_rotate( Lang::THE_NAMESPACE_Shapes_Geometry, "rotate" ) );
3484 env->initDefineCoreFunction( new Lang::Core_rotate3d( Lang::THE_NAMESPACE_Shapes_Geometry3D, "rotate" ) );
3485 env->initDefineCoreFunction( new Lang::Core_scale( Lang::THE_NAMESPACE_Shapes_Geometry, "scale" ) );
3486 env->initDefineCoreFunction( new Lang::Core_scale3d( Lang::THE_NAMESPACE_Shapes_Geometry3D, "scale" ) );
3487 env->initDefineCoreFunction( new Lang::Core_affinetransform( Lang::THE_NAMESPACE_Shapes_Geometry, "affinetransform" ) );
3488 env->initDefineCoreFunction( new Lang::Core_affinetransform3d( Lang::THE_NAMESPACE_Shapes_Geometry3D, "affinetransform" ) );
3489 env->initDefineCoreFunction( new Lang::Core_inverse( Lang::THE_NAMESPACE_Shapes_Geometry, "inverse" ) );
3490 env->initDefineCoreFunction( new Lang::Core_inverse3d( Lang::THE_NAMESPACE_Shapes_Geometry3D, "inverse" ) );
3492 env->initDefineCoreFunction( new Lang::Core_formxo( Lang::THE_NAMESPACE_Shapes_Graphics_PDF, "formxo" ) );
3493 env->initDefineCoreFunction( new Lang::Core_importRasterImage( Lang::THE_NAMESPACE_Shapes_Graphics, "import_raster" ) );
3494 env->initDefineCoreFunction( new Lang::Core_transparencygroup( Lang::THE_NAMESPACE_Shapes_Graphics, "tgroup" ) );
3496 env->initDefineCoreFunction( new Lang::Core_tag( Lang::THE_NAMESPACE_Shapes_Graphics_Tag, "tag" ) );
3497 env->initDefineCoreFunction( new Lang::Core_find( Lang::THE_NAMESPACE_Shapes_Graphics_Tag, "find" ) );
3498 env->initDefineCoreFunction( new Lang::Core_findall( Lang::THE_NAMESPACE_Shapes_Graphics_Tag, "findall" ) );
3500 env->initDefineCoreFunction( new Lang::Core_ambient_light( Lang::THE_NAMESPACE_Shapes_Traits_Light, "ambient_light" ) );
3501 env->initDefineCoreFunction( new Lang::Core_specular_light( Lang::THE_NAMESPACE_Shapes_Traits_Light, "specular_light" ) );
3502 env->initDefineCoreFunction( new Lang::Core_distant_light( Lang::THE_NAMESPACE_Shapes_Traits_Light, "distant_light" ) );
3503 env->initDefineCoreFunction( new Lang::Core_phong( Lang::THE_NAMESPACE_Shapes_Traits_Light, "phong" ) );
3505 env->initDefineCoreFunction( new Lang::Core_vector( Lang::THE_NAMESPACE_Shapes_Data, "vector" ) );
3506 env->initDefineCoreFunction( new Lang::Core_graph( Lang::THE_NAMESPACE_Shapes_Data, "graph" ) );
3507 env->initDefineCoreFunction( new Lang::Core_walk( Lang::THE_NAMESPACE_Shapes_Data, "walk" ) );
3508 env->initDefineCoreFunction( new Lang::Core_importPDFpages( Lang::THE_NAMESPACE_Shapes_Graphics, "import" ) );
3510 env->initDefineCoreFunction( new Lang::Core_svg_path( Lang::THE_NAMESPACE_Shapes_Geometry, "svg_path" ) );
3512 env->initDefineCoreFunction( new Lang::Core_sprintf( Lang::THE_NAMESPACE_Shapes_String, "sprintf" ) );
3513 env->initDefineCoreFunction( new Lang::Core_strftime( Lang::THE_NAMESPACE_Shapes_String, "strftime" ) );
3515 env->initDefineCoreFunction( new Lang::Core_newrandom( Lang::THE_NAMESPACE_Shapes_Numeric_Random, "newRandom" ) );
3516 env->initDefineCoreFunction( new Lang::Core_devrandom( Lang::THE_NAMESPACE_Shapes_Numeric_Random, "devRandom" ) );
3518 env->initDefineCoreFunction( new Lang::Core_destination( Lang::THE_NAMESPACE_Shapes_Graphics_PDF, "destination" ) );
3520 env->initDefineCoreFunction( new Lang::Core_textrenderingmode( Lang::THE_NAMESPACE_Shapes_Text, "textmode" ) );
3521 env->initDefineCoreFunction( new Lang::Core_manualkern( Lang::THE_NAMESPACE_Shapes_Text, "kerning" ) );
3522 env->initDefineCoreFunction( new Lang::Core_automatickern( Lang::THE_NAMESPACE_Shapes_Text, "kern" ) );
3524 env->initDefineCoreFunction( new Lang::Core_importFont( Lang::THE_NAMESPACE_Shapes_Text, "font" ) );
3526 env->initDefineCoreFunction( new Lang::Core_Unicode( Lang::THE_NAMESPACE_Shapes_String, "Unicode" ) );
3527 env->initDefineCoreFunction( new Lang::Core_AdobeGlyphList( Lang::THE_NAMESPACE_Shapes_String, "AdobeGlyphList" ) );