kspread Library API Documentation

kspread_interpreter.cc

00001 /* This file is part of the KDE project
00002    Copyright (C) 1998-2002 The KSpread Team
00003                            www.koffice.org/kspread
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00018    Boston, MA 02111-1307, USA.
00019 */
00020 
00021 #include <stdlib.h>
00022 #include <math.h>
00023 #include <float.h>
00024 
00025 #include <kdebug.h>
00026 
00027 #include <koscript_parser.h>
00028 #include <koscript_util.h>
00029 #include <koscript_func.h>
00030 #include <koscript_synext.h>
00031 
00032 #include "kspread_interpreter.h"
00033 
00034 #include "kspread_functions.h"
00035 #include "kspread_util.h"
00036 #include "kspread_sheet.h"
00037 #include "kspread_doc.h"
00038 #include "kspread_locale.h"
00039 
00040 
00041 /***************************************************************
00042  *
00043  * Classes which store extra informations in some KSParseNode.
00044  *
00045  ***************************************************************/
00046 
00050 class KSParseNodeExtraPoint : public KSParseNodeExtra
00051 {
00052 public:
00053   KSParseNodeExtraPoint( const QString& s, KSpreadMap* m, KSpreadSheet* t ) : m_point( s, m, t )
00054   {
00055   }
00056 
00057   KSpreadPoint* point() { return &m_point; }
00058 
00059 private:
00060   KSpreadPoint m_point;
00061 };
00062 
00066 class KSParseNodeExtraRange : public KSParseNodeExtra
00067 {
00068 public:
00069   KSParseNodeExtraRange( const QString& s, KSpreadMap* m, KSpreadSheet* t )
00070     : m_range( s, m, t )
00071   {
00072   }
00073 
00074   KSpreadRange* range() { return &m_range; }
00075 
00076 private:
00077   KSpreadRange m_range;
00078 };
00079 
00080 /****************************************************
00081  *
00082  * Helper functions
00083  *
00084  ****************************************************/
00085 
00086 static bool kspreadfunc_cell( KSContext& context )
00087 {
00088     QValueList<KSValue::Ptr>& args = context.value()->listValue();
00089 
00090     if ( !KSUtil::checkArgumentsCount( context, 3, "cell", true ) )
00091       return false;
00092 
00093     if ( !KSUtil::checkType( context, args[0], KSValue::ListType, true ) )
00094       return false;
00095     if ( !KSUtil::checkType( context, args[1], KSValue::StringType, true ) )
00096       return false;
00097     if ( !KSUtil::checkType( context, args[2], KSValue::StringType, true ) )
00098       return false;
00099 
00100     const QValueList<KSValue::Ptr>& lines = args[0]->listValue();
00101     if ( lines.count() < 2 )
00102       return FALSE;
00103 
00104     QValueList<KSValue::Ptr>::ConstIterator it = lines.begin();
00105     if ( !KSUtil::checkType( context, (*it), KSValue::ListType, true ) )
00106       return false;
00107     const QValueList<KSValue::Ptr>& line = (*it)->listValue();
00108     QValueList<KSValue::Ptr>::ConstIterator it2 = line.begin();
00109     int x = 1;
00110     ++it;
00111     ++it2;
00112     for( ; it2 != line.end(); ++it2 )
00113     {
00114       if ( !KSUtil::checkType( context, (*it2), KSValue::StringType, true ) )
00115         return false;
00116       if ( (*it2)->stringValue() == args[1]->stringValue() )
00117         break;
00118       ++x;
00119     }
00120     if ( it2 == line.end() )
00121       return FALSE;
00122 
00123     kdDebug(36001) <<"x= "<<x<<endl;
00124     for( ; it != lines.end(); ++it )
00125     {
00126       const QValueList<KSValue::Ptr>& l = (*it)->listValue();
00127       if ( x >= (int)l.count() )
00128         return FALSE;
00129       if ( l[0]->stringValue() == args[2]->stringValue() )
00130       {
00131         context.setValue( new KSValue( *(l[x]) ) );
00132         return TRUE;
00133       }
00134     }
00135 
00136     context.setValue( new KSValue( 0.0 ) );
00137     return true;
00138 }
00139 
00140 static bool kspreadfunc_select_helper( KSContext& context, QValueList<KSValue::Ptr>& args, QString& result )
00141 {
00142     QValueList<KSValue::Ptr>::Iterator it = args.begin();
00143     QValueList<KSValue::Ptr>::Iterator end = args.end();
00144 
00145     for( ; it != end; ++it )
00146     {
00147       if ( KSUtil::checkType( context, *it, KSValue::ListType, false ) )
00148       {
00149         if ( !kspreadfunc_select_helper( context, (*it)->listValue(), result ) )
00150           return false;
00151       }
00152       else if ( !(*it)->toString( context ).isEmpty() )
00153       {
00154         if ( !result.isEmpty() )
00155           result += "\\";
00156         result += (*it)->toString( context );
00157       }
00158     }
00159 
00160     return true;
00161 }
00162 
00163 static bool kspreadfunc_select( KSContext& context )
00164 {
00165   QString result( "" );
00166   bool b = kspreadfunc_select_helper( context, context.value()->listValue(), result );
00167 
00168   if ( b )
00169     context.setValue( new KSValue( result ) );
00170 
00171   return b;
00172 }
00173 
00174 static KSModule::Ptr kspreadCreateModule_KSpread( KSInterpreter* interp )
00175 {
00176   KSModule::Ptr module = new KSModule( interp, "kspread" );
00177 
00178   module->addObject( "CELL", new KSValue( new KSBuiltinFunction( module, "CELL", kspreadfunc_cell ) ) );
00179   module->addObject( "SELECT", new KSValue( new KSBuiltinFunction( module, "SELECT", kspreadfunc_select ) ) );
00180 
00181   // add all built-in functions
00182   KSpreadFunctionRepository* repo = KSpreadFunctionRepository::self();
00183   QStringList functionList = repo->regFunctionNames();
00184   for( unsigned i = 0; i < functionList.count(); i++ )
00185   {
00186     QString name = functionList[i];
00187     KSpreadFunction* function = repo->function( name );
00188     if ( function && function->functionPtr )
00189       module->addObject( name, new KSValue( new KSBuiltinFunction( module, name, function->functionPtr ) ) );
00190   }
00191 
00192   return module;
00193 }
00194 
00195 /*********************************************************************
00196  *
00197  * KSpreadInterpreter
00198  *
00199  *********************************************************************/
00200 
00201 KSpreadInterpreter::KSpreadInterpreter( KSpreadDoc * doc )
00202   : KSInterpreter(),
00203     m_cell( 0 ),
00204     m_doc( doc ),
00205     m_sheet( 0 )
00206 {
00207   KSModule::Ptr m = kspreadCreateModule_KSpread( this );
00208   m_modules.insert( m->name(), m );
00209 
00210   // Integrate the KSpread module in the global namespace for convenience
00211   KSNamespace::Iterator it = m->nameSpace()->begin();
00212   KSNamespace::Iterator end = m->nameSpace()->end();
00213   for(; it != end; ++it )
00214     m_global->insert( it.key(), it.data() );
00215 }
00216 
00217 bool KSpreadInterpreter::processExtension( KSContext& context, KSParseNode* node )
00218 {
00219   KSParseNodeExtra* extra = node->extra();
00220   if ( !extra )
00221   {
00222     if ( node->getType() == t_cell )
00223       extra = new KSParseNodeExtraPoint( node->getStringLiteral(), m_doc->map(), m_sheet );
00224     else if ( node->getType() == t_range )
00225       extra = new KSParseNodeExtraRange( node->getStringLiteral(), m_doc->map(), m_sheet );
00226     else
00227       return KSInterpreter::processExtension( context, node );
00228     node->setExtra( extra );
00229   }
00230 
00231   if ( node->getType() == t_cell )
00232   {
00233     KSParseNodeExtraPoint* p = (KSParseNodeExtraPoint*)extra;
00234     KSpreadPoint* point = p->point();
00235 
00236     if ( !point->isValid() )
00237     {
00238       QString tmp( i18n("The expression %1 is not valid") );
00239       tmp = tmp.arg( node->getStringLiteral() );
00240       context.setException( new KSException( "InvalidCellExpression", tmp ) );
00241       return false;
00242     }
00243 
00244     KSpreadCell* cell = point->cell();
00245 
00246     if ( cell->hasError() )
00247     {
00248       QString tmp( i18n("The cell %1 has an error:\n\n%2") );
00249       tmp = tmp.arg( cell->fullName() );
00250       tmp = tmp.arg( node->getStringLiteral() );
00251       context.setException( new KSException( "ErrorInCell", tmp ) );
00252       return false;
00253     }
00254 
00255     if ( cell->isDefault())
00256       context.setValue( new KSValue(  /*KSValue::Empty*/ 0.0 ) );
00257     else if(cell->isObscured() && cell->isObscuringForced())
00258       context.setValue( new KSValue( 0.0 ) );
00259     else if ( cell->value().isBoolean() )
00260       context.setValue( new KSValue( cell->value().asBoolean() ) );
00261     else if ( cell->isTime() )
00262       context.setValue( new KSValue( cell->value().asTime() ) );
00263     else if ( cell->isDate() )
00264       context.setValue( new KSValue( cell->value().asDate() ) );
00265     else if ( cell->value().isNumber() )
00266       context.setValue( new KSValue( cell->value().asFloat() ) );
00267     else if ( cell->value().asString().isEmpty() )
00268       context.setValue( new KSValue( 0.0  /*KSValue::Empty*/ ) );
00269     else
00270       context.setValue( new KSValue( cell->value().asString() ) );
00271     return true;
00272   }
00273   // Parse a range like "A1:B3"
00274   else if ( node->getType() == t_range )
00275   {
00276     KSParseNodeExtraRange* p = (KSParseNodeExtraRange*)extra;
00277     KSpreadRange* r = p->range();
00278 
00279     // Is it a valid range ?
00280     if ( !r->isValid() )
00281     {
00282       QString tmp( i18n("The expression %1 is not valid") );
00283       tmp = tmp.arg( node->getStringLiteral() );
00284       context.setException( new KSException( "InvalidRangeExpression", tmp ) );
00285       return false;
00286     }
00287 
00288     if ( r->range.left() == r->range.right()
00289          && r->range.top() == r->range.bottom() )
00290     {
00291       KSpreadCell * cell = r->sheet->cellAt( r->range.x(), r->range.y() );
00292 
00293       if ( cell->hasError() )
00294       {
00295         QString tmp( i18n("The cell %1 has an error:\n\n%2") );
00296         tmp = tmp.arg( cell->fullName() );
00297         tmp = tmp.arg( node->getStringLiteral() );
00298         context.setException( new KSException( "ErrorInCell", tmp ) );
00299         return false;
00300       }
00301 
00302       if ( cell->isDefault())
00303         context.setValue( new KSValue(  /*KSValue::Empty*/ 0.0 ) );
00304       else if(cell->isObscured() && cell->isObscuringForced())
00305         context.setValue( new KSValue( 0.0 ) );
00306       else if ( cell->value().isBoolean() )
00307       context.setValue( new KSValue( cell->value().asBoolean() ) );
00308       else if ( cell->isTime() )
00309         context.setValue( new KSValue( cell->value().asTime() ) );
00310       else if ( cell->isDate() )
00311         context.setValue( new KSValue( cell->value().asDate() ) );
00312       else if ( cell->value().isNumber() )
00313         context.setValue( new KSValue( cell->value().asFloat() ) );
00314       else if ( cell->value().asString().isEmpty() )
00315         context.setValue( new KSValue( 0.0  /*KSValue::Empty*/ ) );
00316       else
00317         context.setValue( new KSValue( cell->value().asString() ) );
00318 
00319       return true;
00320     }
00321 
00322     // The range is translated in a list or lists of integers
00323     KSValue* v = new KSValue( KSValue::ListType );
00324     for( int y = 0; y < r->range.height(); ++y )
00325     {
00326       KSValue* l = new KSValue( KSValue::ListType );
00327 
00328       for( int x = 0; x < r->range.width(); ++x )
00329       {
00330         KSValue* c;
00331         KSpreadCell* cell = r->sheet->cellAt( r->range.x() + x, r->range.y() + y );
00332 
00333         if ( cell->hasError() )
00334         {
00335           QString tmp( i18n("The cell %1 has an error:\n\n%2") );
00336           tmp = tmp.arg( cell->fullName() );
00337           tmp = tmp.arg( node->getStringLiteral() );
00338           context.setException( new KSException( "ErrorInCell", tmp ) );
00339           return false;
00340         }
00341 
00342         if ( cell->isDefault() )
00343           c = new KSValue( 0.0 /*KSValue::Empty*/);
00344         else if ( cell->value().isNumber() )
00345           c = new KSValue( cell->value().asFloat() );
00346         else if ( cell->value().isBoolean() )
00347           c = new KSValue( cell->value().asBoolean() );
00348         else if ( cell->isDate() )
00349           c = new KSValue( cell->value().asDate() );
00350         else if ( cell->isTime() )
00351           c = new KSValue( cell->value().asTime() );
00352         else if ( cell->value().asString().isEmpty() )
00353           c = new KSValue( 0.0 /*KSValue::Empty*/ );
00354         else
00355           c = new KSValue( cell->value().asString() );
00356         if ( !(cell->isObscured() && cell->isObscuringForced()) )
00357                 l->listValue().append( c );
00358       }
00359       v->listValue().append( l );
00360     }
00361     context.setValue( v );
00362 
00363     return true;
00364   }
00365   else
00366     Q_ASSERT( 0 );
00367 
00368   // Never reached
00369   return false;
00370 }
00371 
00372 KSParseNode* KSpreadInterpreter::parse( KSContext& context, KSpreadSheet* sheet, const QString& formula )
00373 {
00374     // Create the parse tree.
00375     KSParser parser;
00376     // Tell the parser the locale so that it can parse localized numbers.
00377     if ( !parser.parse( formula.utf8(), KSCRIPT_EXTENSION_KSPREAD, sheet->doc()->locale() ) )
00378     {
00379     context.setException( new KSException( "SyntaxError", parser.errorMessage() ) );
00380     return 0;
00381     }
00382 
00383     KSParseNode* n = parser.donateParseTree();
00384 
00385     return n;
00386 }
00387 
00388 bool KSpreadInterpreter::evaluate( KSContext& context, KSParseNode* node, KSpreadSheet* sheet, KSpreadCell* cell )
00389 {
00390     // Save the current sheet to make this function reentrant.
00391     KSpreadSheet * t = m_sheet;
00392     KSpreadCell * c  = m_cell;
00393     m_sheet = sheet;
00394     m_cell  = cell;
00395 
00396     bool b = node->eval( context );
00397 
00398     m_sheet = t;
00399     m_cell  = c;
00400 
00401     return b;
00402 }
KDE Logo
This file is part of the documentation for kspread Library Version 1.4.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Mon Feb 13 09:43:13 2006 by doxygen 1.4.2 written by Dimitri van Heesch, © 1997-2003