KDECore
ktraderparsetree.cpp
Go to the documentation of this file.
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_p.h" 00021 00022 namespace KTraderParse { 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 case 7: /* EQI */ 00248 if ( c1.type != c2.type ) 00249 { 00250 _context->b = false; 00251 return true; 00252 } 00253 if ( c1.type == ParseContext::T_STRING ) 00254 { 00255 if (m_cmd == 7) { 00256 _context->b = QString::compare(c1.str, c2.str, Qt::CaseInsensitive) == 0; 00257 } else { 00258 _context->b = ( c1.str == c2.str ); 00259 } 00260 return true; 00261 } 00262 if ( c1.type == ParseContext::T_BOOL ) 00263 { 00264 _context->b = ( c1.b == c2.b ); 00265 return true; 00266 } 00267 if ( c1.type == ParseContext::T_DOUBLE ) 00268 { 00269 _context->b = ( c1.f == c2.f ); 00270 return true; 00271 } 00272 if ( c1.type == ParseContext::T_NUM ) 00273 { 00274 _context->b = ( c1.i == c2.i ); 00275 return true; 00276 } 00277 break; 00278 case 2: /* NEQ */ 00279 case 8: /* NEQI */ 00280 if ( c1.type != c2.type ) 00281 { 00282 _context->b = true; 00283 return true; 00284 } 00285 if ( c1.type == ParseContext::T_STRING ) { 00286 if (m_cmd == 8) { 00287 _context->b = QString::compare(c1.str, c2.str, Qt::CaseInsensitive) != 0; 00288 } else { 00289 _context->b = ( c1.str != c2.str ); 00290 } 00291 return true; 00292 } 00293 if ( c1.type == ParseContext::T_BOOL ) 00294 { 00295 _context->b = ( c1.b != c2.b ); 00296 return true; 00297 } 00298 if ( c1.type == ParseContext::T_DOUBLE ) 00299 { 00300 _context->b = ( c1.f != c2.f ); 00301 return true; 00302 } 00303 if ( c1.type == ParseContext::T_NUM ) 00304 { 00305 _context->b = ( c1.i != c2.i ); 00306 return true; 00307 } 00308 break; 00309 case 3: /* GEQ */ 00310 if ( c1.type != c2.type ) 00311 { 00312 _context->b = false; 00313 return true; 00314 } 00315 if ( c1.type == ParseContext::T_DOUBLE ) 00316 { 00317 _context->b = ( c1.f >= c2.f ); 00318 return true; 00319 } 00320 if ( c1.type == ParseContext::T_NUM ) 00321 { 00322 _context->b = ( c1.i >= c2.i ); 00323 return true; 00324 } 00325 _context->b = false; 00326 return true; 00327 00328 case 4: /* LEQ */ 00329 if ( c1.type != c2.type ) 00330 { 00331 _context->b = false; 00332 return true; 00333 } 00334 if ( c1.type == ParseContext::T_DOUBLE ) 00335 { 00336 _context->b = ( c1.f <= c2.f ); 00337 return true; 00338 } 00339 if ( c1.type == ParseContext::T_NUM ) 00340 { 00341 _context->b = ( c1.i <= c2.i ); 00342 return true; 00343 } 00344 _context->b = false; 00345 return true; 00346 00347 case 5: /* < */ 00348 if ( c1.type != c2.type ) 00349 { 00350 _context->b = false; 00351 return true; 00352 } 00353 if ( c1.type == ParseContext::T_DOUBLE ) 00354 { 00355 _context->b = ( c1.f < c2.f ); 00356 return true; 00357 } 00358 if ( c1.type == ParseContext::T_NUM ) 00359 { 00360 _context->b = ( c1.i < c2.i ); 00361 return true; 00362 } 00363 _context->b = false; 00364 return true; 00365 00366 case 6: /* > */ 00367 if ( c1.type != c2.type ) 00368 { 00369 _context->b = false; 00370 return true; 00371 } 00372 if ( c1.type == ParseContext::T_DOUBLE ) 00373 { 00374 _context->b = ( c1.f > c2.f ); 00375 return true; 00376 } 00377 if ( c1.type == ParseContext::T_NUM ) 00378 { 00379 _context->b = ( c1.i > c2.i ); 00380 return true; 00381 } 00382 _context->b = false; 00383 return true; 00384 00385 } 00386 00387 return false; 00388 } 00389 00390 bool ParseTreeNOT::eval( ParseContext *_context ) const 00391 { 00392 ParseContext c1( _context ); 00393 if ( !m_pLeft->eval( &c1 ) ) 00394 return false; 00395 if ( c1.type != ParseContext::T_BOOL ) 00396 return false; 00397 00398 _context->b = !c1.b; 00399 _context->type = ParseContext::T_BOOL; 00400 00401 return true; 00402 } 00403 00404 bool ParseTreeEXIST::eval( ParseContext *_context ) const 00405 { 00406 _context->type = ParseContext::T_BOOL; 00407 00408 QVariant prop = _context->service->property( m_id ); 00409 _context->b = prop.isValid(); 00410 00411 return true; 00412 } 00413 00414 bool ParseTreeMATCH::eval( ParseContext *_context ) const 00415 { 00416 _context->type = ParseContext::T_BOOL; 00417 00418 ParseContext c1( _context ); 00419 ParseContext c2( _context ); 00420 if ( !m_pLeft->eval( &c1 ) ) 00421 return false; 00422 if ( !m_pRight->eval( &c2 ) ) 00423 return false; 00424 if ( c1.type != ParseContext::T_STRING || c2.type != ParseContext::T_STRING ) 00425 return false; 00426 00427 _context->b = c2.str.contains( c1.str, m_cs ); 00428 00429 return true; 00430 } 00431 00432 bool ParseTreeIN::eval( ParseContext *_context ) const 00433 { 00434 _context->type = ParseContext::T_BOOL; 00435 00436 ParseContext c1( _context ); 00437 ParseContext c2( _context ); 00438 if ( !m_pLeft->eval( &c1 ) ) 00439 return false; 00440 if ( !m_pRight->eval( &c2 ) ) 00441 return false; 00442 00443 if ( (c1.type == ParseContext::T_NUM) && 00444 (c2.type == ParseContext::T_SEQ) && 00445 ((*(c2.seq.begin())).type() == QVariant::Int)) { 00446 00447 QList<QVariant>::ConstIterator it = c2.seq.constBegin(); 00448 QList<QVariant>::ConstIterator end = c2.seq.constEnd(); 00449 _context->b = false; 00450 for (; it != end; ++it) 00451 if ((*it).type() == QVariant::Int && 00452 (*it).toInt() == c1.i) { 00453 _context->b = true; 00454 break; 00455 } 00456 return true; 00457 } 00458 00459 if ( c1.type == ParseContext::T_DOUBLE && 00460 c2.type == ParseContext::T_SEQ && 00461 (*(c2.seq.begin())).type() == QVariant::Double) { 00462 00463 QList<QVariant>::ConstIterator it = c2.seq.constBegin(); 00464 QList<QVariant>::ConstIterator end = c2.seq.constEnd(); 00465 _context->b = false; 00466 for (; it != end; ++it) 00467 if ((*it).type() == QVariant::Double && 00468 (*it).toDouble() == c1.i) { 00469 _context->b = true; 00470 break; 00471 } 00472 return true; 00473 } 00474 00475 if (c1.type == ParseContext::T_STRING && c2.type == ParseContext::T_STR_SEQ) 00476 { 00477 if (false && m_substring) { 00478 _context->b = false; 00479 foreach (const QString &string, c2.strSeq) { 00480 if (string.contains(c1.str, m_cs)) { 00481 _context->b = true; 00482 break; 00483 } 00484 } 00485 } else { 00486 _context->b = c2.strSeq.contains(c1.str, m_cs); 00487 } 00488 00489 return true; 00490 } 00491 00492 return false; 00493 } 00494 00495 bool ParseTreeID::eval( ParseContext *_context ) const 00496 { 00497 QVariant prop = _context->service->property( m_str ); 00498 if ( !prop.isValid() ) 00499 return false; 00500 00501 if ( prop.type() == QVariant::String ) 00502 { 00503 _context->str = prop.toString(); 00504 _context->type = ParseContext::T_STRING; 00505 return true; 00506 } 00507 00508 if ( prop.type() == QVariant::Int ) 00509 { 00510 _context->i = prop.toInt(); 00511 _context->type = ParseContext::T_NUM; 00512 return true; 00513 } 00514 00515 if ( prop.type() == QVariant::Bool ) 00516 { 00517 _context->b = prop.toBool(); 00518 _context->type = ParseContext::T_BOOL; 00519 return true; 00520 } 00521 00522 if ( prop.type() == QVariant::Double ) 00523 { 00524 _context->f = prop.toDouble(); 00525 _context->type = ParseContext::T_DOUBLE; 00526 return true; 00527 } 00528 00529 if ( prop.type() == QVariant::List ) 00530 { 00531 _context->seq = prop.toList(); 00532 _context->type = ParseContext::T_SEQ; 00533 return true; 00534 } 00535 00536 if ( prop.type() == QVariant::StringList ) 00537 { 00538 _context->strSeq = prop.toStringList(); 00539 _context->type = ParseContext::T_STR_SEQ; 00540 return true; 00541 } 00542 00543 // Value has unknown type 00544 return false; 00545 } 00546 00547 bool ParseTreeMIN2::eval( ParseContext *_context ) const 00548 { 00549 _context->type = ParseContext::T_DOUBLE; 00550 00551 QVariant prop = _context->service->property( m_strId ); 00552 if ( !prop.isValid() ) 00553 return false; 00554 00555 if ( !_context->initMaxima( m_strId ) ) 00556 return false; 00557 00558 QMap<QString,PreferencesMaxima>::Iterator it = _context->maxima.find( m_strId ); 00559 if ( it == _context->maxima.end() ) 00560 return false; 00561 00562 if ( prop.type() == QVariant::Int && it.value().type == PreferencesMaxima::PM_INT ) 00563 { 00564 _context->f = (double)( prop.toInt() - it.value().iMin ) / 00565 (double)(it.value().iMax - it.value().iMin ) * (-2.0) + 1.0; 00566 return true; 00567 } 00568 else if ( prop.type() == QVariant::Double && it.value().type == PreferencesMaxima::PM_DOUBLE ) 00569 { 00570 _context->f = ( prop.toDouble() - it.value().fMin ) / (it.value().fMax - it.value().fMin ) 00571 * (-2.0) + 1.0; 00572 return true; 00573 } 00574 00575 return false; 00576 } 00577 00578 bool ParseTreeMAX2::eval( ParseContext *_context ) const 00579 { 00580 _context->type = ParseContext::T_DOUBLE; 00581 00582 QVariant prop = _context->service->property( m_strId ); 00583 if ( !prop.isValid() ) 00584 return false; 00585 00586 // Create extrema 00587 if ( !_context->initMaxima( m_strId ) ) 00588 return false; 00589 00590 // Find extrema 00591 QMap<QString,PreferencesMaxima>::Iterator it = _context->maxima.find( m_strId ); 00592 if ( it == _context->maxima.end() ) 00593 return false; 00594 00595 if ( prop.type() == QVariant::Int && it.value().type == PreferencesMaxima::PM_INT ) 00596 { 00597 _context->f = (double)( prop.toInt() - it.value().iMin ) / 00598 (double)(it.value().iMax - it.value().iMin ) * 2.0 - 1.0; 00599 return true; 00600 } 00601 else if ( prop.type() == QVariant::Double && it.value().type == PreferencesMaxima::PM_DOUBLE ) 00602 { 00603 _context->f = ( prop.toDouble() - it.value().fMin ) / 00604 (it.value().fMax - it.value().fMin ) * 2.0 - 1.0; 00605 return true; 00606 } 00607 00608 return false; 00609 } 00610 00611 int matchConstraint( const ParseTreeBase *_tree, const KService::Ptr &_service, 00612 const KService::List& _list ) 00613 { 00614 // Empty tree matches always 00615 if ( !_tree ) 00616 return 1; 00617 00618 QMap<QString,PreferencesMaxima> maxima; 00619 ParseContext c( _service, _list, maxima ); 00620 00621 // Error during evaluation ? 00622 if ( !_tree->eval( &c ) ) 00623 return -1; 00624 00625 // Did we get a bool ? 00626 if ( c.type != ParseContext::T_BOOL ) 00627 return -1; 00628 00629 return ( c.b ? 1 : 0 ); 00630 } 00631 00632 bool ParseContext::initMaxima( const QString& _prop ) 00633 { 00634 // Is the property known ? 00635 QVariant prop = service->property( _prop ); 00636 if ( !prop.isValid() ) 00637 return false; 00638 00639 // Numeric ? 00640 if ( prop.type() != QVariant::Int && prop.type() != QVariant::Double ) 00641 return false; 00642 00643 // Did we cache the result ? 00644 QMap<QString,PreferencesMaxima>::Iterator it = maxima.find( _prop ); 00645 if ( it != maxima.end() ) 00646 return ( it.value().type == PreferencesMaxima::PM_DOUBLE || 00647 it.value().type == PreferencesMaxima::PM_INT ); 00648 00649 // Double or Int ? 00650 PreferencesMaxima extrema; 00651 if ( prop.type() == QVariant::Int ) 00652 extrema.type = PreferencesMaxima::PM_INVALID_INT; 00653 else 00654 extrema.type = PreferencesMaxima::PM_INVALID_DOUBLE; 00655 00656 // Iterate over all offers 00657 KService::List::ConstIterator oit = offers.begin(); 00658 for( ; oit != offers.end(); ++oit ) 00659 { 00660 QVariant p = (*oit)->property( _prop ); 00661 if ( p.isValid() ) 00662 { 00663 // Determine new maximum/minimum 00664 if ( extrema.type == PreferencesMaxima::PM_INVALID_INT ) 00665 { 00666 extrema.type = PreferencesMaxima::PM_INT; 00667 extrema.iMin = p.toInt(); 00668 extrema.iMax = p.toInt(); 00669 } 00670 // Correct existing extrema 00671 else if ( extrema.type == PreferencesMaxima::PM_INT ) 00672 { 00673 if ( p.toInt() < extrema.iMin ) 00674 extrema.iMin = p.toInt(); 00675 if ( p.toInt() > extrema.iMax ) 00676 extrema.iMax = p.toInt(); 00677 } 00678 // Determine new maximum/minimum 00679 else if ( extrema.type == PreferencesMaxima::PM_INVALID_DOUBLE ) 00680 { 00681 extrema.type = PreferencesMaxima::PM_DOUBLE; 00682 extrema.fMin = p.toDouble(); 00683 extrema.fMax = p.toDouble(); 00684 } 00685 // Correct existing extrema 00686 else if ( extrema.type == PreferencesMaxima::PM_DOUBLE ) 00687 { 00688 if ( p.toDouble() < it.value().fMin ) 00689 extrema.fMin = p.toDouble(); 00690 if ( p.toDouble() > it.value().fMax ) 00691 extrema.fMax = p.toDouble(); 00692 } 00693 } 00694 } 00695 00696 // Cache the result 00697 maxima.insert( _prop, extrema ); 00698 00699 // Did we succeed ? 00700 return ( extrema.type == PreferencesMaxima::PM_DOUBLE || 00701 extrema.type == PreferencesMaxima::PM_INT ); 00702 } 00703 00704 }
KDE 4.6 API Reference