Update procedures
[shapes.git] / source / elementarytypes.cc
blob078d3e60b94b67b9c4f39e9933006c259d46d3b9
1 /* This file is part of Shapes.
3 * Shapes is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * any later version.
8 * Shapes is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with Shapes. If not, see <http://www.gnu.org/licenses/>.
16 * Copyright 2008, 2013, 2014 Henrik Tidefelt
19 #include <cmath>
21 #include "shapestypes.h"
22 #include "shapesexceptions.h"
23 #include "astexpr.h"
24 #include "consts.h"
25 #include "angleselect.h"
26 #include "astvar.h"
27 #include "astclass.h"
28 #include "elementarycoords.h"
29 #include "globals.h"
30 #include "singlelistrange.h"
31 #include "continuations.h"
32 #include "methodbase.h"
34 #include <ctype.h>
35 #include <stack>
37 using namespace Shapes;
38 using namespace std;
41 Lang::Symbol::NameTableType Lang::Symbol::nameTable;
42 Lang::Symbol::ReverseTableType Lang::Symbol::reverseTable;
43 int Lang::Symbol::nextUnique = -1;
45 /* The following global variables used to be in globals.cc, but now they are here to ensure they get initialized after the static variables in Lang::Symbol.
47 RefCountPtr< const Lang::Symbol > Kernel::THE_NAVIGATION_SYMBOL( ".navigation" ); /* Note that the leading dot puts this symbol aside all user-symbols. */
48 RefCountPtr< const Lang::Symbol > Kernel::THE_ANNOTATION_SYMBOL( ".annotation" ); /* Note that the leading dot puts this symbol aside all user-symbols. */
50 Lang::Symbol::Symbol( )
52 key_ = nextUnique;
53 --nextUnique;
56 DISPATCHIMPL( Symbol );
58 Lang::Symbol::Symbol( int key )
60 if( key != 0 )
62 throw Exceptions::InternalError( "Only the key 0 may be used when creating symbols with a given key." );
64 key_ = 0;
67 Lang::Symbol::Symbol( const char * name )
69 NameTableType::const_iterator i = nameTable.find( name );
70 if( i != nameTable.end( ) )
72 key_ = i->second;
74 else
76 const char * nameCopy = strdup( name );
77 key_ = nameTable.size( ) + 1;
78 nameTable[ nameCopy ] = key_;
79 reverseTable.insert( ReverseTableType::value_type( key_, RefCountPtr< const char >( nameCopy ) ) );
83 bool
84 Lang::Symbol::operator == ( const Symbol & other ) const
86 return key_ == other.key_;
89 bool
90 Lang::Symbol::operator != ( const Symbol & other ) const
92 return key_ != other.key_;
95 bool
96 Lang::Symbol::operator < ( const Symbol & other ) const
98 return key_ < other.key_;
101 bool
102 Lang::Symbol::operator > ( const Symbol & other ) const
104 return key_ > other.key_;
107 bool
108 Lang::Symbol::operator <= ( const Symbol & other ) const
110 return key_ <= other.key_;
113 bool
114 Lang::Symbol::operator >= ( const Symbol & other ) const
116 return key_ >= other.key_;
119 bool
120 Lang::Symbol::isUnique( ) const
122 return key_ < 0;
125 RefCountPtr< const char >
126 Lang::Symbol::name( ) const
128 if( key_ > 0 )
130 ReverseTableType::const_iterator i = reverseTable.find( key_ );
131 if( i == reverseTable.end( ) )
133 throw Exceptions::InternalError( "The reverse symbol table did not include the sought key." );
135 return i->second;
137 else if( key_ < 0 )
139 return strrefdup( "<unique>" );
141 return strrefdup( "<dummy>" );
144 RefCountPtr< const char >
145 Lang::Symbol::nameFromKey( KeyType key )
147 if( key <= 0 )
149 throw Exceptions::MiscellaneousRequirement( "It is forbidden to ask for the name of a unique symbol." );
151 ReverseTableType::const_iterator i = reverseTable.find( key );
152 if( i == reverseTable.end( ) )
154 throw Exceptions::InternalError( "The reverse symbol table did not include the sought key." );
156 return i->second;
160 RefCountPtr< const Lang::Class > Lang::Symbol::TypeID( new Lang::SystemFinalClass( strrefdup( "Symbol" ) ) );
161 TYPEINFOIMPL( Symbol );
163 void
164 Lang::Symbol::show( std::ostream & os ) const
166 if( isUnique( ) )
168 os << "'<unique>" ;
170 else
172 os << "'" << name( ) ;
177 DISPATCHIMPL( Float );
179 RefCountPtr< const Lang::Class > Lang::Float::TypeID( new Lang::SystemFinalClass( strrefdup( "Float" ) ) );
180 TYPEINFOIMPL( Float );
182 void
183 Lang::Float::show( std::ostream & os ) const
185 if( val_ >= 0.0 ){
186 os << val_ ;
187 }else{
188 os << "~" << -val_ ;
193 DISPATCHIMPL( Integer );
195 RefCountPtr< const Lang::Class > Lang::Integer::TypeID( new Lang::SystemFinalClass( strrefdup( "Integer" ) ) );
196 TYPEINFOIMPL( Integer );
198 bool
199 Lang::Integer::operator == ( const Integer & other ) const
201 return val_ == other.val_;
204 bool
205 Lang::Integer::operator != ( const Integer & other ) const
207 return val_ != other.val_;
210 bool
211 Lang::Integer::operator < ( const Integer & other ) const
213 return val_ < other.val_;
216 bool
217 Lang::Integer::operator > ( const Integer & other ) const
219 return val_ > other.val_;
222 bool
223 Lang::Integer::operator <= ( const Integer & other ) const
225 return val_ <= other.val_;
228 bool
229 Lang::Integer::operator >= ( const Integer & other ) const
231 return val_ >= other.val_;
234 Kernel::VariableHandle
235 Lang::Integer::getField( const char * fieldID, const RefCountPtr< const Lang::Value > & selfRef ) const
237 if( strcmp( fieldID, "hex" ) == 0 )
239 std::ostringstream oss;
240 ValueType tmp = val_;
241 if( tmp < 0 )
243 oss << "~" ;
244 tmp = -tmp;
246 oss << std::hex << tmp ;
247 return Helpers::newValHandle( new Lang::String( strrefdup( oss ) ) );
249 if( strcmp( fieldID, "oct" ) == 0 )
251 std::ostringstream oss;
252 ValueType tmp = val_;
253 if( tmp < 0 )
255 oss << "~" ;
256 tmp = -tmp;
258 oss << std::oct << tmp ;
259 return Helpers::newValHandle( new Lang::String( strrefdup( oss ) ) );
261 if( strcmp( fieldID, "bin" ) == 0 )
263 std::ostringstream oss;
264 ValueType tmp = val_;
265 if( tmp < 0 )
267 oss << "~" ;
268 tmp = -tmp;
270 char buf[ 8 * sizeof( ValueType ) ]; /* Since ValueType is signed, there is enough memory to hold the terminating null character. */
271 char * dst = buf;
272 ValueType twopow = 1;
273 while( twopow < tmp )
275 twopow *= 2;
277 for( ; twopow > 0; twopow /= 2, ++dst )
279 if( tmp >= twopow )
281 *dst = '1';
282 tmp -= twopow;
284 else
286 *dst = '0';
289 *dst = '\0';
290 oss << buf ;
291 return Helpers::newValHandle( new Lang::String( strrefdup( oss ) ) );
293 if( strcmp( fieldID, "bits_bin" ) == 0 )
295 std::ostringstream oss;
296 ValueType_unsigned tmp = *reinterpret_cast< const ValueType_unsigned * >( & val_ );
297 char buf[ 8 * sizeof( ValueType ) + 1];
298 char * dst = buf + 8 * sizeof( ValueType );
299 *dst = '\0';
300 for( ; dst > buf; )
302 --dst;
303 *dst = ( ( tmp % 2 ) != 0 ) ? '1': '0';
304 tmp /= 2;
306 oss << buf ;
307 return Helpers::newValHandle( new Lang::String( strrefdup( oss ) ) );
309 if( strcmp( fieldID, "bits_hex" ) == 0 )
311 std::ostringstream oss;
312 ValueType_unsigned tmp = *reinterpret_cast< const ValueType_unsigned * >( & val_ );
313 char buf[ 2 * sizeof( ValueType ) + 1];
314 char * dst = buf + 2 * sizeof( ValueType );
315 *dst = '\0';
316 for( ; dst > buf; )
318 --dst;
319 unsigned char d = tmp % 0x10;
320 if( d < 10 )
322 *dst = '0' + d;
324 else
326 *dst = 'A' + ( d - 10 );
328 tmp /= 0x10;
330 oss << buf ;
331 return Helpers::newValHandle( new Lang::String( strrefdup( oss ) ) );
333 if( strcmp( fieldID, "dec" ) == 0 )
335 std::ostringstream oss;
336 ValueType tmp = val_;
337 if( tmp < 0 )
339 oss << "~" ;
340 tmp = -tmp;
342 oss << std::dec << tmp ;
343 return Helpers::newValHandle( new Lang::String( strrefdup( oss ) ) );
346 throw Exceptions::NonExistentMember( getTypeName( ), fieldID );
349 void
350 Lang::Integer::show( std::ostream & os ) const
352 if( val_ >= 0 ){
353 os << "'" << val_ ;
354 }else{
355 os << "'~" << -val_ ;
359 DISPATCHIMPL( Character );
361 RefCountPtr< const Lang::Class > Lang::Character::TypeID( new Lang::SystemFinalClass( strrefdup( "Character" ) ) );
362 TYPEINFOIMPL( Character );
364 void
365 Lang::Character::show( std::ostream & os ) const
367 const size_t bufSize = 8;
368 char buf[ bufSize ];
369 char * dst = buf;
370 size_t out_avail = bufSize - 1;
371 val_.encode_UTF8( & dst, & out_avail );
372 *dst = '\0';
373 os << buf ;
376 Kernel::VariableHandle
377 Lang::Character::getField( const char * fieldID, const RefCountPtr< const Lang::Value > & selfRef ) const
379 if( strcmp( fieldID, "code" ) == 0 )
381 return Helpers::newValHandle( new Lang::Integer( val_.get_UCS4( ) ) );
384 throw Exceptions::NonExistentMember( getTypeName( ), fieldID );
388 //Lang::Length::Length( double val )
389 // : isOffset_( false ), val_( val )
390 //{ }
392 //Lang::Length::Length( bool isOffset, double val )
393 // : isOffset_( _isOffset ), val_( _val )
394 //{ }
396 DISPATCHIMPL( Length );
398 Concrete::Length
399 Lang::Length::get( Concrete::Length baseLength ) const
401 if( isOffset_ )
403 return baseLength + val_;
405 return val_;
408 Concrete::Length
409 Lang::Length::get( ) const
411 if( isOffset_ )
413 throw Exceptions::MiscellaneousRequirement( "Offset lengths are not allowed here." );
415 return val_;
418 double
419 Lang::Length::getScalar( Concrete::Length baseLength ) const
421 if( isOffset_ )
423 return ( baseLength + val_ ).offtype< 1, 0 >( );
425 return val_.offtype< 1, 0 >( );
428 double
429 Lang::Length::getScalar( ) const
431 if( isOffset_ )
433 throw Exceptions::MiscellaneousRequirement( "Offset lengths are not allowed here." );
435 return val_.offtype< 1, 0 >( );
438 Lang::Length
439 Lang::Length::operator + ( const Lang::Length & term ) const
441 if( term.isOffset_ )
443 throw Exceptions::MiscellaneousRequirement( "The right term in a length addition must not be offset." );
445 return Lang::Length( isOffset_, val_ + term.val_ );
448 Lang::Length
449 Lang::Length::operator - ( const Lang::Length & term ) const
451 if( term.isOffset_ )
453 throw Exceptions::MiscellaneousRequirement( "The right term in a length subtraction must not be offset." );
455 return Lang::Length( isOffset_, val_ - term.val_ );
458 RefCountPtr< const Lang::Class > Lang::Length::TypeID( new Lang::SystemFinalClass( strrefdup( "Length" ) ) );
459 TYPEINFOIMPL( Length );
461 void
462 Lang::Length::show( std::ostream & os ) const
464 os << *this ;
468 std::ostream &
469 Lang::operator << ( std::ostream & os, const Lang::Length & self )
471 if( self.isOffset_ )
473 os << "(+" ;
475 double lengthVal = static_cast< double >( self.val_ / Interaction::displayUnit );
476 if( lengthVal >= 0 ){
477 os << lengthVal ;
478 }else{
479 os << "~" << -lengthVal ;
481 os << Interaction::displayUnitName ;
482 if( self.isOffset_ )
484 os << ")" ;
486 return os;
490 DISPATCHIMPL( Boolean );
492 RefCountPtr< const Lang::Class > Lang::Boolean::TypeID( new Lang::SystemFinalClass( strrefdup( "Boolean" ) ) );
493 TYPEINFOIMPL( Boolean );
495 void
496 Lang::Boolean::show( std::ostream & os ) const
498 if( val_ )
500 os << "true" ;
502 else
504 os << "false" ;
509 namespace Shapes
512 namespace Lang
515 class StringMethod_byteselect : public Lang::MethodBase< Lang::String >
517 public:
518 StringMethod_byteselect( RefCountPtr< const Lang::String > _self, const Ast::FileID * fullMethodID );
519 virtual ~StringMethod_byteselect( );
520 virtual void call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const;
521 static const char * staticFieldID( ) { return "byteselect"; }
524 class StringMethod_UTF8select : public Lang::MethodBase< Lang::String >
526 public:
527 StringMethod_UTF8select( RefCountPtr< const Lang::String > _self, const Ast::FileID * fullMethodID );
528 virtual ~StringMethod_UTF8select( );
529 virtual void call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const;
530 static const char * staticFieldID( ) { return "UTF8select"; }
536 void
537 String_register_methods( Lang::SystemFinalClass * dstClass )
539 dstClass->registerMethod( new Kernel::MethodFactory< Lang::String, Lang::StringMethod_byteselect >( ) );
540 dstClass->registerMethod( new Kernel::MethodFactory< Lang::String, Lang::StringMethod_UTF8select >( ) );
543 Lang::String::~String( )
546 DISPATCHIMPL( String );
548 RefCountPtr< const Lang::Class > Lang::String::TypeID( new Lang::SystemFinalClass( strrefdup( "String" ), String_register_methods ) );
549 TYPEINFOIMPL( String );
551 Kernel::VariableHandle
552 Lang::String::getField( const char * fieldID, const RefCountPtr< const Lang::Value > & selfRef ) const
554 if( strcmp( fieldID, "bytecount" ) == 0 )
556 return Helpers::newValHandle( new Lang::Integer( bytecount_ ) );
558 if( strcmp( fieldID, "UTF8count" ) == 0 )
560 return Helpers::newValHandle( new Lang::Integer( UTF8count( ) ) );
562 if( strcmp( fieldID, "UTF8?" ) == 0 )
564 const unsigned char * src = reinterpret_cast< const unsigned char * >( val_.getPtr( ) );
565 const unsigned char * end = src + bytecount_;
566 bool res = true;
567 for( ; src < end; ++src )
569 if( ( ( *src ^ 0x00 ) & 0x80 ) == 0 )
571 continue;
573 if( ( ( *src ^ 0xC0 ) & 0xE0 ) == 0 )
575 ++src;
576 if( ( ( *src ^ 0x80 ) & 0xC0 ) != 0 )
578 res = false;
579 break;
581 continue;
583 if( ( ( *src ^ 0xE0 ) & 0xF0 ) == 0 )
585 ++src;
586 if( ( ( *src ^ 0x80 ) & 0xC0 ) != 0 )
588 res = false;
589 break;
591 ++src;
592 if( ( ( *src ^ 0x80 ) & 0xC0 ) != 0 )
594 res = false;
595 break;
597 continue;
599 if( ( ( *src ^ 0xE0 ) & 0xF8 ) == 0 )
601 ++src;
602 if( ( ( *src ^ 0x80 ) & 0xC0 ) != 0 )
604 res = false;
605 break;
607 ++src;
608 if( ( ( *src ^ 0x80 ) & 0xC0 ) != 0 )
610 res = false;
611 break;
613 ++src;
614 if( ( ( *src ^ 0x80 ) & 0xC0 ) != 0 )
616 res = false;
617 break;
619 continue;
621 res = false;
622 break;
624 if( src != end || *src != '\0' )
626 res = false;
628 return Helpers::newValHandle( new Lang::Boolean( res ) );
631 return TypeID->getMethod( selfRef, fieldID ); /* This will throw if there is no such method. */
634 size_t
635 Lang::String::UTF8count( ) const
637 const char * src = val_.getPtr( );
638 const char * end = src + bytecount_;
640 const char * ASCIIstart = src;
641 size_t count = 0;
643 while( *src > 0 )
645 ASCII:
646 ++src;
649 count += src - ASCIIstart;
650 while( *src != 0 && src < end )
652 if( *src > 0 )
654 ASCIIstart = src;
655 goto ASCII;
657 else
659 switch( 0xF0 & *src )
661 case 0xE0: src += 3; break;
662 case 0xF0: src += 4; break;
663 default: src += 2; break;
666 ++count;
668 if( *src != 0 || src != end )
670 throw Exceptions::MiscellaneousRequirement( "The string is not valid UTF-8, so the number of UTF-8 characters could not be counted." );
673 return count;
676 void
677 Lang::String::show( std::ostream & os ) const
679 os << val_.getPtr( ) ;
683 Lang::Continuation::Continuation( const Kernel::ContRef & cont )
684 : cont_( cont )
687 Lang::Continuation::~Continuation( )
690 RefCountPtr< const Lang::Class > Lang::Continuation::TypeID( new Lang::SystemFinalClass( strrefdup( "Backtrace" ) ) );
691 TYPEINFOIMPL( Continuation );
693 Kernel::VariableHandle
694 Lang::Continuation::getField( const char * fieldID, const RefCountPtr< const Lang::Value > & selfRef ) const
696 if( strcmp( fieldID, "up" ) == 0 )
698 Kernel::ContRef res = cont_->up( );
699 if( res == NullPtr< Kernel::Continuation >( ) )
701 throw Exceptions::MiscellaneousRequirement( "The top continuation has no parent." );
703 return Helpers::newValHandle( new Lang::Continuation( res ) );
705 else if( strcmp( fieldID, "top?" ) == 0 )
707 Kernel::ContRef res = cont_->up( );
708 return ( res == NullPtr< Kernel::Continuation >( ) ) ? Kernel::THE_TRUE_VARIABLE : Kernel::THE_FALSE_VARIABLE;
710 throw Exceptions::NonExistentMember( getTypeName( ), fieldID );
713 void
714 Lang::Continuation::show( std::ostream & os ) const
716 os << "( backtrace to use in error messages )" ;
719 void
720 Lang::Continuation::gcMark( Kernel::GCMarkedSet & marked )
722 cont_->gcMark( marked );
726 Lang::Exception::Exception( const Ast::SourceLocation & loc, const RefCountPtr< const Lang::Symbol > & kind, const RefCountPtr< const Lang::String > & source, const RefCountPtr< const Lang::Value > & details, const RefCountPtr< const char > & message, const Kernel::ContRef & cont, Interaction::ExitCode exitCode )
727 : loc_( loc ), kind_( kind ), source_( source ), details_( details ), message_( message ), cont_( cont ), exitCode_( exitCode )
730 Lang::Exception::Exception( const RefCountPtr< const Lang::Symbol > & kind, const RefCountPtr< const Lang::String > & source, const RefCountPtr< const Lang::Value > & details, const RefCountPtr< const char > & message, const Kernel::ContRef & cont, Interaction::ExitCode exitCode )
731 : loc_( cont->traceLoc( ) ), kind_( kind ), source_( source ), details_( details ), message_( message ), cont_( cont ), exitCode_( exitCode )
734 Lang::Exception::~Exception( )
737 RefCountPtr< const Lang::Class > Lang::Exception::TypeID( new Lang::SystemFinalClass( strrefdup( "Exception" ) ) );
738 TYPEINFOIMPL( Exception );
740 Kernel::VariableHandle
741 Lang::Exception::getField( const char * fieldID, const RefCountPtr< const Lang::Value > & selfRef ) const
743 if( strcmp( fieldID, "kind" ) == 0 )
745 return Kernel::VariableHandle( new Kernel::Variable( kind_ ) );
747 else if( strcmp( fieldID, "source" ) == 0 )
749 return Kernel::VariableHandle( new Kernel::Variable( source_ ) );
751 else if( strcmp( fieldID, "details" ) == 0 )
753 return Kernel::VariableHandle( new Kernel::Variable( details_ ) );
755 else if( strcmp( fieldID, "backtrace" ) == 0 )
757 return Helpers::newValHandle( new Lang::Continuation( cont_ ) );
759 throw Exceptions::NonExistentMember( getTypeName( ), fieldID );
762 void
763 Lang::Exception::show( std::ostream & os ) const
765 os << message_ ;
768 void
769 Lang::Exception::gcMark( Kernel::GCMarkedSet & marked )
771 const_cast< Lang::Value * >( details_.getPtr( ) )->gcMark( marked );
772 const_cast< Kernel::Continuation * >( cont_.getPtr( ) )->gcMark( marked );
776 Lang::FloatPair::FloatPair( const Concrete::UnitFloatPair & orig )
777 : x_( orig.x_ ), y_( orig.y_ )
781 DISPATCHIMPL( FloatPair );
783 Kernel::VariableHandle
784 Lang::FloatPair::getField( const char * fieldID, const RefCountPtr< const Lang::Value > & selfRef ) const
786 if( strcmp( fieldID, "x" ) == 0 )
788 return Helpers::newValHandle( new Lang::Float( x_ ) );
790 if( strcmp( fieldID, "y" ) == 0 )
792 return Helpers::newValHandle( new Lang::Float( y_ ) );
794 throw Exceptions::NonExistentMember( getTypeName( ), fieldID );
797 RefCountPtr< const Lang::Class > Lang::FloatPair::TypeID( new Lang::SystemFinalClass( strrefdup( "FloatPair" ) ) );
798 TYPEINFOIMPL( FloatPair );
800 RefCountPtr< const Lang::FloatPair >
801 Lang::FloatPair::transformed( const Lang::Transform2D & tf ) const
803 return RefCountPtr< const Lang::FloatPair >
804 ( new Lang::FloatPair( tf.xx_ * x_ + tf.xy_ * y_, tf.yx_ * x_ + tf.yy_ * y_ ) );
807 void
808 Lang::FloatPair::show( std::ostream & os ) const
810 os << "( " << x_ << ", " << y_ << " )" ;
813 Lang::FloatTriple::FloatTriple( const Concrete::UnitFloatTriple & orig )
814 : x_( orig.x_ ), y_( orig.y_ ), z_( orig.z_ )
817 DISPATCHIMPL( FloatTriple );
819 Kernel::VariableHandle
820 Lang::FloatTriple::getField( const char * fieldID, const RefCountPtr< const Lang::Value > & selfRef ) const
822 if( strcmp( fieldID, "x" ) == 0 )
824 return Helpers::newValHandle( new Lang::Float( x_ ) );
826 if( strcmp( fieldID, "y" ) == 0 )
828 return Helpers::newValHandle( new Lang::Float( y_ ) );
830 if( strcmp( fieldID, "z" ) == 0 )
832 return Helpers::newValHandle( new Lang::Float( z_ ) );
834 throw Exceptions::NonExistentMember( getTypeName( ), fieldID );
837 RefCountPtr< const Lang::Class > Lang::FloatTriple::TypeID( new Lang::SystemFinalClass( strrefdup( "FloatTriple" ) ) );
838 TYPEINFOIMPL( FloatTriple );
840 RefCountPtr< const Lang::FloatTriple >
841 Lang::FloatTriple::transformed( const Lang::Transform3D & tf ) const
843 return RefCountPtr< const Lang::FloatTriple >
844 ( new Lang::FloatTriple( tf.xx_ * x_ + tf.xy_ * y_ + tf.xz_ * z_,
845 tf.yx_ * x_ + tf.yy_ * y_ + tf.yz_ * z_,
846 tf.zx_ * x_ + tf.zy_ * y_ + tf.zz_ * z_ ) );
849 void
850 Lang::FloatTriple::show( std::ostream & os ) const
852 os << "( " << x_ << ", " << y_ << ", " << z_ << " )" ;
856 Lang::Coords2D::Coords2D( const Lang::Coords2D & orig )
857 : x_( orig.x_ ), y_( orig.y_ )
860 Lang::Coords2D::Coords2D( const Lang::Length & x, const Lang::Length & y )
861 : x_( x ), y_( y )
864 Lang::Coords2D::Coords2D( const Concrete::Length & x, const Concrete::Length & y )
865 : x_( x ), y_( y )
868 DISPATCHIMPL( Coords2D );
870 Kernel::VariableHandle
871 Lang::Coords2D::getField( const char * fieldID, const RefCountPtr< const Lang::Value > & selfRef ) const
873 if( strcmp( fieldID, "x" ) == 0 )
875 return Helpers::newValHandle( new Lang::Length( x_ ) );
877 if( strcmp( fieldID, "y" ) == 0 )
879 return Helpers::newValHandle( new Lang::Length( y_ ) );
881 throw Exceptions::NonExistentMember( getTypeName( ), fieldID );
884 Lang::Coords2D *
885 Lang::Coords2D::transformedPtr( const Lang::Transform2D & tf ) const
887 Concrete::Length tmpx = x_.get( );
888 Concrete::Length tmpy = y_.get( );
889 return new Lang::Coords2D( tf.xx_ * tmpx + tf.xy_ * tmpy + tf.xt_, tf.yx_ * tmpx + tf.yy_ * tmpy + tf.yt_ );
892 RefCountPtr< const Lang::Geometric2D >
893 Lang::Coords2D::transformed( const Lang::Transform2D & tf, const RefCountPtr< const Lang::Geometric2D > & self ) const
895 return RefCountPtr< const Lang::Geometric2D >( transformedPtr( tf ) );
898 RefCountPtr< const Lang::Geometric3D >
899 Lang::Coords2D::to3D( const RefCountPtr< const Lang::Geometric2D > & self ) const
901 return RefCountPtr< const Lang::Coords3D >( new Lang::Coords3D( x_, y_, Lang::Length( Concrete::Length( 0 ) ) ) );
904 RefCountPtr< const Lang::Class > Lang::Coords2D::TypeID( new Lang::SystemFinalClass( strrefdup( "Coords2D" ) ) );
905 TYPEINFOIMPL( Coords2D );
907 void
908 Lang::Coords2D::show( std::ostream & os ) const
910 os << "( " << x_ << ", " << y_ << " )" ;
913 std::ostream &
914 Lang::operator << ( std::ostream & os, const Lang::Coords2D & self )
916 os << "( " << self.x_ << ", " << self.y_ << " )" ;
917 return os;
921 Lang::CornerCoords2D::CornerCoords2D( const Lang::Length & x, const Lang::Length & y, double a )
922 : Lang::Coords2D( x, y ), a_( a )
925 Lang::CornerCoords2D::CornerCoords2D( const Concrete::Length & x, const Concrete::Length & y, double a )
926 : Lang::Coords2D( x, y ), a_( a )
929 RefCountPtr< const Lang::Class > Lang::CornerCoords2D::TypeID( new Lang::SystemFinalClass( strrefdup( "CornerCoords2D" ) ) );
930 DISPATCHIMPL( CornerCoords2D );
932 Kernel::VariableHandle
933 Lang::CornerCoords2D::getField( const char * fieldID, const RefCountPtr< const Lang::Value > & selfRef ) const
935 if( strcmp( fieldID, "x" ) == 0 )
937 return Helpers::newValHandle( new Lang::Length( x_ ) );
939 if( strcmp( fieldID, "y" ) == 0 )
941 return Helpers::newValHandle( new Lang::Length( y_ ) );
943 if( strcmp( fieldID, "a" ) == 0 )
945 return Helpers::newValHandle( new Lang::Float( a_ ) );
947 throw Exceptions::NonExistentMember( getTypeName( ), fieldID );
950 Lang::CornerCoords2D *
951 Lang::CornerCoords2D::transformedPtr( const Lang::Transform2D & tf ) const
953 Concrete::Length tmpx = x_.get( );
954 Concrete::Length tmpy = y_.get( );
955 return new Lang::CornerCoords2D( tf.xx_ * tmpx + tf.xy_ * tmpy + tf.xt_, tf.yx_ * tmpx + tf.yy_ * tmpy + tf.yt_, a_ );
958 RefCountPtr< const Lang::Geometric2D >
959 Lang::CornerCoords2D::transformed( const Lang::Transform2D & tf, const RefCountPtr< const Lang::Geometric2D > & self ) const
961 return RefCountPtr< const Lang::Geometric2D >( transformedPtr( tf ) );
964 RefCountPtr< const Lang::Geometric3D >
965 Lang::CornerCoords2D::to3D( const RefCountPtr< const Lang::Geometric2D > & self ) const
967 throw Exceptions::MiscellaneousRequirement( "Corner coordinates cannot move into 3D space." );
970 TYPEINFOIMPL( CornerCoords2D );
973 Lang::Coords3D::Coords3D( const Lang::Coords3D & orig )
974 : x_( orig.x_ ), y_( orig.y_ ), z_( orig.z_ )
977 Lang::Coords3D::Coords3D( const Lang::Length & x, const Lang::Length & y, const Lang::Length & z )
978 : x_( x ), y_( y ), z_( z )
981 Lang::Coords3D::Coords3D( const Concrete::Length & x, const Concrete::Length & y, const Concrete::Length & z )
982 : x_( x ), y_( y ), z_( z )
985 DISPATCHIMPL( Coords3D );
987 Kernel::VariableHandle
988 Lang::Coords3D::getField( const char * fieldID, const RefCountPtr< const Lang::Value > & selfRef ) const
990 if( strcmp( fieldID, "x" ) == 0 )
992 return Helpers::newValHandle( new Lang::Length( x_ ) );
994 if( strcmp( fieldID, "y" ) == 0 )
996 return Helpers::newValHandle( new Lang::Length( y_ ) );
998 if( strcmp( fieldID, "z" ) == 0 )
1000 return Helpers::newValHandle( new Lang::Length( z_ ) );
1002 throw Exceptions::NonExistentMember( getTypeName( ), fieldID );
1005 Lang::Coords3D *
1006 Lang::Coords3D::transformedPtr( const Lang::Transform3D & tf ) const
1008 Concrete::Length tmpx = x_.get( );
1009 Concrete::Length tmpy = y_.get( );
1010 Concrete::Length tmpz = z_.get( );
1011 return new Lang::Coords3D( tf.xx_ * tmpx + tf.xy_ * tmpy + tf.xz_ * tmpz + tf.xt_,
1012 tf.yx_ * tmpx + tf.yy_ * tmpy + tf.yz_ * tmpz + tf.yt_,
1013 tf.zx_ * tmpx + tf.zy_ * tmpy + tf.zz_ * tmpz + tf.zt_ );
1016 RefCountPtr< const Lang::Geometric3D >
1017 Lang::Coords3D::transformed( const Lang::Transform3D & tf, const RefCountPtr< const Lang::Geometric3D > & self ) const
1019 return RefCountPtr< const Lang::Geometric3D >( transformedPtr( tf ) );
1022 RefCountPtr< const Lang::Coords2D >
1023 Lang::Coords3D::make2D( Concrete::Length eyez ) const
1025 if( eyez < Concrete::HUGE_LENGTH )
1027 return RefCountPtr< const Lang::Coords2D >( new Lang::Coords2D( x_.get( ) * ( eyez / ( eyez - z_.get( ) ) ),
1028 y_.get( ) * ( eyez / ( eyez - z_.get( ) ) ) ) );
1030 return RefCountPtr< const Lang::Coords2D >( new Lang::Coords2D( x_.get( ),
1031 y_.get( ) ) );
1035 RefCountPtr< const Lang::Geometric2D >
1036 Lang::Coords3D::to2D( const Kernel::PassedDyn & dyn, const RefCountPtr< const Lang::Geometric3D > & self ) const
1038 return make2D( dyn->getEyeZ( ) );
1041 RefCountPtr< const Lang::Class > Lang::Coords3D::TypeID( new Lang::SystemFinalClass( strrefdup( "Coords3D" ) ) );
1042 TYPEINFOIMPL( Coords3D );
1044 void
1045 Lang::Coords3D::show( std::ostream & os ) const
1047 os << "( " << x_ << ", " << y_ << ", " << z_ << " )" ;
1050 std::ostream &
1051 Lang::operator << ( std::ostream & os, const Lang::Coords3D & self )
1053 os << "( " << self.x_ << ", " << self.y_ << ", " << self.z_ << " )" ;
1054 return os;
1058 namespace Shapes
1060 namespace Kernel
1062 class StringMethod_select_cont : public Kernel::Continuation
1064 RefCountPtr< const Lang::String > self_;
1065 bool UTF8select_;
1066 Kernel::ContRef cont_;
1067 public:
1068 StringMethod_select_cont( const RefCountPtr< const Lang::String > & self, bool UTF8select, Kernel::ContRef cont, const Ast::SourceLocation & traceLoc )
1069 : Kernel::Continuation( traceLoc ), self_( self ), UTF8select_( UTF8select ), cont_( cont )
1071 virtual ~StringMethod_select_cont( ) { }
1072 virtual void takeValue( const RefCountPtr< const Lang::Value > & posUntyped, Kernel::EvalState * evalState, bool dummy ) const
1074 RefCountPtr< const Lang::SingleList > pos = posUntyped.down_cast< const Lang::SingleList >( );
1075 if( pos == NullPtr< const Lang::SingleList >( ) )
1076 throw Exceptions::InternalError( "StringMethod_select_cont::takeValue did not get a SingleList value." );
1078 Lang::Integer::ValueType posEnd = UTF8select_ ? self_->UTF8count( ) : self_->bytecount_;
1080 typedef std::vector< Lang::Integer::ValueType > PosVecType;
1081 PosVecType posTyped;
1083 RefCountPtr< const Lang::SingleList > src = pos;
1084 while( ! src->isNull( ) )
1088 typedef const Lang::SingleListPair ArgType;
1089 RefCountPtr< ArgType > p = Helpers::try_cast_CoreArgument< ArgType >( src );
1090 posTyped.push_back( p->car_->getVal< const Lang::Integer >( traceLoc_ )->val_ );
1091 src = p->cdr_;
1092 continue;
1094 catch( const NonLocalExit::NotThisType & ball )
1096 /* Wrong type; never mind!.. but see below!
1101 typedef const Lang::SingleListRange< const Lang::Integer > ArgType;
1102 RefCountPtr< ArgType > p = Helpers::try_cast_CoreArgument< ArgType >( src );
1103 p->expand( & posTyped );
1104 break;
1106 catch( const NonLocalExit::NotThisType & ball )
1108 /* Wrong type; never mind!.. but see below!
1112 std::ostringstream msg;
1113 msg << "When selecting bytes/characters in a string, all positions must be of type " << Lang::Integer::staticTypeName( ) << "." ;
1114 throw Exceptions::MiscellaneousRequirement( strrefdup( msg ) );
1118 for( PosVecType::const_iterator i = posTyped.begin( ); i != posTyped.end( ); ++i )
1120 if( *i < 0 )
1122 throw Exceptions::OutOfRange( "A negative position was encountered." );
1124 if( *i >= posEnd )
1126 throw Exceptions::OutOfRange( "A position beyond the end of the string was encountered." );
1130 RefCountPtr< const char > resMem = RefCountPtr< const char >( NullPtr< const char >( ) );
1131 size_t resSize;
1133 if( UTF8select_ )
1135 std::vector< Kernel::UnicodeCodePoint > selfChars;
1136 selfChars.reserve( posEnd );
1137 /* Compare String::UTF8count! */
1139 Kernel::UnicodeCodePoint c;
1140 const char * src = self_->val_.getPtr( );
1141 const char * end = src + self_->bytecount_;
1143 while( *src > 0 )
1145 ASCII:
1146 size_t avail = 1;
1147 c.decode_UTF8( & src, & avail );
1148 selfChars.push_back( c );
1151 while( *src != 0 && src < end )
1153 if( *src > 0 )
1155 goto ASCII;
1157 else
1159 switch( 0xF0 & *src )
1161 case 0xE0:
1163 size_t avail = 3;
1164 c.decode_UTF8( & src, & avail );
1165 selfChars.push_back( c );
1167 break;
1168 case 0xF0:
1170 size_t avail = 4;
1171 c.decode_UTF8( & src, & avail );
1172 selfChars.push_back( c );
1174 break;
1175 default:
1177 size_t avail = 2;
1178 c.decode_UTF8( & src, & avail );
1179 selfChars.push_back( c );
1181 break;
1185 if( *src != 0 || src != end )
1187 throw Exceptions::InternalError( "The string is not valid UTF-8, but this should have been detected when the characters were counted." );
1191 std::ostringstream dst;
1192 const size_t bufSize = 10;
1193 char buf[ bufSize ];
1194 for( PosVecType::const_iterator i = posTyped.begin( ); i != posTyped.end( ); ++i )
1196 char * tmpBuf = buf;
1197 size_t outAvail = bufSize;
1198 selfChars[ *i ].encode_UTF8( & tmpBuf, & outAvail );
1199 *tmpBuf = '\0';
1200 dst << buf;
1202 resMem = strrefdup( dst );
1203 resSize = dst.str( ).size( );
1205 else
1207 resSize = posEnd;
1208 char * dst = new char[ resSize + 1 ];
1209 resMem = RefCountPtr< const char >( dst );
1210 const char * srcBegin = self_->val_.getPtr( );
1211 for( PosVecType::const_iterator i = posTyped.begin( ); i != posTyped.end( ); ++i, ++dst )
1213 *dst = *( srcBegin + *i );
1215 *dst = '\0';
1218 evalState->cont_ = cont_;
1219 cont_->takeValue( RefCountPtr< const Lang::String >( new Lang::String( resMem, resSize ) ), evalState );
1221 virtual Kernel::ContRef up( ) const
1223 return cont_;
1225 virtual RefCountPtr< const char > description( ) const
1227 return strrefdup( "Select bytes/characters from String, after forcing positions." );
1229 virtual void gcMark( Kernel::GCMarkedSet & marked )
1231 const_cast< Lang::String * >( self_.getPtr( ) )->gcMark( marked );
1232 cont_->gcMark( marked );
1236 class StringMethod_select_span_cont : public Kernel::Continuation
1238 RefCountPtr< const Lang::String > self_;
1239 bool UTF8select_;
1240 Kernel::ContRef cont_;
1241 public:
1242 StringMethod_select_span_cont( const RefCountPtr< const Lang::String > & self, bool UTF8select, Kernel::ContRef cont, const Ast::SourceLocation & traceLoc )
1243 : Kernel::Continuation( traceLoc ), self_( self ), UTF8select_( UTF8select ), cont_( cont )
1245 virtual ~StringMethod_select_span_cont( ) { }
1246 virtual void takeValue( const RefCountPtr< const Lang::Value > & val, Kernel::EvalState * evalState, bool dummy ) const
1248 typedef const Lang::SingleList ArgType;
1249 RefCountPtr< ArgType > pos( Helpers::down_cast_ContinuationArgument< ArgType >( val, this ) );
1251 evalState->cont_ = Kernel::ContRef( new Kernel::ForcingListContinuation( Kernel::ContRef( new Kernel::StringMethod_select_cont( self_, UTF8select_, cont_, traceLoc_ ) ), traceLoc_ ) );
1252 Kernel::ContRef cont = evalState->cont_;
1253 cont->takeValue( pos, evalState );
1255 virtual Kernel::ContRef up( ) const
1257 return cont_;
1259 virtual RefCountPtr< const char > description( ) const
1261 return strrefdup( "Select bytes/characters from String, expand span." );
1263 virtual void gcMark( Kernel::GCMarkedSet & marked )
1265 const_cast< Lang::String * >( self_.getPtr( ) )->gcMark( marked );
1266 cont_->gcMark( marked );
1274 Lang::StringMethod_byteselect::StringMethod_byteselect( RefCountPtr< const Lang::String > self, const Ast::FileID * fullMethodID )
1275 : Lang::MethodBase< class_type >( self, fullMethodID, false, true )
1277 formals_->appendEvaluatedCoreFormal( "pos", Kernel::THE_SLOT_VARIABLE );
1280 Lang::StringMethod_byteselect::~StringMethod_byteselect( )
1283 void
1284 Lang::StringMethod_byteselect::call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1286 args.applyDefaults( callLoc );
1288 size_t argsi = 0;
1291 typedef const Lang::SingleList ArgType;
1292 RefCountPtr< ArgType > pos = Helpers::try_cast_CoreArgument< ArgType >( args.getValue( argsi ) );
1294 evalState->cont_ = Kernel::ContRef( new Kernel::ForcingListContinuation( Kernel::ContRef( new Kernel::StringMethod_select_cont( self_, false, evalState->cont_, callLoc ) ), callLoc ) );
1295 Kernel::ContRef cont = evalState->cont_;
1296 cont->takeValue( pos, evalState );
1297 return;
1299 catch( const NonLocalExit::NotThisType & ball )
1301 /* Wrong type; never mind!.. but see below!
1307 typedef const Lang::Span ArgType;
1308 RefCountPtr< ArgType > pos = Helpers::try_cast_CoreArgument< ArgType >( args.getValue( argsi ) );
1310 evalState->cont_ = Kernel::ContRef( new Kernel::StringMethod_select_span_cont( self_, false, evalState->cont_, callLoc ) );
1311 pos->Lang::Function::call( evalState, RefCountPtr< const Lang::Value >( new Lang::Integer( self_->bytecount_ - 1 ) ), callLoc );
1312 return;
1314 catch( const NonLocalExit::NotThisType & ball )
1316 /* Wrong type; never mind!.. but see below!
1322 typedef const Lang::Integer ArgType;
1323 ArgType::ValueType pos = Helpers::try_cast_CoreArgument< ArgType >( args.getValue( argsi ) )->val_;
1324 if( pos < 0 )
1326 throw Exceptions::CoreOutOfRange( coreLoc_, args, argsi, "The position is negative." );
1328 size_t upos = pos;
1329 if( upos >= self_->bytecount_ )
1331 throw Exceptions::CoreOutOfRange( coreLoc_, args, argsi, "The position is beyond the end of the string." );
1333 Kernel::ContRef cont = evalState->cont_;
1334 cont->takeValue( Kernel::ValueRef( new Lang::Integer( *reinterpret_cast< const unsigned char * >( self_->val_.getPtr( ) + upos ) ) ),
1335 evalState );
1336 return;
1338 catch( const NonLocalExit::NotThisType & ball )
1340 /* Wrong type; never mind!.. but see below!
1344 throw Exceptions::CoreTypeMismatch( callLoc, coreLoc_, args, argsi, Helpers::typeSetString( Lang::SingleList::staticTypeName( ), Lang::Span::staticTypeName( ) ) );
1347 Lang::StringMethod_UTF8select::StringMethod_UTF8select( RefCountPtr< const Lang::String > self, const Ast::FileID * fullMethodID )
1348 : Lang::MethodBase< class_type >( self, fullMethodID, false, true )
1350 formals_->appendEvaluatedCoreFormal( "pos", Kernel::THE_SLOT_VARIABLE );
1353 Lang::StringMethod_UTF8select::~StringMethod_UTF8select( )
1356 void
1357 Lang::StringMethod_UTF8select::call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1359 args.applyDefaults( callLoc );
1361 size_t argsi = 0;
1364 typedef const Lang::SingleList ArgType;
1365 RefCountPtr< ArgType > pos = Helpers::try_cast_CoreArgument< ArgType >( args.getValue( argsi ) );
1367 evalState->cont_ = Kernel::ContRef( new Kernel::ForcingListContinuation( Kernel::ContRef( new Kernel::StringMethod_select_cont( self_, true, evalState->cont_, callLoc ) ), callLoc ) );
1368 Kernel::ContRef cont = evalState->cont_;
1369 cont->takeValue( pos, evalState );
1370 return;
1372 catch( const NonLocalExit::NotThisType & ball )
1374 /* Wrong type; never mind!.. but see below!
1380 typedef const Lang::Span ArgType;
1381 RefCountPtr< ArgType > pos = Helpers::try_cast_CoreArgument< ArgType >( args.getValue( argsi ) );
1383 evalState->cont_ = Kernel::ContRef( new Kernel::StringMethod_select_span_cont( self_, true, evalState->cont_, callLoc ) );
1384 pos->Lang::Function::call( evalState, RefCountPtr< const Lang::Value >( new Lang::Integer( self_->UTF8count( ) - 1 ) ), callLoc );
1385 return;
1387 catch( const NonLocalExit::NotThisType & ball )
1389 /* Wrong type; never mind!.. but see below!
1395 typedef const Lang::Integer ArgType;
1396 ArgType::ValueType pos = Helpers::try_cast_CoreArgument< ArgType >( args.getValue( argsi ) )->val_;
1397 if( pos < 0 )
1399 throw Exceptions::CoreOutOfRange( coreLoc_, args, argsi, "The position is negative." );
1401 size_t upos = pos;
1402 if( upos >= self_->UTF8count( ) )
1404 throw Exceptions::CoreOutOfRange( coreLoc_, args, argsi, "The position is beyond the end of the string." );
1407 /* Compare String::UTF8count ! */
1409 const char * src = self_->val_.getPtr( );
1410 const char * end = src + self_->bytecount_;
1412 const char * ASCIIstart = src;
1413 size_t count = 0;
1414 if( count == upos )
1416 goto done;
1418 while( *src > 0 )
1420 ASCII:
1421 ++src;
1423 count += src - ASCIIstart;
1424 if( count >= upos )
1426 src -= ( count - upos );
1427 goto done;
1429 while( *src != 0 && src < end )
1431 if( *src > 0 )
1433 ASCIIstart = src;
1434 goto ASCII;
1436 else
1438 switch( 0xF0 & *src )
1440 case 0xE0: src += 3; break;
1441 case 0xF0: src += 4; break;
1442 default: src += 2; break;
1445 ++count;
1446 if( count == upos )
1448 goto done;
1451 if( *src != 0 || src != end )
1453 throw Exceptions::InternalError( "Failed to located character at given position in string." );
1456 done:
1457 Kernel::UnicodeCodePoint c;
1458 c.decode_UTF8( src );
1459 Kernel::ContRef cont = evalState->cont_;
1460 cont->takeValue( Kernel::ValueRef( new Lang::Character( c ) ),
1461 evalState );
1462 return;
1464 catch( const NonLocalExit::NotThisType & ball )
1466 /* Wrong type; never mind!.. but see below!
1470 throw Exceptions::CoreTypeMismatch( callLoc, coreLoc_, args, argsi, Helpers::typeSetString( Lang::SingleList::staticTypeName( ), Lang::Span::staticTypeName( ) ) );