ktraderparsetree.cpp
00001 /* This file is part of the KDE project 00002 Copyright (C) 1998, 1999 Torben Weis <weis@kde.org> 00003 00004 This library is free software; you can redistribute it and/or 00005 modify it under the terms of the GNU Library General Public 00006 License as published by the Free Software Foundation; either 00007 version 2 of the License, or (at your option) any later version. 00008 00009 This library is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 Library General Public License for more details. 00013 00014 You should have received a copy of the GNU Library General Public License 00015 along with this library; see the file COPYING.LIB. If not, write to 00016 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00017 Boston, MA 02110-1301, USA. 00018 */ 00019 00020 #include "ktraderparsetree.h" 00021 00022 namespace TDEIO { 00023 00024 bool ParseTreeOR::eval( ParseContext *_context ) const 00025 { 00026 ParseContext c1( _context ); 00027 ParseContext c2( _context ); 00028 00029 // don't evaluate both expressions but return immediately 00030 // if the first one of them succeeds. Otherwise queries like 00031 // ((not exist Blah) or (Blah == 'Foo')) do not work, because 00032 // the evaluation of the second term ends up in a fatal error 00033 // (Simon) 00034 00035 if ( !m_pLeft->eval( &c1 ) ) 00036 return false; 00037 00038 if ( c1.type != ParseContext::T_BOOL ) 00039 return false; 00040 00041 _context->b = c1.b; 00042 _context->type = ParseContext::T_BOOL; 00043 if ( c1.b ) 00044 return true; 00045 00046 if ( !m_pRight->eval( &c2 ) ) 00047 return false; 00048 00049 if ( c2.type != ParseContext::T_BOOL ) 00050 return false; 00051 00052 _context->b = ( c1.b || c2.b ); 00053 _context->type = ParseContext::T_BOOL; 00054 00055 return true; 00056 } 00057 00058 bool ParseTreeAND::eval( ParseContext *_context ) const 00059 { 00060 _context->type = ParseContext::T_BOOL; 00061 00062 ParseContext c1( _context ); 00063 ParseContext c2( _context ); 00064 if ( !m_pLeft->eval( &c1 ) ) 00065 return false; 00066 if ( c1.type != ParseContext::T_BOOL ) 00067 return false; 00068 if ( !c1.b ) 00069 { 00070 _context->b = false; 00071 return true; 00072 } 00073 00074 if ( !m_pRight->eval( &c2 ) ) 00075 return false; 00076 if ( c2.type != ParseContext::T_BOOL ) 00077 return false; 00078 00079 _context->b = ( c1.b && c2.b ); 00080 00081 return true; 00082 } 00083 00084 bool ParseTreeCALC::eval( ParseContext *_context ) const 00085 { 00086 ParseContext c1( _context ); 00087 ParseContext c2( _context ); 00088 if ( !m_pLeft->eval( &c1 ) ) 00089 return false; 00090 if ( !m_pRight->eval( &c2 ) ) 00091 return false; 00092 00093 // Bool extension 00094 if ( c1.type != ParseContext::T_NUM && c1.type != ParseContext::T_DOUBLE && c1.type != ParseContext::T_BOOL ) 00095 return false; 00096 // Bool extension 00097 if ( c2.type != ParseContext::T_NUM && c2.type != ParseContext::T_DOUBLE && c2.type != ParseContext::T_BOOL ) 00098 return false; 00099 // Bool extension 00100 if ( c1.type == ParseContext::T_BOOL && c2.type == ParseContext::T_BOOL ) 00101 return false; 00102 00106 if ( c1.type == ParseContext::T_NUM && c2.type == ParseContext::T_DOUBLE ) 00107 { 00108 c1.type = ParseContext::T_DOUBLE; 00109 c1.f = (double)c1.i; 00110 } 00111 else if ( c1.type == ParseContext::T_DOUBLE && c2.type == ParseContext::T_NUM ) 00112 { 00113 c2.type = ParseContext::T_DOUBLE; 00114 c2.f = (double)c2.i; 00115 } 00116 // Bool extension 00117 else if ( c1.type == ParseContext::T_BOOL && c2.type == ParseContext::T_NUM ) 00118 { 00119 c1.type = ParseContext::T_NUM; 00120 if ( c1.b ) 00121 c1.i = 1; 00122 else 00123 c1.i = -1; 00124 } 00125 // Bool extension 00126 else if ( c1.type == ParseContext::T_BOOL && c2.type == ParseContext::T_DOUBLE ) 00127 { 00128 c1.type = ParseContext::T_DOUBLE; 00129 if ( c1.b ) 00130 c1.f = 1.0; 00131 else 00132 c1.f = -1.0; 00133 } 00134 // Bool extension 00135 else if ( c1.type == ParseContext::T_NUM && c2.type == ParseContext::T_BOOL ) 00136 { 00137 c2.type = ParseContext::T_NUM; 00138 if ( c2.b ) 00139 c2.i = 1; 00140 else 00141 c2.i = -1; 00142 } 00143 // Bool extension 00144 else if ( c1.type == ParseContext::T_DOUBLE && c2.type == ParseContext::T_BOOL ) 00145 { 00146 c2.type = ParseContext::T_DOUBLE; 00147 if ( c2.b ) 00148 c2.f = 1.0; 00149 else 00150 c2.f = -1.0; 00151 } 00152 00153 _context->type = c1.type; 00154 00158 switch( m_cmd ) 00159 { 00160 case 1: /* Add */ 00161 if ( c1.type == ParseContext::T_DOUBLE ) 00162 { 00163 _context->f = ( c1.f + c2.f ); 00164 return true; 00165 } 00166 if ( c1.type == ParseContext::T_NUM ) 00167 { 00168 _context->i = ( c1.i + c2.i ); 00169 return true; 00170 } 00171 break; 00172 case 2: /* Sub */ 00173 if ( c1.type == ParseContext::T_DOUBLE ) 00174 { 00175 _context->f = ( c1.f - c2.f ); 00176 return true; 00177 } 00178 if ( c1.type == ParseContext::T_NUM ) 00179 { 00180 _context->i = ( c1.i - c2.i ); 00181 return true; 00182 } 00183 break; 00184 case 3: /* Mul */ 00185 if ( c1.type == ParseContext::T_DOUBLE ) 00186 { 00187 //cout << "Double Mult" << endl; 00188 _context->f = ( c1.f * c2.f ); 00189 return true; 00190 } 00191 if ( c1.type == ParseContext::T_NUM ) 00192 { 00193 _context->i = ( c1.i * c2.i ); 00194 return true; 00195 } 00196 break; 00197 case 4: /* Div */ 00198 if ( c1.type == ParseContext::T_DOUBLE ) 00199 { 00200 _context->f = ( c1.f / c2.f ); 00201 return true; 00202 } 00203 if ( c1.type == ParseContext::T_NUM ) 00204 { 00205 _context->i = ( c1.i / c2.i ); 00206 return true; 00207 } 00208 break; 00209 } 00210 00211 return false; 00212 } 00213 00214 bool ParseTreeCMP::eval( ParseContext *_context ) const 00215 { 00216 //cout << "CMP 1 cmd=" << m_cmd << endl; 00217 ParseContext c1( _context ); 00218 ParseContext c2( _context ); 00219 if ( !m_pLeft->eval( &c1 ) ) 00220 return false; 00221 00222 if ( !m_pRight->eval( &c2 ) ) 00223 return false; 00224 00228 if ( c1.type == ParseContext::T_NUM && c2.type == ParseContext::T_DOUBLE ) 00229 { 00230 c1.type = ParseContext::T_DOUBLE; 00231 c1.f = (double)c1.i; 00232 } 00233 else if ( c1.type == ParseContext::T_DOUBLE && c2.type == ParseContext::T_NUM ) 00234 { 00235 c2.type = ParseContext::T_DOUBLE; 00236 c2.f = (double)c2.i; 00237 } 00238 00242 _context->type = ParseContext::T_BOOL; 00243 00244 switch( m_cmd ) 00245 { 00246 case 1: /* EQ */ 00247 if ( c1.type != c2.type ) 00248 { 00249 _context->b = false; 00250 return true; 00251 } 00252 if ( c1.type == ParseContext::T_STRING ) 00253 { 00254 _context->b = ( c1.str == c2.str ); 00255 return true; 00256 } 00257 if ( c1.type == ParseContext::T_BOOL ) 00258 { 00259 _context->b = ( c1.b == c2.b ); 00260 return true; 00261 } 00262 if ( c1.type == ParseContext::T_DOUBLE ) 00263 { 00264 _context->b = ( c1.f == c2.f ); 00265 return true; 00266 } 00267 if ( c1.type == ParseContext::T_NUM ) 00268 { 00269 _context->b = ( c1.i == c2.i ); 00270 return true; 00271 } 00272 break; 00273 case 2: /* NEQ */ 00274 if ( c1.type != c2.type ) 00275 { 00276 _context->b = true; 00277 return true; 00278 } 00279 if ( c1.type == ParseContext::T_STRING ) 00280 { 00281 _context->b = ( c1.str != c2.str ); 00282 return true; 00283 } 00284 if ( c1.type == ParseContext::T_BOOL ) 00285 { 00286 _context->b = ( c1.b != c2.b ); 00287 return true; 00288 } 00289 if ( c1.type == ParseContext::T_DOUBLE ) 00290 { 00291 _context->b = ( c1.f != c2.f ); 00292 return true; 00293 } 00294 if ( c1.type == ParseContext::T_NUM ) 00295 { 00296 _context->b = ( c1.i != c2.i ); 00297 return true; 00298 } 00299 break; 00300 case 3: /* GEQ */ 00301 if ( c1.type != c2.type ) 00302 { 00303 _context->b = false; 00304 return true; 00305 } 00306 if ( c1.type == ParseContext::T_DOUBLE ) 00307 { 00308 _context->b = ( c1.f >= c2.f ); 00309 return true; 00310 } 00311 if ( c1.type == ParseContext::T_NUM ) 00312 { 00313 _context->b = ( c1.i >= c2.i ); 00314 return true; 00315 } 00316 _context->b = false; 00317 return true; 00318 00319 case 4: /* LEQ */ 00320 if ( c1.type != c2.type ) 00321 { 00322 _context->b = false; 00323 return true; 00324 } 00325 if ( c1.type == ParseContext::T_DOUBLE ) 00326 { 00327 _context->b = ( c1.f <= c2.f ); 00328 return true; 00329 } 00330 if ( c1.type == ParseContext::T_NUM ) 00331 { 00332 _context->b = ( c1.i <= c2.i ); 00333 return true; 00334 } 00335 _context->b = false; 00336 return true; 00337 00338 case 5: /* < */ 00339 if ( c1.type != c2.type ) 00340 { 00341 _context->b = false; 00342 return true; 00343 } 00344 if ( c1.type == ParseContext::T_DOUBLE ) 00345 { 00346 _context->b = ( c1.f < c2.f ); 00347 return true; 00348 } 00349 if ( c1.type == ParseContext::T_NUM ) 00350 { 00351 _context->b = ( c1.i < c2.i ); 00352 return true; 00353 } 00354 _context->b = false; 00355 return true; 00356 00357 case 6: /* > */ 00358 if ( c1.type != c2.type ) 00359 { 00360 _context->b = false; 00361 return true; 00362 } 00363 if ( c1.type == ParseContext::T_DOUBLE ) 00364 { 00365 _context->b = ( c1.f > c2.f ); 00366 return true; 00367 } 00368 if ( c1.type == ParseContext::T_NUM ) 00369 { 00370 _context->b = ( c1.i > c2.i ); 00371 return true; 00372 } 00373 _context->b = false; 00374 return true; 00375 00376 } 00377 00378 return false; 00379 } 00380 00381 bool ParseTreeNOT::eval( ParseContext *_context ) const 00382 { 00383 ParseContext c1( _context ); 00384 if ( !m_pLeft->eval( &c1 ) ) 00385 return false; 00386 if ( c1.type != ParseContext::T_BOOL ) 00387 return false; 00388 00389 _context->b = !c1.b; 00390 _context->type = ParseContext::T_BOOL; 00391 00392 return true; 00393 } 00394 00395 bool ParseTreeEXIST::eval( ParseContext *_context ) const 00396 { 00397 _context->type = ParseContext::T_BOOL; 00398 00399 TQVariant prop = _context->service->property( m_id ); 00400 _context->b = prop.isValid(); 00401 00402 return true; 00403 } 00404 00405 bool ParseTreeMATCH::eval( ParseContext *_context ) const 00406 { 00407 _context->type = ParseContext::T_BOOL; 00408 00409 ParseContext c1( _context ); 00410 ParseContext c2( _context ); 00411 if ( !m_pLeft->eval( &c1 ) ) 00412 return false; 00413 if ( !m_pRight->eval( &c2 ) ) 00414 return false; 00415 if ( c1.type != ParseContext::T_STRING || c2.type != ParseContext::T_STRING ) 00416 return false; 00417 00418 _context->b = ( c2.str.find( c1.str ) != -1 ); 00419 00420 return true; 00421 } 00422 00423 bool ParseTreeIN::eval( ParseContext *_context ) const 00424 { 00425 _context->type = ParseContext::T_BOOL; 00426 00427 ParseContext c1( _context ); 00428 ParseContext c2( _context ); 00429 if ( !m_pLeft->eval( &c1 ) ) 00430 return false; 00431 if ( !m_pRight->eval( &c2 ) ) 00432 return false; 00433 00434 if ( (c1.type == ParseContext::T_NUM) && 00435 (c2.type == ParseContext::T_SEQ) && 00436 ((*(c2.seq.begin())).type() == TQVariant::Int)) { 00437 00438 TQValueList<TQVariant>::ConstIterator it = c2.seq.begin(); 00439 TQValueList<TQVariant>::ConstIterator end = c2.seq.end(); 00440 _context->b = false; 00441 for (; it != end; it++) 00442 if ((*it).type() == TQVariant::Int && 00443 (*it).toInt() == c1.i) { 00444 _context->b = true; 00445 break; 00446 } 00447 return true; 00448 } 00449 00450 if ( c1.type == ParseContext::T_DOUBLE && 00451 c2.type == ParseContext::T_SEQ && 00452 (*(c2.seq.begin())).type() == TQVariant::Double) { 00453 00454 TQValueList<TQVariant>::ConstIterator it = c2.seq.begin(); 00455 TQValueList<TQVariant>::ConstIterator end = c2.seq.end(); 00456 _context->b = false; 00457 for (; it != end; it++) 00458 if ((*it).type() == TQVariant::Double && 00459 (*it).toDouble() == c1.i) { 00460 _context->b = true; 00461 break; 00462 } 00463 return true; 00464 } 00465 00466 if ( c1.type == ParseContext::T_STRING && c2.type == ParseContext::T_STR_SEQ ) 00467 { 00468 _context->b = ( c2.strSeq.find( c1.str ) != c2.strSeq.end() ); 00469 return true; 00470 } 00471 00472 return false; 00473 } 00474 00475 bool ParseTreeID::eval( ParseContext *_context ) const 00476 { 00477 TQVariant prop = _context->service->property( m_str ); 00478 if ( !prop.isValid() ) 00479 return false; 00480 00481 if ( prop.type() == TQVariant::String ) 00482 { 00483 _context->str = prop.toString(); 00484 _context->type = ParseContext::T_STRING; 00485 return true; 00486 } 00487 00488 if ( prop.type() == TQVariant::Int ) 00489 { 00490 _context->i = prop.toInt(); 00491 _context->type = ParseContext::T_NUM; 00492 return true; 00493 } 00494 00495 if ( prop.type() == TQVariant::Bool ) 00496 { 00497 _context->b = prop.toBool(); 00498 _context->type = ParseContext::T_BOOL; 00499 return true; 00500 } 00501 00502 if ( prop.type() == TQVariant::Double ) 00503 { 00504 _context->f = prop.toDouble(); 00505 _context->type = ParseContext::T_DOUBLE; 00506 return true; 00507 } 00508 00509 if ( prop.type() == TQVariant::List ) 00510 { 00511 _context->seq = prop.toList(); 00512 _context->type = ParseContext::T_SEQ; 00513 return true; 00514 } 00515 00516 if ( prop.type() == TQVariant::StringList ) 00517 { 00518 _context->strSeq = prop.toStringList(); 00519 _context->type = ParseContext::T_STR_SEQ; 00520 return true; 00521 } 00522 00523 // Value has unknown type 00524 return false; 00525 } 00526 00527 bool ParseTreeMIN2::eval( ParseContext *_context ) const 00528 { 00529 _context->type = ParseContext::T_DOUBLE; 00530 00531 TQVariant prop = _context->service->property( m_strId ); 00532 if ( !prop.isValid() ) 00533 return false; 00534 00535 if ( !_context->initMaxima( m_strId ) ) 00536 return false; 00537 00538 TQMap<TQString,PreferencesMaxima>::Iterator it = _context->maxima.find( m_strId ); 00539 if ( it == _context->maxima.end() ) 00540 return false; 00541 00542 if ( prop.type() == TQVariant::Int && it.data().type == PreferencesMaxima::PM_INT ) 00543 { 00544 _context->f = (double)( prop.toInt() - it.data().iMin ) / 00545 (double)(it.data().iMax - it.data().iMin ) * (-2.0) + 1.0; 00546 return true; 00547 } 00548 else if ( prop.type() == TQVariant::Double && it.data().type == PreferencesMaxima::PM_DOUBLE ) 00549 { 00550 _context->f = ( prop.toDouble() - it.data().fMin ) / (it.data().fMax - it.data().fMin ) 00551 * (-2.0) + 1.0; 00552 return true; 00553 } 00554 00555 return false; 00556 } 00557 00558 bool ParseTreeMAX2::eval( ParseContext *_context ) const 00559 { 00560 _context->type = ParseContext::T_DOUBLE; 00561 00562 TQVariant prop = _context->service->property( m_strId ); 00563 if ( !prop.isValid() ) 00564 return false; 00565 00566 // Create extrema 00567 if ( !_context->initMaxima( m_strId ) ) 00568 return false; 00569 00570 // Find extrema 00571 TQMap<TQString,PreferencesMaxima>::Iterator it = _context->maxima.find( m_strId ); 00572 if ( it == _context->maxima.end() ) 00573 return false; 00574 00575 if ( prop.type() == TQVariant::Int && it.data().type == PreferencesMaxima::PM_INT ) 00576 { 00577 _context->f = (double)( prop.toInt() - it.data().iMin ) / 00578 (double)(it.data().iMax - it.data().iMin ) * 2.0 - 1.0; 00579 return true; 00580 } 00581 else if ( prop.type() == TQVariant::Double && it.data().type == PreferencesMaxima::PM_DOUBLE ) 00582 { 00583 _context->f = ( prop.toDouble() - it.data().fMin ) / 00584 (it.data().fMax - it.data().fMin ) * 2.0 - 1.0; 00585 return true; 00586 } 00587 00588 return false; 00589 } 00590 00591 int matchConstraint( const ParseTreeBase *_tree, const KService::Ptr &_service, 00592 const KServiceTypeProfile::OfferList& _list ) 00593 { 00594 // Empty tree matches always 00595 if ( !_tree ) 00596 return 1; 00597 00598 TQMap<TQString,PreferencesMaxima> maxima; 00599 ParseContext c( _service, _list, maxima ); 00600 00601 // Error during evaluation ? 00602 if ( !_tree->eval( &c ) ) 00603 return -1; 00604 00605 // Did we get a bool ? 00606 if ( c.type != ParseContext::T_BOOL ) 00607 return -1; 00608 00609 return ( c.b ? 1 : 0 ); 00610 } 00611 00612 PreferencesReturn matchPreferences( const ParseTreeBase *_tree, const KService::Ptr &_service, 00613 const KServiceTypeProfile::OfferList& _list ) 00614 { 00615 // By default: error 00616 PreferencesReturn ret; 00617 00618 if ( !_tree ) 00619 return ret; 00620 00621 TQMap<TQString,PreferencesMaxima> maxima; 00622 ParseContext c( _service, _list, maxima ); 00623 00624 if ( !_tree->eval( &c ) ) 00625 return ret; 00626 00627 // Did we get a numeric return value ? 00628 if ( c.type == ParseContext::T_NUM ) 00629 { 00630 ret.type = PreferencesReturn::PRT_DOUBLE; 00631 ret.f = (double)c.i; 00632 } 00633 else if ( c.type == ParseContext::T_DOUBLE ) 00634 { 00635 ret.type = PreferencesReturn::PRT_DOUBLE; 00636 ret.f = c.f; 00637 } 00638 00639 return ret; 00640 } 00641 00642 bool ParseContext::initMaxima( const TQString& _prop ) 00643 { 00644 // Is the property known ? 00645 TQVariant prop = service->property( _prop ); 00646 if ( !prop.isValid() ) 00647 return false; 00648 00649 // Numeric ? 00650 if ( prop.type() != TQVariant::Int && prop.type() != TQVariant::Double ) 00651 return false; 00652 00653 // Did we cache the result ? 00654 TQMap<TQString,PreferencesMaxima>::Iterator it = maxima.find( _prop ); 00655 if ( it != maxima.end() ) 00656 return ( it.data().type == PreferencesMaxima::PM_DOUBLE || 00657 it.data().type == PreferencesMaxima::PM_INT ); 00658 00659 // Double or Int ? 00660 PreferencesMaxima extrema; 00661 if ( prop.type() == TQVariant::Int ) 00662 extrema.type = PreferencesMaxima::PM_INVALID_INT; 00663 else 00664 extrema.type = PreferencesMaxima::PM_INVALID_DOUBLE; 00665 00666 // Iterate over all offers 00667 KServiceTypeProfile::OfferList::ConstIterator oit = offers.begin(); 00668 for( ; oit != offers.end(); ++oit ) 00669 { 00670 TQVariant p = (*oit).service()->property( _prop ); 00671 if ( p.isValid() ) 00672 { 00673 // Determine new maximum/minimum 00674 if ( extrema.type == PreferencesMaxima::PM_INVALID_INT ) 00675 { 00676 extrema.type = PreferencesMaxima::PM_INT; 00677 extrema.iMin = p.toInt(); 00678 extrema.iMax = p.toInt(); 00679 } 00680 // Correct existing extrema 00681 else if ( extrema.type == PreferencesMaxima::PM_INT ) 00682 { 00683 if ( p.toInt() < extrema.iMin ) 00684 extrema.iMin = p.toInt(); 00685 if ( p.toInt() > extrema.iMax ) 00686 extrema.iMax = p.toInt(); 00687 } 00688 // Determine new maximum/minimum 00689 else if ( extrema.type == PreferencesMaxima::PM_INVALID_DOUBLE ) 00690 { 00691 extrema.type = PreferencesMaxima::PM_DOUBLE; 00692 extrema.fMin = p.toDouble(); 00693 extrema.fMax = p.toDouble(); 00694 } 00695 // Correct existing extrema 00696 else if ( extrema.type == PreferencesMaxima::PM_DOUBLE ) 00697 { 00698 if ( p.toDouble() < it.data().fMin ) 00699 extrema.fMin = p.toDouble(); 00700 if ( p.toDouble() > it.data().fMax ) 00701 extrema.fMax = p.toDouble(); 00702 } 00703 } 00704 } 00705 00706 // Cache the result 00707 maxima.insert( _prop, extrema ); 00708 00709 // Did we succeed ? 00710 return ( extrema.type == PreferencesMaxima::PM_DOUBLE || 00711 extrema.type == PreferencesMaxima::PM_INT ); 00712 } 00713 00714 }