Back to index

nordugrid-arc-nox  1.1.0~rc6
RSLParser.cpp
Go to the documentation of this file.
00001 // -*- indent-tabs-mode: nil -*-
00002 
00003 #ifdef HAVE_CONFIG_H
00004 #include <config.h>
00005 #endif
00006 
00007 #include <exception>
00008 #include <sstream>
00009 
00010 #include <arc/Logger.h>
00011 #include <arc/StringConv.h>
00012 
00013 #include "RSLParser.h"
00014 
00015 namespace Arc {
00016 
00017   RSLValue::RSLValue() {}
00018 
00019   RSLValue::~RSLValue() {}
00020 
00021   RSLValue* RSLValue::Evaluate(std::map<std::string, std::string>& vars) const {
00022     const RSLLiteral *n;
00023     const RSLVariable *v;
00024     const RSLConcat *c;
00025     const RSLList *l;
00026     const RSLSequence *s;
00027     if ((n = dynamic_cast<const RSLLiteral*>(this)))
00028       return new RSLLiteral(n->Value());
00029     else if ((v = dynamic_cast<const RSLVariable*>(this))) {
00030       std::map<std::string, std::string>::iterator it = vars.find(v->Var());
00031       return new RSLLiteral((it != vars.end()) ? it->second : "");
00032     }
00033     else if ((c = dynamic_cast<const RSLConcat*>(this))) {
00034       RSLValue *left = c->Left()->Evaluate(vars);
00035       if (!left) {
00036         std::stringstream ss;
00037         ss << *c->Left();
00038         logger.msg(ERROR, "Can't evaluate left operand for RSL "
00039                    "concatenation: %s", ss.str());
00040         return NULL;
00041       }
00042       RSLValue *right = c->Right()->Evaluate(vars);
00043       if (!right) {
00044         std::stringstream ss;
00045         ss << *c->Right();
00046         logger.msg(ERROR, "Can't evaluate right operand for RSL "
00047                    "concatenation: %s", ss.str());
00048         delete left;
00049         return NULL;
00050       }
00051       RSLLiteral *nleft = dynamic_cast<RSLLiteral*>(left);
00052       if (!nleft) {
00053         std::stringstream ss;
00054         ss << *left;
00055         logger.msg(ERROR, "Left operand for RSL concatenation does not "
00056                    "evaluate to a literal: %s", ss.str());
00057         delete left;
00058         delete right;
00059         return NULL;
00060       }
00061       RSLLiteral *nright = dynamic_cast<RSLLiteral*>(right);
00062       if (!nright) {
00063         std::stringstream ss;
00064         ss << *right;
00065         logger.msg(ERROR, "Right operand for RSL concatenation does not "
00066                    "evaluate to a literal: %s", ss.str());
00067         delete left;
00068         delete right;
00069         return NULL;
00070       }
00071       RSLLiteral *result = new RSLLiteral(nleft->Value() + nright->Value());
00072       delete left;
00073       delete right;
00074       return result;
00075     }
00076     else if ((l = dynamic_cast<const RSLList*>(this))) {
00077       RSLList *result = new RSLList;
00078       for (std::list<RSLValue*>::const_iterator it = l->begin();
00079            it != l->end(); it++) {
00080         RSLValue *value = (*it)->Evaluate(vars);
00081         if (!value) {
00082           std::stringstream ss;
00083           ss << **it;
00084           logger.msg(ERROR, "Can't evaluate RSL list member: %s", ss.str());
00085           delete result;
00086           return NULL;
00087         }
00088         result->Add(value);
00089       }
00090       return result;
00091     }
00092     else if ((s = dynamic_cast<const RSLSequence*>(this))) {
00093       RSLList *result = new RSLList;
00094       for (std::list<RSLValue*>::const_iterator it = s->begin();
00095            it != s->end(); it++) {
00096         RSLValue *value = (*it)->Evaluate(vars);
00097         if (!value) {
00098           std::stringstream ss;
00099           ss << **it;
00100           logger.msg(ERROR, "Can't evaluate RSL sequence member: %s", ss.str());
00101           delete result;
00102           return NULL;
00103         }
00104         result->Add(value);
00105       }
00106       return new RSLSequence(result);
00107     }
00108     else {
00109       logger.msg(ERROR, "Unknown RSL value type - should not happen");
00110       return NULL;
00111     }
00112   }
00113 
00114   RSLLiteral::RSLLiteral(const std::string& str)
00115     : RSLValue(),
00116       str(str) {}
00117 
00118   RSLLiteral::~RSLLiteral() {}
00119 
00120   void RSLLiteral::Print(std::ostream& os) const {
00121     std::string s(str);
00122     std::string::size_type pos = 0;
00123     while ((pos = s.find('"', pos)) != std::string::npos) {
00124       s.insert(pos, 1, '"');
00125       pos += 2;
00126     }
00127     os << '"' << s << '"';
00128   }
00129 
00130   RSLVariable::RSLVariable(const std::string& var)
00131     : RSLValue(),
00132       var(var) {}
00133 
00134   RSLVariable::~RSLVariable() {}
00135 
00136   void RSLVariable::Print(std::ostream& os) const {
00137     os << "$(" << var << ')';
00138   }
00139 
00140   RSLConcat::RSLConcat(RSLValue *left, RSLValue *right)
00141     : RSLValue(),
00142       left(left),
00143       right(right) {}
00144 
00145   RSLConcat::~RSLConcat() {
00146     delete left;
00147     delete right;
00148   }
00149 
00150   void RSLConcat::Print(std::ostream& os) const {
00151     os << *left << " # " << *right;
00152   }
00153 
00154   RSLList::RSLList()
00155     : RSLValue() {}
00156 
00157   RSLList::~RSLList() {
00158     for (std::list<RSLValue*>::iterator it = begin(); it != end(); it++)
00159       delete *it;
00160   }
00161 
00162   void RSLList::Add(RSLValue *value) {
00163     values.push_back(value);
00164   }
00165 
00166   void RSLList::Print(std::ostream& os) const {
00167     for (std::list<RSLValue*>::const_iterator it = begin();
00168          it != end(); it++) {
00169       if (it != begin())
00170         os << " ";
00171       os << **it;
00172     }
00173   }
00174 
00175   RSLSequence::RSLSequence(RSLList *seq)
00176     : RSLValue(),
00177       seq(seq) {}
00178 
00179   RSLSequence::~RSLSequence() {
00180     delete seq;
00181   }
00182 
00183   void RSLSequence::Print(std::ostream& os) const {
00184     os << "( " << *seq << " )";
00185   }
00186 
00187   RSL::RSL() {}
00188 
00189   RSL::~RSL() {}
00190 
00191   RSL* RSL::Evaluate() const {
00192     const RSLBoolean *b = dynamic_cast<const RSLBoolean*>(this);
00193     if (b && (b->Op() == RSLMulti)) {
00194       RSLBoolean *result = new RSLBoolean(RSLMulti);
00195       for (std::list<RSL*>::const_iterator it = b->begin();
00196            it != b->end(); it++) {
00197         RSL *rsl = (*it)->Evaluate();
00198         if (!rsl) {
00199           std::stringstream ss;
00200           ss << **it;
00201           logger.msg(ERROR, "RLS (inside multi) could not be evaluated: %s",
00202                      ss.str());
00203           delete rsl;
00204           return NULL;
00205         }
00206         result->Add(rsl);
00207       }
00208       return result;
00209     }
00210     else {
00211       std::map<std::string, std::string> vars;
00212       RSL *result = Evaluate(vars);
00213       if (!result) {
00214         std::stringstream ss;
00215         ss << *this;
00216         logger.msg(ERROR, "RLS could not be evaluated: %s", ss.str());
00217         return NULL;
00218       }
00219       return result;
00220     }
00221   }
00222 
00223   RSL* RSL::Evaluate(std::map<std::string, std::string>& vars) const {
00224     const RSLBoolean *b;
00225     const RSLCondition *c;
00226     if ((b = dynamic_cast<const RSLBoolean*>(this))) {
00227       if (b->Op() == RSLMulti) {
00228         logger.msg(ERROR, "RSL multi operator not at top level");
00229         return NULL;
00230       }
00231       else {
00232         RSLBoolean *result = new RSLBoolean(b->Op());
00233         std::map<std::string, std::string> vars2(vars);
00234         for (std::list<RSL*>::const_iterator it = b->begin();
00235              it != b->end(); it++) {
00236           RSL *rsl = (*it)->Evaluate(vars2);
00237           if (!rsl) {
00238             std::stringstream ss;
00239             ss << **it;
00240             logger.msg(ERROR, "Can't evaluate RLS fragment: %s", ss.str());
00241             delete rsl;
00242             return NULL;
00243           }
00244           result->Add(rsl);
00245         }
00246         return result;
00247       }
00248     }
00249     else if ((c = dynamic_cast<const RSLCondition*>(this))) {
00250       RSLList *l = new RSLList;
00251       if (c->Attr() == "rslsubstitution") // Underscore, in 'rsl_substitution', is removed by normalization.
00252         for (std::list<RSLValue*>::const_iterator it = c->begin();
00253              it != c->end(); it++) {
00254           const RSLSequence *s = dynamic_cast<const RSLSequence*>(*it);
00255           if (!s) {
00256             std::stringstream ss;
00257             ss << **it;
00258             logger.msg(ERROR, "RLS substitution is not a sequence: %s",
00259                        ss.str());
00260             delete l;
00261             return NULL;
00262           }
00263           if (s->size() != 2) {
00264             std::stringstream ss;
00265             ss << *s;
00266             logger.msg(ERROR, "RLS substitution sequence is not of "
00267                        "length 2: %s", ss.str());
00268             delete l;
00269             return NULL;
00270           }
00271           std::list<RSLValue*>::const_iterator it2 = s->begin();
00272           RSLValue *var = (*it2)->Evaluate(vars);
00273           if (!var) {
00274             std::stringstream ss;
00275             ss << **it2;
00276             logger.msg(ERROR, "Can't evaluate RLS substitution variable "
00277                        "name: %s", ss.str());
00278             delete l;
00279             return NULL;
00280           }
00281           it2++;
00282           RSLValue *val = (*it2)->Evaluate(vars);
00283           if (!val) {
00284             std::stringstream ss;
00285             ss << **it2;
00286             logger.msg(ERROR, "Can't evaluate RLS substitution variable "
00287                        "value: %s", ss.str());
00288             delete l;
00289             delete var;
00290             return NULL;
00291           }
00292           RSLLiteral *nvar = dynamic_cast<RSLLiteral*>(var);
00293           if (!nvar) {
00294             std::stringstream ss;
00295             ss << *var;
00296             logger.msg(ERROR, "RLS substitution variable name does not "
00297                        "evaluate to a literal: %s", ss.str());
00298             delete l;
00299             delete var;
00300             delete val;
00301             return NULL;
00302           }
00303           RSLLiteral *nval = dynamic_cast<RSLLiteral*>(val);
00304           if (!nval) {
00305             std::stringstream ss;
00306             ss << *val;
00307             logger.msg(ERROR, "RLS substitution variable value does not "
00308                        "evaluate to a literal: %s", ss.str());
00309             delete l;
00310             delete var;
00311             delete val;
00312             return NULL;
00313           }
00314           vars[nvar->Value()] = nval->Value();
00315           RSLList *seq = new RSLList;
00316           seq->Add(var);
00317           seq->Add(val);
00318           l->Add(new RSLSequence(seq));
00319         }
00320       else
00321         for (std::list<RSLValue*>::const_iterator it = c->begin();
00322              it != c->end(); it++) {
00323           RSLValue *v = (*it)->Evaluate(vars);
00324           if (!v) {
00325             std::stringstream ss;
00326             ss << **it;
00327             logger.msg(ERROR, "Can't evaluate RSL condition value: %s",
00328                        ss.str());
00329             delete l;
00330             return NULL;
00331           }
00332           l->Add(v);
00333         }
00334       return new RSLCondition(c->Attr(), c->Op(), l);
00335     }
00336     else {
00337       logger.msg(ERROR, "Unknown RSL type - should not happen");
00338       return NULL;
00339     }
00340   }
00341 
00342   RSLBoolean::RSLBoolean(RSLBoolOp op)
00343     : RSL(),
00344       op(op) {}
00345 
00346   RSLBoolean::~RSLBoolean() {
00347     for (std::list<RSL*>::iterator it = begin(); it != end(); it++)
00348       delete *it;
00349   }
00350 
00351   void RSLBoolean::Add(RSL *condition) {
00352     conditions.push_back(condition);
00353   }
00354 
00355   void RSLBoolean::Print(std::ostream& os) const {
00356     os << op;
00357     for (std::list<RSL*>::const_iterator it = begin(); it != end(); it++)
00358       os << "( " << **it << " )";
00359   }
00360 
00361   RSLCondition::RSLCondition(const std::string& attr,
00362                              RSLRelOp op, RSLList *values)
00363     : RSL(),
00364       attr(attr),
00365       op(op),
00366       values(values) {
00367     // Normalize the attribute name
00368     // Does the same thing as globus_rsl_assist_attributes_canonicalize,
00369     // i.e. lowercase the attribute name and remove underscores
00370     this->attr = lower(this->attr);
00371     std::string::size_type pos = 0;
00372     while ((pos = this->attr.find('_', pos)) != std::string::npos)
00373       this->attr.erase(pos, 1);
00374   }
00375 
00376   RSLCondition::~RSLCondition() {
00377     delete values;
00378   }
00379 
00380   void RSLCondition::Print(std::ostream& os) const {
00381     os << attr << ' ' << op << ' ' << *values;
00382   }
00383 
00384   RSLParser::RSLParser(const std::string s)
00385     : s(s),
00386       n(0),
00387       parsed(NULL),
00388       evaluated(NULL) {}
00389 
00390   RSLParser::~RSLParser() {
00391     if (parsed)
00392       delete parsed;
00393     if (evaluated)
00394       delete evaluated;
00395   }
00396 
00397   const RSL* RSLParser::Parse(bool evaluate) {
00398     if (n == 0) {
00399       std::string::size_type pos = 0;
00400       while ((pos = s.find("(*", pos)) != std::string::npos) {
00401         std::string::size_type pos2 = s.find("*)", pos);
00402         if (pos2 == std::string::npos) {
00403           logger.msg(ERROR, "End of comment not found at position %ld", pos);
00404           return NULL;
00405         }
00406         s.replace(pos, pos2 - pos + 2, 1, ' ');
00407       }
00408       parsed = ParseRSL();
00409       if (!parsed)
00410         logger.msg(VERBOSE, "RSL parsing failed at position %ld", n);
00411       else {
00412         SkipWS();
00413         if (n != std::string::npos) {
00414           logger.msg(ERROR, "Junk at end of RSL at position %ld", n);
00415           delete parsed;
00416         }
00417       }
00418       if (parsed)
00419         evaluated = parsed->Evaluate();
00420     }
00421     return evaluate ? evaluated : parsed;
00422   }
00423 
00424   void RSLParser::SkipWS() {
00425     n = s.find_first_not_of(" \t\n\v\f\r", n);
00426   }
00427 
00428   RSLBoolOp RSLParser::ParseBoolOp() {
00429     switch (s[n]) {
00430     case '+':
00431       n++;
00432       return RSLMulti;
00433       break;
00434 
00435     case '&':
00436       n++;
00437       return RSLAnd;
00438       break;
00439 
00440     case '|':
00441       n++;
00442       return RSLOr;
00443       break;
00444 
00445     default:
00446       return RSLBoolError;
00447       break;
00448     }
00449   }
00450 
00451   RSLRelOp RSLParser::ParseRelOp() {
00452     switch (s[n]) {
00453     case '=':
00454       n++;
00455       return RSLEqual;
00456       break;
00457 
00458     case '!':
00459       if (s[n + 1] == '=') {
00460         n += 2;
00461         return RSLNotEqual;
00462       }
00463       return RSLRelError;
00464       break;
00465 
00466     case '<':
00467       n++;
00468       if (s[n] == '=') {
00469         n++;
00470         return RSLLessOrEqual;
00471       }
00472       return RSLLess;
00473       break;
00474 
00475     case '>':
00476       n++;
00477       if (s[n] == '=') {
00478         n++;
00479         return RSLGreaterOrEqual;
00480       }
00481       return RSLGreater;
00482       break;
00483 
00484     default:
00485       return RSLRelError;
00486       break;
00487     }
00488   }
00489 
00490   std::string RSLParser::ParseString(int& status) {
00491     // status: 1 - OK, 0 - not a string, -1 - error
00492     if (s[n] == '\'') {
00493       std::string str;
00494       do {
00495         std::string::size_type pos = s.find('\'', n + 1);
00496         if (pos == std::string::npos) {
00497           logger.msg(ERROR, "End of single quoted string not found "
00498                      "at position %ld", n);
00499           status = -1;
00500           return "";
00501         }
00502         str += s.substr(n + 1, pos - n - 1);
00503         n = pos + 1;
00504         if (s[n] == '\'')
00505           str += '\'';
00506       } while (s[n] == '\'');
00507       status = 1;
00508       return str;
00509     }
00510     else if (s[n] == '"') {
00511       std::string str;
00512       do {
00513         std::string::size_type pos = s.find('"', n + 1);
00514         if (pos == std::string::npos) {
00515           logger.msg(ERROR, "End of double quoted string not found "
00516                      "at position %ld", n);
00517           status = -1;
00518           return "";
00519         }
00520         str += s.substr(n + 1, pos - n - 1);
00521         n = pos + 1;
00522         if (s[n] == '"')
00523           str += '"';
00524       } while (s[n] == '"');
00525       status = 1;
00526       return str;
00527     }
00528     else if (s[n] == '^') {
00529       n++;
00530       char delim = s[n];
00531       std::string str;
00532       do {
00533         std::string::size_type pos = s.find(delim, n + 1);
00534         if (pos == std::string::npos) {
00535           logger.msg(ERROR, "End of user delimiter quoted string not found "
00536                      "at position %ld", n);
00537           status = -1;
00538           return "";
00539         }
00540         str += s.substr(n + 1, pos - n - 1);
00541         n = pos + 1;
00542         if (s[n] == delim)
00543           str += delim;
00544       } while (s[n] == delim);
00545       status = 1;
00546       return str;
00547     }
00548     else {
00549       std::string::size_type pos =
00550         s.find_first_of("+&|()=<>!\"'^#$ \t\n\v\f\r", n);
00551       if (pos == n) {
00552         status = 0;
00553         return "";
00554       }
00555       std::string str = s.substr(n, pos - n);
00556       n = pos;
00557       status = 1;
00558       return str;
00559     }
00560   }
00561 
00562   RSLList* RSLParser::ParseList() {
00563 
00564     RSLList *values = new RSLList();
00565     RSLValue *left = NULL;
00566     RSLValue *right = NULL;
00567 
00568     try {
00569       int concat = 0; // 0 = No, 1 = Explicit, 2 = Implicit
00570       do {
00571         right = NULL;
00572         int nextconcat = 0;
00573         std::string::size_type nsave = n;
00574         SkipWS();
00575         if (n != nsave)
00576           concat = 0;
00577         if (s[n] == '#') {
00578           n++;
00579           SkipWS();
00580           concat = 1;
00581         }
00582         if (s[n] == '(') {
00583           n++;
00584           RSLList *seq = ParseList();
00585           SkipWS();
00586           if (s[n] != ')') {
00587             logger.msg(ERROR, "Expected ) at position %ld", n);
00588             throw std::exception();
00589           }
00590           n++;
00591           right = new RSLSequence(seq);
00592         }
00593         else if (s[n] == '$') {
00594           n++;
00595           SkipWS();
00596           if (s[n] != '(') {
00597             logger.msg(ERROR, "Expected ( at position %ld", n);
00598             throw std::exception();
00599           }
00600           n++;
00601           SkipWS();
00602           int status;
00603           std::string var = ParseString(status);
00604           if (status != 1) {
00605             logger.msg(ERROR, "Expected variable name at position %ld", n);
00606             throw std::exception();
00607           }
00608           if (var.find_first_of("+&|()=<>!\"'^#$") != std::string::npos) {
00609             logger.msg(ERROR, "Variable name contains invalid character "
00610                        "at position %ld", n);
00611             throw std::exception();
00612           }
00613           SkipWS();
00614           if (s[n] != ')') {
00615             logger.msg(ERROR, "Expected ) at position %ld", n);
00616             throw std::exception();
00617           }
00618           n++;
00619           right = new RSLVariable(var);
00620           nextconcat = 2;
00621         }
00622         else {
00623           int status;
00624           std::string val = ParseString(status);
00625           if (status == -1) {
00626             logger.msg(ERROR, "Broken string at position %ld", n);
00627             throw std::exception();
00628           }
00629           right = (status == 1) ? new RSLLiteral(val) : NULL;
00630           nextconcat = right ? 2 : 0;
00631         }
00632         if (concat == 0) {
00633           if (left)
00634             values->Add(left);
00635           left = right;
00636         }
00637         else if (concat == 1) {
00638           if (!left) {
00639             logger.msg(ERROR, "no left operand for concatenation operator "
00640                        "at position %ld", n);
00641             throw std::exception();
00642           }
00643           if (!right) {
00644             logger.msg(ERROR, "no right operand for concatenation operator "
00645                        "at position %ld", n);
00646             throw std::exception();
00647           }
00648           left = new RSLConcat(left, right);
00649         }
00650         else if (concat == 2) {
00651           if (left) {
00652             if (right)
00653               left = new RSLConcat(left, right);
00654           }
00655           else
00656             left = right;
00657         }
00658         concat = nextconcat;
00659       } while (left || right);
00660       return values;
00661     } catch (std::exception e) {
00662       if (values)
00663         delete values;
00664       if (left)
00665         delete left;
00666       if (right)
00667         delete right;
00668       return NULL;
00669     }
00670   }
00671 
00672   RSL* RSLParser::ParseRSL() {
00673     SkipWS();
00674     RSLBoolOp op = ParseBoolOp();
00675     if (op != RSLBoolError) {
00676       SkipWS();
00677       RSLBoolean *b = new RSLBoolean(op);
00678       do {
00679         if (s[n] != '(') {
00680           logger.msg(ERROR, "Expected ( at position %ld", n);
00681           delete b;
00682           return NULL;
00683         }
00684         n++;
00685         SkipWS();
00686         RSL *rsl = ParseRSL();
00687         if (!rsl) {
00688           logger.msg(ERROR, "RSL parsing error at position %ld", n);
00689           delete b;
00690           return NULL;
00691         }
00692         b->Add(rsl);
00693         SkipWS();
00694         if (s[n] != ')') {
00695           logger.msg(ERROR, "Expected ) at position %ld", n);
00696           delete b;
00697           return NULL;
00698         }
00699         n++;
00700         SkipWS();
00701       } while (s[n] == '(');
00702       return b;
00703     }
00704     else {
00705       int status;
00706       std::string attr = ParseString(status);
00707       if (status != 1) {
00708         logger.msg(VERBOSE, "Expected attribute name at position %ld", n);
00709         return NULL;
00710       }
00711       if (attr.find_first_of("+&|()=<>!\"'^#$") != std::string::npos) {
00712         logger.msg(ERROR, "Attribute name contains invalid character "
00713                    "at position %ld", n);
00714         return NULL;
00715       }
00716       SkipWS();
00717       RSLRelOp op = ParseRelOp();
00718       if (op == RSLRelError) {
00719         logger.msg(VERBOSE, "Expected relation operator at position %ld", n);
00720         return NULL;
00721       }
00722       SkipWS();
00723       RSLList *values = ParseList();
00724       if (!values) {
00725         logger.msg(ERROR, "RSL parsing error at position %ld", n);
00726         return NULL;
00727       }
00728       RSLCondition *c = new RSLCondition(attr, op, values);
00729       return c;
00730     }
00731   }
00732 
00733   Logger RSLValue::logger(Logger::getRootLogger(), "RSLValue");
00734   Logger RSL::logger(Logger::getRootLogger(), "RSL");
00735   Logger RSLParser::logger(Logger::getRootLogger(), "RSLParser");
00736 
00737   std::ostream& operator<<(std::ostream& os, const RSLBoolOp op) {
00738     switch (op) {
00739     case RSLBoolError:
00740       return os << "This should not happen";
00741 
00742     case RSLMulti:
00743       return os << '+';
00744 
00745     case RSLAnd:
00746       return os << '&';
00747 
00748     case RSLOr:
00749       return os << '|';
00750     }
00751   }
00752 
00753   std::ostream& operator<<(std::ostream& os, const RSLRelOp op) {
00754     switch (op) {
00755     case RSLRelError:
00756       return os << "This should not happen";
00757 
00758     case RSLEqual:
00759       return os << '=';
00760 
00761     case RSLNotEqual:
00762       return os << "!=";
00763 
00764     case RSLLess:
00765       return os << '<';
00766 
00767     case RSLGreater:
00768       return os << '>';
00769 
00770     case RSLLessOrEqual:
00771       return os << "<=";
00772 
00773     case RSLGreaterOrEqual:
00774       return os << ">=";
00775     }
00776   }
00777 
00778   std::ostream& operator<<(std::ostream& os, const RSLValue& value) {
00779     value.Print(os);
00780     return os;
00781   }
00782 
00783   std::ostream& operator<<(std::ostream& os, const RSL& rsl) {
00784     rsl.Print(os);
00785     return os;
00786   }
00787 
00788 } // namespace Arc