AttributeParser.cc

Go to the documentation of this file.
00001 // $Id: AttributeParser.cc 238 2006-06-29 17:28:25Z bingmann $
00002 
00003 // #define BOOST_SPIRIT_DEBUG
00004 
00005 #include "GraphContainer.h"
00006 
00007 #include "AttributeParser.h"
00008 #include "AttributeProperties.h"
00009 #include "GraphProperties.h"
00010 #include "GraphPort.h"
00011 
00012 #include "AttributeBlob_impl.h"
00013 
00014 #include "ByteOutBuffer.h"
00015 
00016 #include <boost/spirit/core.hpp>
00017 
00018 #include <boost/spirit/tree/ast.hpp>
00019 
00020 #include <boost/spirit/utility/lists.hpp>
00021 #include <boost/spirit/utility/distinct.hpp>
00022 #include <boost/spirit/utility/escape_char.hpp>
00023 #include <boost/spirit/utility/grammar_def.hpp> 
00024 
00025 #include <boost/spirit/dynamic/if.hpp>
00026 
00027 #ifdef BOOST_SPIRIT_DEBUG
00028 #include <boost/spirit/tree/tree_to_xml.hpp>
00029 #endif
00030 
00031 #include <iostream>
00032 #include <sstream>
00033 
00034 namespace VGServer {
00035 
00038 namespace AttributeParser {
00039 
00040 using namespace boost::spirit;
00041 
00042 // this enum specifies ids for the parse tree nodes created for each rule.
00043 enum parser_ids
00044 {
00045     integer_const_id = 1,
00046     double_const_id,
00047     string_const_id,
00048     constant_id,
00049 
00050     function_call_id,
00051     function_identifier_id,
00052 
00053     attrname_id,
00054 
00055     atom_expr_id,
00056 
00057     unary_expr_id,
00058     mul_expr_id,
00059     add_expr_id,
00060 
00061     cast_expr_id,
00062     cast_spec_id,
00063 
00064     comp_expr_id,
00065     and_expr_id,
00066     or_expr_id,
00067 
00068     expr_id,
00069 
00070     attrlist_star_id,
00071     attrlist_exprlist_id,
00072     attrlist_id,
00073 
00074     filter_expr_id,
00075 };
00076 
00078 distinct_parser<> keyword_p("a-zA-Z0-9_");
00079 
00081 struct AttributeGrammar : public grammar<AttributeGrammar>
00082 {
00083     template <typename ScannerT>
00084     struct definition : public grammar_def<rule<ScannerT, parser_context<>, parser_tag<attrlist_id> >,
00085                                            rule<ScannerT, parser_context<>, parser_tag<filter_expr_id> > >
00086     {
00087         definition(AttributeGrammar const& /*self*/)
00088         {
00089             // *** Constants
00090 
00091             constant
00092                 = double_const
00093                 | integer_const
00094                 | string_const
00095                 ;
00096             
00097             integer_const
00098                 = int_p
00099                 ;
00100 
00101             double_const
00102                 = strict_real_p
00103                 ;
00104 
00105             string_const
00106                 = lexeme_d[
00107                     token_node_d[ '"' >> *(c_escape_ch_p - '"') >> '"' ]
00108                     ]
00109                 ;
00110 
00111             // *** Function call and function identifier
00112 
00113             function_call
00114                 = function_identifier >> discard_node_d[ ch_p('(') ] 
00115                                       >> infix_node_d[ !list_p(expr, ch_p(',')) ]
00116                                       >> discard_node_d[ ch_p(')') ]
00117                 ;
00118 
00119             function_identifier
00120                 = lexeme_d[ 
00121                     token_node_d[ alpha_p >> *(alnum_p | ch_p('_')) ]
00122                     ]
00123                 ;
00124 
00125             // *** Attribute names
00126 
00127             attrname
00128                 = lexeme_d[ 
00129                     token_node_d[ alpha_p >> *(alnum_p | ch_p('_'))
00130                                   >> !( ch_p('.') >> alpha_p >> *(alnum_p | ch_p('_')) ) ]
00131                     ]
00132                 ;
00133             // *** Valid Expressions, from small to large
00134 
00135             atom_expr
00136                 = constant
00137                 | inner_node_d[ ch_p('(') >> expr >> ch_p(')') ]
00138                 // TODO: we want function calls? | function_call
00139                 | attrname
00140                 ;
00141 
00142             unary_expr
00143                 = !( root_node_d[ch_p('+') | ch_p('-') | ch_p('!') | str_p("not")] )
00144                     >> atom_expr
00145                 ;
00146 
00147             mul_expr
00148                 = unary_expr >>
00149                   *( root_node_d[ch_p('*')] >> unary_expr 
00150                    | root_node_d[ch_p('/')] >> unary_expr )
00151                 ;
00152 
00153             add_expr
00154                 = mul_expr >>
00155                   *( root_node_d[ch_p('+')] >> mul_expr
00156                    | root_node_d[ch_p('-')] >> mul_expr )
00157                 ;
00158 
00159             cast_spec
00160                 = as_lower_d[
00161                     discard_node_d[ keyword_p("cast") ] >>
00162                     (
00163                         keyword_p("bool") |
00164                         keyword_p("char") | keyword_p("short") | keyword_p("integer") | keyword_p("long") |
00165                         keyword_p("byte") | keyword_p("word") | keyword_p("dword") | keyword_p("qword") |
00166                         keyword_p("float") | keyword_p("double") |
00167                         keyword_p("string") | keyword_p("longstring")
00168                      )
00169                     ]
00170                 ;
00171 
00172             cast_expr
00173                 = add_expr >> root_node_d[ !cast_spec ]
00174                 ;
00175 
00176             comp_expr
00177                 = cast_expr >>
00178                 *( root_node_d[str_p("==")] >> cast_expr 
00179                  | root_node_d[ch_p('=')] >> cast_expr
00180                  | root_node_d[str_p("!=")] >> cast_expr
00181                  | root_node_d[ch_p('<')] >> cast_expr
00182                  | root_node_d[ch_p('>')] >> cast_expr
00183                  | root_node_d[str_p("<=")] >> cast_expr
00184                  | root_node_d[str_p(">=")] >> cast_expr
00185                  | root_node_d[str_p("=<")] >> cast_expr
00186                  | root_node_d[str_p("=>")] >> cast_expr
00187                  )
00188                 ;
00189 
00190             and_expr
00191                 = comp_expr >>
00192                 *( root_node_d[ as_lower_d[ str_p("and")] ] >> comp_expr
00193                  | root_node_d[ as_lower_d[ str_p("&&")] ] >> comp_expr
00194                  )
00195                 ;
00196 
00197             or_expr
00198                 = and_expr >>
00199                 *( root_node_d[ as_lower_d[ str_p("or")] ] >> and_expr
00200                  | root_node_d[ as_lower_d[ str_p("||")] ] >> and_expr
00201                  )
00202                 ;
00203 
00204             expr
00205                 = or_expr
00206                 ;
00207 
00208             // *** Rules for the attribute selector list parser
00209             
00210             attrlist_star
00211                 = ch_p('*')
00212                 ;
00213 
00214             attrlist_exprlist
00215                 = infix_node_d[ !list_p(expr, ch_p(',')) ]
00216                 ;
00217 
00218             attrlist
00219                 = attrlist_star
00220                 | attrlist_exprlist
00221                 ;
00222 
00223             // *** Rules for the filter parser
00224 
00225             filter_expr
00226                 = !( root_node_d[ keyword_p("vertex:")
00227                                 | keyword_p("vertices:")
00228                                 | keyword_p("vertics:")
00229                                 | keyword_p("v:")
00230                                 | keyword_p("edge:")
00231                                 | keyword_p("edges:")
00232                                 | keyword_p("e:") ]
00233                      >> expr )
00234                 ;
00235 
00236             // this is a special spirit feature to declare multiple grammar entry points
00237             this->start_parsers(attrlist, filter_expr); 
00238 
00239 #ifdef BOOST_SPIRIT_DEBUG
00240             BOOST_SPIRIT_DEBUG_RULE(constant);
00241 
00242             BOOST_SPIRIT_DEBUG_RULE(integer_const);
00243             BOOST_SPIRIT_DEBUG_RULE(double_const);
00244             BOOST_SPIRIT_DEBUG_RULE(string_const);
00245 
00246             BOOST_SPIRIT_DEBUG_RULE(function_call);
00247             BOOST_SPIRIT_DEBUG_RULE(function_identifier);
00248             
00249             BOOST_SPIRIT_DEBUG_RULE(attrname);
00250 
00251             BOOST_SPIRIT_DEBUG_RULE(atom_expr);
00252 
00253             BOOST_SPIRIT_DEBUG_RULE(unary_expr);
00254             BOOST_SPIRIT_DEBUG_RULE(mul_expr);
00255             BOOST_SPIRIT_DEBUG_RULE(add_expr);
00256 
00257             BOOST_SPIRIT_DEBUG_RULE(cast_spec);
00258             BOOST_SPIRIT_DEBUG_RULE(cast_expr);
00259 
00260             BOOST_SPIRIT_DEBUG_RULE(comp_expr);
00261             BOOST_SPIRIT_DEBUG_RULE(and_expr);
00262             BOOST_SPIRIT_DEBUG_RULE(or_expr);
00263 
00264             BOOST_SPIRIT_DEBUG_RULE(expr);
00265 
00266             BOOST_SPIRIT_DEBUG_RULE(attrlist_star);
00267             BOOST_SPIRIT_DEBUG_RULE(attrlist_exprlist);
00268             BOOST_SPIRIT_DEBUG_RULE(attrlist);
00269 
00270             BOOST_SPIRIT_DEBUG_RULE(filter_expr);
00271 #endif
00272         }
00273 
00274         rule<ScannerT, parser_context<>, parser_tag<constant_id> >              constant;
00275 
00276         rule<ScannerT, parser_context<>, parser_tag<integer_const_id> >         integer_const;
00277         rule<ScannerT, parser_context<>, parser_tag<double_const_id> >          double_const;
00278         rule<ScannerT, parser_context<>, parser_tag<string_const_id> >          string_const;
00279 
00280         rule<ScannerT, parser_context<>, parser_tag<function_call_id> >         function_call;
00281         rule<ScannerT, parser_context<>, parser_tag<function_identifier_id> >   function_identifier;
00282 
00283         rule<ScannerT, parser_context<>, parser_tag<attrname_id> >              attrname;
00284 
00285         rule<ScannerT, parser_context<>, parser_tag<atom_expr_id> >             atom_expr;
00286 
00287         rule<ScannerT, parser_context<>, parser_tag<unary_expr_id> >            unary_expr;
00288         rule<ScannerT, parser_context<>, parser_tag<mul_expr_id> >              mul_expr;
00289         rule<ScannerT, parser_context<>, parser_tag<add_expr_id> >              add_expr;
00290 
00291         rule<ScannerT, parser_context<>, parser_tag<cast_spec_id> >             cast_spec;
00292         rule<ScannerT, parser_context<>, parser_tag<cast_expr_id> >             cast_expr;
00293 
00294         rule<ScannerT, parser_context<>, parser_tag<comp_expr_id> >             comp_expr;
00295         rule<ScannerT, parser_context<>, parser_tag<and_expr_id> >              and_expr;
00296         rule<ScannerT, parser_context<>, parser_tag<or_expr_id> >               or_expr;
00297 
00298         rule<ScannerT, parser_context<>, parser_tag<expr_id> >                  expr;
00299 
00300         rule<ScannerT, parser_context<>, parser_tag<attrlist_star_id> >         attrlist_star;
00301         rule<ScannerT, parser_context<>, parser_tag<attrlist_exprlist_id> >     attrlist_exprlist;
00302         rule<ScannerT, parser_context<>, parser_tag<attrlist_id> >              attrlist;
00303 
00304         rule<ScannerT, parser_context<>, parser_tag<filter_expr_id> >           filter_expr;
00305     };
00306 };
00307 
00308 // *** Classes representing the nodes in the resulting parse tree, these need
00309 // *** not be publicly available via the header file.
00310 
00313 class PNConstant : public ParseNode
00314 {
00315 private:
00317     class AnyType       val;
00318 
00319 public:
00321     PNConstant(attrtype_t type, std::string strvalue)
00322         : ParseNode(), val(type)
00323     {
00324         if (type == ATTRTYPE_STRING)
00325             val.setStringQuoted(strvalue);
00326         else
00327             val.setString(strvalue);
00328     }
00329 
00331     PNConstant(const AnyType &_val)
00332         : val(_val)
00333     {
00334     }
00335 
00337     virtual bool getValue(AnyType &dest, const class GraphContainer& , const class Changelist& ,
00338                           vertex_or_edge_t , unsigned int , unsigned int ) const
00339     {
00340         dest = val;
00341         return true;
00342     }
00343 
00345     virtual bool getConstVal(AnyType *dest) const
00346     {
00347         if (dest) *dest = val;
00348         return true;
00349     }
00350 
00352     virtual std::string toString() const
00353     {
00354         return val.getString();
00355     }
00356 };
00357 
00358 #define WITH_CHANGELIST
00359 
00363 class PNAttributeName : public ParseNode
00364 {
00365 private:
00367     std::string         attrname;
00368 
00370     unsigned int        attrid;
00371 
00373     AnyType             attrval;
00374 
00375 public:
00377     PNAttributeName(std::string _attrname, const AttributePropertiesList &attrlist, vertex_or_edge_t voe)
00378         : ParseNode(), attrname(_attrname), attrval(ATTRTYPE_INVALID)
00379     {
00380         if (voe == VE_VERTEX and attrname == "id") {
00381             attrid = UINT_MAX;
00382             attrval = 0U;
00383             return;
00384         }
00385 
00386         int _attrid = attrlist.lookupAttributeName(attrname);
00387         if (_attrid < 0)
00388             throw(AttributeParseException("Unknown attribute name " + attrname + ". Remember they are case-sensitive."));
00389 
00390         attrid = _attrid;
00391         attrval = attrlist[attrid];
00392     }
00393 
00396     virtual bool getValue(AnyType &dest, const class GraphContainer &gc, const class Changelist &cl,
00397                           vertex_or_edge_t wantedge, unsigned int vid1, unsigned int vid2) const
00398     {
00399         if (not wantedge) // vertex attribute selection
00400         {
00401             if (attrid == UINT_MAX) {
00402                 dest = vid1;
00403                 return true;
00404             }
00405 
00406             assert( attrid < gc.getProperties().vertexattr.size() );
00407             assert( gc.getProperties().vertexattr[attrid].name == attrname );
00408 
00409 #ifdef WITH_CHANGELIST
00410             VertexRef vr = gc.getVertex(vid1, cl);
00411             if (!vr.valid())
00412             {
00413                 dest = gc.getProperties().vertexattr[attrid];
00414                 return false;
00415             }
00416             else
00417             {
00418                 dest = vr.getAttr(attrid);
00419             }
00420 #else
00421             if (!gc.existVertex(vid1))
00422                 return false;
00423 
00424             const GraphData::Vertex* vp = static_cast<const GraphData&>(gc).getVertex(vid1);
00425             
00426             dest = vp->getAttr(attrid, gc);
00427 #endif
00428         }
00429         else
00430         {
00431             // edge attribute selector
00432 
00433             assert( attrid < gc.getProperties().edgeattr.size() );
00434             assert( gc.getProperties().edgeattr[attrid].name == attrname );
00435 
00436 #ifdef WITH_CHANGELIST
00437             EdgeRef er = gc.getEdge(vid1, vid2, cl);
00438             if (!er.valid())
00439             {
00440                 dest = gc.getProperties().edgeattr[attrid];
00441                 return false;
00442             }
00443             else
00444             {
00445                 dest = er.getAttr(attrid);
00446             }
00447 #else
00448             const GraphData::Edge *ep = static_cast<const GraphData&>(gc).getEdge(vid1, vid2);
00449             
00450             if (!ep)
00451             {
00452                 dest = gc.getProperties().edgeattr[attrid];
00453                 return false;
00454             }
00455             else
00456             {
00457                 dest = ep->getAttr(attrid, gc);
00458             }
00459 #endif
00460         }
00461         return true;
00462     }
00463 
00465     virtual bool getConstVal(AnyType *dest) const
00466     {
00467         if (dest) *dest = attrval;
00468         return false;
00469     }
00470 
00472     virtual std::string toString() const
00473     {
00474         return attrname;
00475     }
00476 };
00477 
00481 class PNAttributeDotName : public ParseNode
00482 {
00483 private:
00485     std::string         fullname, attrname;
00486 
00488     unsigned int        attrid;
00489 
00491     AnyType             attrval;
00492 
00494     bool                src_or_tgt;
00495 
00496 public:
00498     PNAttributeDotName(std::string _attrname, const GraphProperties &gp, vertex_or_edge_t voe)
00499         : ParseNode(), fullname(_attrname), attrval(ATTRTYPE_INVALID)
00500     {
00501         if (voe != VE_EDGE) {
00502             assert(0);
00503             throw(AttributeParseException("Program error: AttributeDotName not applicable to a vertex"));
00504         }
00505         
00506         // find the dot
00507         size_t dotloc = _attrname.find('.');
00508         assert(dotloc != std::string::npos);
00509 
00510         // check if the first component is either "src" or "tgt" or "s" or "t":
00511         std::string comp1 = std::string(_attrname.begin(), _attrname.begin()+dotloc);
00512 
00513         if (comp1 == "src" or comp1 == "s") src_or_tgt = false;
00514         else if (comp1 == "tgt" or comp1 == "t") src_or_tgt = true;
00515         else {
00516             throw(AttributeParseException("Unknown first component in attribute name " + attrname + ". Remember they are case-sensitive."));
00517         }
00518 
00519         std::string comp2 = std::string(_attrname.begin()+dotloc+1, _attrname.end());
00520 
00521         if (comp2 == "id") {
00522             attrname = comp2;
00523             attrid = UINT_MAX;
00524             attrval = 0U;
00525             return;
00526         }
00527 
00528         int _attrid = gp.vertexattr.lookupAttributeName(comp2);
00529         if (_attrid < 0)
00530             throw(AttributeParseException("Unknown second component in attribute name " + comp2 + ". Remember they are case-sensitive."));
00531 
00532         attrname = comp2;
00533         attrid = _attrid;
00534         attrval = gp.vertexattr[attrid];
00535     }
00536 
00539     virtual bool getValue(AnyType &dest, const class GraphContainer &gc, const class Changelist &cl,
00540                           vertex_or_edge_t wantedge, unsigned int vid1, unsigned int vid2) const
00541     {
00542         if (not wantedge) { // vertex attribute selection
00543             assert(0);
00544         }
00545         else
00546         {
00547             if (attrid == UINT_MAX) {
00548                 dest = src_or_tgt ? vid1 : vid2;
00549                 return true;
00550             }
00551 
00552             // edge attribute selector: get either source or target vertex object
00553 
00554             assert( attrid < gc.getProperties().vertexattr.size() );
00555             assert( gc.getProperties().vertexattr[attrid].name == attrname );
00556 
00557 #ifdef WITH_CHANGELIST
00558             VertexRef vr = gc.getVertex( src_or_tgt == false ? vid1 : vid2 , cl);
00559            
00560             if (!vr.valid())
00561             {
00562                 dest = gc.getProperties().vertexattr[attrid];
00563                 return false;
00564             }
00565             else
00566             {
00567                 dest = vr.getAttr(attrid);
00568             }
00569 #else
00570             if (!gc.existVertex( src_or_tgt == false ? vid1 : vid2))
00571                 return false;
00572 
00573             const GraphData::Vertex* vp = static_cast<const GraphData&>(gc).getVertex( src_or_tgt == false ? vid1 : vid2 );
00574             
00575             dest = vp->getAttr(attrid, gc);
00576 #endif
00577         }
00578         return true;
00579     }
00580 
00582     virtual bool getConstVal(AnyType *dest) const
00583     {
00584         if (dest) *dest = attrval;
00585         return false;
00586     }
00587 
00589     virtual std::string toString() const
00590     {
00591         return fullname;
00592     }
00593 };
00594 
00597 class PNUnaryArithmExpr : public ParseNode
00598 {
00599 private:
00601     const ParseNode     *opand;
00602 
00605     char        op;
00606 
00607 public:
00608     PNUnaryArithmExpr(const ParseNode* _opand, char _op)
00609         : ParseNode(), opand(_opand), op(_op)
00610     {
00611         if (op == 'n') op = '!';
00612     }
00613 
00615     virtual ~PNUnaryArithmExpr()
00616     {
00617         delete opand;
00618     }
00619 
00621     virtual bool getValue(AnyType &dest, const class GraphContainer &gc, const class Changelist &cl,
00622                           vertex_or_edge_t wantedge, unsigned int vid1, unsigned int vid2) const
00623     { 
00624         bool b = opand->getValue(dest, gc, cl, wantedge, vid1, vid2);
00625 
00626         if (op == '-') {
00627             dest = -dest;           
00628         }
00629         else if (op == '!')
00630         {
00631             // this should not happend, as types are constant in the parse tree
00632             if (dest.getType() != ATTRTYPE_BOOL)
00633                 throw(AttributeParseException("Invalid operand for !. Operand must be of type bool."));
00634 
00635             dest = -dest;
00636         }
00637         else {
00638             assert(op == '+');
00639         }
00640 
00641         return b;
00642     }
00643 
00645     virtual bool getConstVal(AnyType *dest) const
00646     {
00647         if (!dest) return false;
00648 
00649         bool b = opand->getConstVal(dest);
00650 
00651         if (op == '-') {
00652             *dest = -(*dest);
00653         }
00654         else if (op == '!')
00655         {
00656             if (dest->getType() != ATTRTYPE_BOOL)
00657                 throw(AttributeParseException("Invalid operand for !. Operand must be of type bool."));
00658 
00659             *dest = -(*dest);
00660         }
00661         else {
00662             assert(op == '+');
00663         }
00664         
00665         return b;
00666     }
00667 
00668     virtual std::string toString() const
00669     {
00670         return std::string("(") + op + " " + opand->toString() + ")";
00671     }
00672 };
00673 
00676 class PNBinaryArithmExpr : public ParseNode
00677 {
00678 private:
00680     const ParseNode     *left, *right;
00681 
00684     char        op;
00685 
00686 public:
00687     PNBinaryArithmExpr(const ParseNode* _left,
00688                        const ParseNode* _right,
00689                        char _op)
00690         : ParseNode(),
00691           left(_left), right(_right), op(_op)
00692     { }
00693 
00695     virtual ~PNBinaryArithmExpr()
00696     {
00697         delete left;
00698         delete right;
00699     }
00700 
00703     virtual bool getValue(AnyType &dest, const class GraphContainer &gc, const class Changelist &cl,
00704                           vertex_or_edge_t wantedge, unsigned int vid1, unsigned int vid2) const
00705     {
00706         AnyType vl(ATTRTYPE_INVALID), vr(ATTRTYPE_INVALID);
00707         
00708         bool bl = left->getValue(vl, gc, cl, wantedge, vid1, vid2);
00709         bool br = right->getValue(vr, gc, cl , wantedge, vid1, vid2);
00710 
00711         if (op == '+') {
00712             dest = vl + vr;
00713         }
00714         else if (op == '-') {
00715             dest = vl - vr;
00716         }
00717         else if (op == '*') {
00718             dest = vl * vr;
00719         }
00720         else if (op == '/') {
00721             dest = vl / vr;
00722         }
00723 
00724         return (bl and br);
00725     }
00726 
00728     virtual bool getConstVal(AnyType *dest) const
00729     {
00730         if (!dest) return false;
00731 
00732         AnyType vl(ATTRTYPE_INVALID), vr(ATTRTYPE_INVALID);
00733         
00734         bool bl = left->getConstVal(&vl);
00735         bool br = right->getConstVal(&vr);
00736 
00737         if (op == '+') {
00738             *dest = vl + vr;
00739         }
00740         else if (op == '-') {
00741             *dest = vl - vr;
00742         }
00743         else if (op == '*') {
00744             *dest = vl * vr;
00745         }
00746         else if (op == '/') {
00747             *dest = vl / vr;
00748         }
00749 
00750         return (bl and br);
00751     }
00752 
00754     virtual std::string toString() const
00755     {
00756         return std::string("(") + left->toString() + " " + op + " " + right->toString() + ")";
00757     }
00758 };
00759 
00761 class PNCastExpr : public ParseNode
00762 {
00763 private:
00765     const ParseNode     *val;
00766 
00768     attrtype_t  type;
00769 
00770 public:
00771     PNCastExpr(const ParseNode* _val,
00772                attrtype_t _type)
00773         : ParseNode(),
00774           val(_val), type(_type)
00775     { }
00776 
00778     virtual ~PNCastExpr()
00779     {
00780         delete val;
00781     }
00782 
00785     virtual bool getValue(AnyType &dest, const class GraphContainer &gc, const class Changelist &cl,
00786                           vertex_or_edge_t wantedge, unsigned int vid1, unsigned int vid2) const
00787     {
00788         bool b = val->getValue(dest, gc, cl, wantedge, vid1, vid2);
00789         dest.convertType(type);
00790         return b;
00791     }
00792 
00794     virtual bool getConstVal(AnyType *dest) const
00795     {
00796         if (!dest) return false;
00797 
00798         bool b = val->getConstVal(dest);
00799         dest->convertType(type);
00800         return b;
00801     }
00802 
00804     virtual std::string toString() const
00805     {
00806         return std::string("(") + val->toString() + " cast " + AnyType::getTypeString(type) + std::string(")");
00807     }
00808 };
00809 
00812 class PNBinaryComparisonExpr : public ParseNode
00813 {
00814 private:
00816     const ParseNode     *left, *right;
00817 
00819     enum { EQUAL, NOTEQUAL, LESS, GREATER, LESSEQUAL, GREATEREQUAL } op;
00820 
00822     std::string         opstr;
00823 
00824 public:
00825     PNBinaryComparisonExpr(const ParseNode* _left,
00826                            const ParseNode* _right,
00827                            std::string _op)
00828         : ParseNode(),
00829           left(_left), right(_right), opstr(_op)
00830     {
00831         if (_op == "==" or _op == "=")
00832             op = EQUAL;
00833         else if (_op == "!=")
00834             op = NOTEQUAL;
00835         else if (_op == "<")
00836             op = LESS;
00837         else if (_op == ">")
00838             op = GREATER;
00839         else if (_op == "<=" or _op == "=<")
00840             op = LESSEQUAL;
00841         else if (_op == ">=" or _op == "=>")
00842             op = GREATEREQUAL;
00843         else
00844             throw(AttributeParseException("Program Error: invalid binary comparision operator."));
00845     }
00846 
00848     virtual ~PNBinaryComparisonExpr()
00849     {
00850         delete left;
00851         delete right;
00852     }
00853 
00856     virtual bool getValue(AnyType &dest, const class GraphContainer &gc, const class Changelist &cl,
00857                           vertex_or_edge_t wantedge, unsigned int vid1, unsigned int vid2) const
00858     {
00859         AnyType vl(ATTRTYPE_INVALID), vr(ATTRTYPE_INVALID);
00860         
00861         bool bl = left->getValue(vl, gc, cl, wantedge, vid1, vid2);
00862         bool br = right->getValue(vr, gc, cl , wantedge, vid1, vid2);
00863 
00864         dest.resetType(ATTRTYPE_BOOL);
00865 
00866         switch(op)
00867         {
00868         case EQUAL:
00869             dest = AnyType( vl.op_equal_to(vr) );
00870             break;
00871 
00872         case NOTEQUAL:
00873             dest = AnyType( vl.op_not_equal_to(vr) );
00874             break;
00875 
00876         case LESS:
00877             dest = AnyType( vl.op_less(vr) );
00878             break;
00879 
00880         case GREATER:
00881             dest = AnyType( vl.op_greater(vr) );
00882             break;
00883 
00884         case LESSEQUAL:
00885             dest = AnyType( vl.op_less_equal(vr) );
00886             break;
00887 
00888         case GREATEREQUAL:
00889             dest = AnyType( vl.op_greater_equal(vr) );
00890             break;
00891 
00892         default:
00893             assert(0);
00894         }
00895 
00896         return (bl and br);
00897     }
00898 
00900     virtual bool getConstVal(AnyType *dest) const
00901     {
00902         if (!dest) return false;
00903 
00904         AnyType vl(ATTRTYPE_INVALID), vr(ATTRTYPE_INVALID);
00905         
00906         bool bl = left->getConstVal(&vl);
00907         bool br = right->getConstVal(&vr);
00908 
00909         switch(op)
00910         {
00911         case EQUAL:
00912             *dest = AnyType( vl.op_equal_to(vr) );
00913             break;
00914 
00915         case NOTEQUAL:
00916             *dest = AnyType( vl.op_not_equal_to(vr) );
00917             break;
00918 
00919         case LESS:
00920             *dest = AnyType( vl.op_less(vr) );
00921             break;
00922 
00923         case GREATER:
00924             *dest = AnyType( vl.op_greater(vr) );
00925             break;
00926 
00927         case LESSEQUAL:
00928             *dest = AnyType( vl.op_less_equal(vr) );
00929             break;
00930 
00931         case GREATEREQUAL:
00932             *dest = AnyType( vl.op_greater_equal(vr) );
00933             break;
00934 
00935         default:
00936             assert(0);
00937         }
00938 
00939         return (bl and br);
00940     }
00941 
00943     virtual std::string toString() const
00944     {
00945         return std::string("(") + left->toString() + " " + opstr + " " + right->toString() + ")";
00946     }
00947 };
00948 
00951 class PNBinaryLogicExpr : public ParseNode
00952 {
00953 private:
00955     const ParseNode     *left, *right;
00956 
00958     enum { OP_AND, OP_OR } op;
00959 
00960 public:
00961     PNBinaryLogicExpr(const ParseNode* _left,
00962                       const ParseNode* _right,
00963                       std::string _op)
00964         : ParseNode(),
00965           left(_left), right(_right)
00966     {
00967         if (_op == "and" or _op == "&&")
00968             op = OP_AND;
00969         else if (_op == "or" or _op == "||")
00970             op = OP_OR;
00971         else
00972             throw(AttributeParseException("Program Error: invalid binary logic operator."));
00973     }
00974 
00976     virtual ~PNBinaryLogicExpr()
00977     {
00978         if (left) delete left;
00979         if (right) delete right;
00980     }
00981 
00983     inline bool do_operator(bool left, bool right) const
00984     {
00985         if (op == OP_AND) return left && right;
00986         else if (op == OP_OR) return left || right;
00987         else return false;
00988     }
00989 
00992     virtual bool getValue(AnyType &dest, const class GraphContainer &gc, const class Changelist &cl,
00993                           vertex_or_edge_t wantedge, unsigned int vid1, unsigned int vid2) const
00994     {
00995         AnyType vl(ATTRTYPE_INVALID), vr(ATTRTYPE_INVALID);
00996         
00997         bool bl = left->getValue(vl, gc, cl, wantedge, vid1, vid2);
00998         bool br = right->getValue(vr, gc, cl , wantedge, vid1, vid2);
00999 
01000         // these should never happen.
01001         if (vl.getType() != ATTRTYPE_BOOL)
01002             throw(AttributeParseException(std::string("Invalid left operand for ") + (op == OP_AND ? "&&" : "||") + ". Both operands must be of type bool."));
01003         if (vr.getType() != ATTRTYPE_BOOL)
01004             throw(AttributeParseException(std::string("Invalid right operand for ") + (op == OP_AND ? "&&" : "||") + ". Both operands must be of type bool."));
01005 
01006         int bvl = vl.getInteger();
01007         int bvr = vr.getInteger();
01008 
01009         dest = AnyType( do_operator(bvl, bvr) );
01010 
01011         return (bl and br); // this is not the constness, it is the validitiy of the return value.
01012     }
01013 
01014     virtual bool getConstVal(AnyType *dest) const
01015     {
01016         if (!dest) return false; 
01017 
01018         AnyType vl(ATTRTYPE_INVALID), vr(ATTRTYPE_INVALID);
01019         
01020         bool bl = left->getConstVal(&vl);
01021         bool br = right->getConstVal(&vr);
01022 
01023         if (vl.getType() != ATTRTYPE_BOOL)
01024             throw(AttributeParseException(std::string("Invalid left operand for ") + (op == OP_AND ? "&&" : "||") + ". Both operands must be of type bool."));
01025         if (vr.getType() != ATTRTYPE_BOOL)
01026             throw(AttributeParseException(std::string("Invalid right operand for ") + (op == OP_AND ? "&&" : "||") + ". Both operands must be of type bool."));
01027 
01028         int bvl = vl.getInteger();
01029         int bvr = vr.getInteger();
01030 
01031         *dest = AnyType( do_operator(bvl, bvr) );
01032 
01033         if (op == OP_AND)
01034         {
01035             // true if either both ops are themselves constant, or if either of
01036             // the ops are constant and evaluates to false.
01037             return (bl and br) or (bl and !bvl) or (br and !bvr);
01038         }
01039         else if (op == OP_OR)
01040         {
01041             // true if either both ops are themselves constant, or if either of
01042             // the ops is constant and evaultes to true.
01043             return (bl and br) or (bl and bvl) or (br and bvr);
01044         }
01045         else {
01046             assert(0);
01047             return false;
01048         }
01049     }
01050 
01052     virtual std::string toString() const
01053     {
01054         return std::string("(") + left->toString() + " " + (op == OP_AND ? "&&" : "||") + " " + right->toString() + ")";
01055     }
01056 
01058     inline const ParseNode* detach_left()
01059     {
01060         const ParseNode *n = left;
01061         left = NULL;
01062         return n;
01063     }
01064 
01066     inline const ParseNode* detach_right()
01067     {
01068         const ParseNode *n = right;
01069         right = NULL;
01070         return n;
01071     }
01072 };
01073 
01074 // *** Functions which translate the resulting parse tree into our expression
01075 // *** tree, simultaneously folding constants.
01076 
01077 typedef char const* InputIterT;
01078 
01079 typedef tree_match<InputIterT> ParseTreeMatchT;
01080 
01081 typedef ParseTreeMatchT::const_tree_iterator TreeIterT;
01082 
01085 static const ParseNode* build_expr(TreeIterT const& i, const GraphProperties &gp, vertex_or_edge_t voe)
01086 {
01087 #ifdef BOOST_SPIRIT_DEBUG
01088     std::cout << "In build_expr. i->value = " <<
01089         std::string(i->value.begin(), i->value.end()) <<
01090         " i->children.size() = " << i->children.size() << 
01091         " i->value.id = " << i->value.id().to_long() << std::endl;
01092 #endif
01093 
01094     switch(i->value.id().to_long())
01095     {
01096     // *** Constant node cases
01097     case integer_const_id:
01098     {
01099         return new PNConstant(ATTRTYPE_INTEGER,
01100                               std::string(i->value.begin(), i->value.end()));
01101     }
01102 
01103     case double_const_id:
01104     {
01105         return new PNConstant(ATTRTYPE_DOUBLE,
01106                               std::string(i->value.begin(), i->value.end()));
01107     }
01108 
01109     case string_const_id:
01110     {
01111         return new PNConstant(ATTRTYPE_STRING,
01112                               std::string(i->value.begin(), i->value.end()));
01113     }
01114 
01115     // *** Arithmetic node cases
01116 
01117     case add_expr_id:
01118     case mul_expr_id:
01119     {
01120         char arithop = *i->value.begin();
01121         assert(i->children.size() == 2);
01122 
01123         // we need auto_ptr because of possible parse exceptions in build_expr.
01124 
01125         std::auto_ptr<const ParseNode> left( build_expr(i->children.begin(), gp, voe) );
01126         std::auto_ptr<const ParseNode> right( build_expr(i->children.begin()+1, gp, voe) );
01127 
01128         if (left->getConstVal(NULL) and right->getConstVal(NULL))
01129         {
01130             // construct a constant node
01131             PNBinaryArithmExpr tmpnode(left.release(), right.release(), arithop);
01132             AnyType both(ATTRTYPE_INVALID);
01133 
01134             tmpnode.getConstVal(&both);
01135 
01136             // left and right are deleted by tmpnode's deconstructor
01137 
01138             return new PNConstant(both);
01139         }
01140         else
01141         {
01142             // calculation node
01143             return new PNBinaryArithmExpr(left.release(), right.release(), arithop);
01144         }
01145     }
01146 
01147     case unary_expr_id:
01148     {
01149         char arithop = *i->value.begin();
01150         assert(i->children.size() == 1);
01151 
01152         const ParseNode *val = build_expr(i->children.begin(), gp, voe);
01153 
01154         if (val->getConstVal(NULL))
01155         {
01156             // construct a constant node
01157             PNUnaryArithmExpr tmpnode(val, arithop);
01158             AnyType constval(ATTRTYPE_INVALID);
01159 
01160             tmpnode.getConstVal(&constval);
01161 
01162             return new PNConstant(constval);
01163         }
01164         else
01165         {
01166             // calculation node
01167             return new PNUnaryArithmExpr(val, arithop);
01168         }
01169     }
01170 
01171     // *** Cast node case
01172 
01173     case cast_spec_id:
01174     {
01175         assert(i->children.size() == 1);
01176 
01177         std::string tname(i->value.begin(), i->value.end());
01178         attrtype_t at = AnyType::stringToType(tname);
01179         
01180         const ParseNode *val = build_expr(i->children.begin(), gp, voe);
01181 
01182         if (val->getConstVal(NULL))
01183         {
01184             // construct a constant node
01185             PNCastExpr tmpnode(val, at);
01186 
01187             AnyType constval(ATTRTYPE_INVALID);
01188 
01189             tmpnode.getConstVal(&constval);
01190 
01191             return new PNConstant(constval);
01192         }
01193         else
01194         {
01195             return new PNCastExpr(val, at);
01196         }
01197     }
01198 
01199     // *** Binary Comparison Operator
01200 
01201     case comp_expr_id:
01202     {
01203         assert(i->children.size() == 2);
01204 
01205         std::string arithop(i->value.begin(), i->value.end());
01206 
01207         // we need auto_ptr because of possible parse exceptions in build_expr.
01208 
01209         std::auto_ptr<const ParseNode> left( build_expr(i->children.begin(), gp, voe) );
01210         std::auto_ptr<const ParseNode> right( build_expr(i->children.begin()+1, gp, voe) );
01211 
01212         if (left->getConstVal(NULL) and right->getConstVal(NULL))
01213         {
01214             // construct a constant node
01215             PNBinaryComparisonExpr tmpnode(left.release(), right.release(), arithop);
01216             AnyType both(ATTRTYPE_INVALID);
01217 
01218             tmpnode.getConstVal(&both);
01219 
01220             // left and right are deleted by tmpnode's deconstructor
01221 
01222             return new PNConstant(both);
01223         }
01224         else
01225         {
01226             // calculation node
01227             return new PNBinaryComparisonExpr(left.release(), right.release(), arithop);
01228         }
01229     }
01230 
01231     // *** Binary Logic Operator
01232 
01233     case and_expr_id:
01234     case or_expr_id:
01235     {
01236         assert(i->children.size() == 2);
01237 
01238         std::string logicop(i->value.begin(), i->value.end());
01239 
01240         // we need auto_ptr because of possible parse exceptions in build_expr.
01241 
01242         std::auto_ptr<const ParseNode> left( build_expr(i->children.begin(), gp, voe) );
01243         std::auto_ptr<const ParseNode> right( build_expr(i->children.begin()+1, gp, voe) );
01244 
01245         bool constleft = left->getConstVal(NULL);
01246         bool constright = right->getConstVal(NULL);
01247 
01248         // a logical node is constant if one of the two ops is constant. so we
01249         // construct a calculation node and check later.
01250         std::auto_ptr<PNBinaryLogicExpr> node( new PNBinaryLogicExpr(left.release(), right.release(), logicop) );
01251 
01252         if (constleft or constright)
01253         {
01254             AnyType both(ATTRTYPE_INVALID);
01255 
01256             // test if the node is really const.
01257             if (node->getConstVal(&both))
01258             {
01259                 // return a constant node instead, node will be deleted by
01260                 // auto_ptr, left,right by node's destructor.
01261                 return new PNConstant(both);
01262             }
01263         }
01264         if (constleft)
01265         {
01266             // left node is constant, but the evaluation is not
01267             // -> only right node is meaningful.
01268             return node->detach_right();
01269         }
01270         if (constright)
01271         {
01272             // right node is constant, but the evaluation is not
01273             // -> only left node is meaningful.
01274             return node->detach_left();
01275         }
01276 
01277         return node.release();
01278     }
01279 
01280     // *** Vertex/Edge Attribute place-holder
01281 
01282     case attrname_id:
01283     {
01284         assert(i->children.size() == 0);
01285 
01286         std::string attrname(i->value.begin(), i->value.end());
01287 
01288         size_t dotloc = attrname.find('.');
01289         if (dotloc == std::string::npos)
01290         {
01291             // usual attribute string
01292             return new PNAttributeName(attrname, voe == VE_VERTEX ? gp.vertexattr : gp.edgeattr, voe);
01293         }
01294         else
01295         {
01296             if (voe != VE_EDGE)
01297                 throw(AttributeParseException("Invalid attribute name " + attrname + " for vertex selection."));
01298 
01299             // attribute string containing a dot.
01300             return new PNAttributeDotName(attrname, gp, voe);
01301         }       
01302     }
01303 
01304     default:
01305         throw(AttributeParseException("Unknown ast parse tree node found. This should never happen."));
01306     }
01307 }
01308 
01311 bool build_attrlist(TreeIterT const &i, const GraphProperties &gp, vertex_or_edge_t voe, class AttributeSelectorList &sellist)
01312 {
01313 #ifdef BOOST_SPIRIT_DEBUG
01314     std::cout << "In build_attrlist. i->value = " <<
01315         std::string(i->value.begin(), i->value.end()) <<
01316         " i->children.size() = " << i->children.size() << 
01317         " i->value.id = " << i->value.id().to_long() << std::endl;
01318 #endif
01319 
01320     sellist.clear();
01321 
01322     switch(i->value.id().to_long())
01323     {
01324     case attrlist_star_id:
01325     {
01326         sellist.selectStar(voe == VE_VERTEX ? gp.vertexattr: gp.edgeattr, voe);
01327         break;
01328     }
01329 
01330     case attrlist_exprlist_id:
01331     {
01332         for(TreeIterT ci = i->children.begin(); ci != i->children.end(); ++ci)
01333         {
01334             const ParseNode *vas = build_expr(ci, gp, voe);
01335             //std::cout << "parsed: " << vas->toString() << "\n";
01336 
01337             sellist.addAttrsel(vas);
01338         }
01339         break;
01340     }
01341 
01342     default:
01343     {
01344         // for attribute lists with only one entry, the ast tree does not
01345         // contain an attrlist_exprlist_id
01346 
01347         const ParseNode *vas = build_expr(i, gp, voe);
01348 
01349         //std::cout << "parsed: " << vas->toString() << "\n";
01350 
01351         sellist.addAttrsel(vas);
01352         break;
01353     }
01354     }
01355 
01356     sellist.calcAttributeLookups();
01357     return true;
01358 }
01359 
01360 } // namespace AttributeParser
01361 
01362 // *** AttributeSelectorList methods
01363 
01364 void AttributeSelectorList::selectStar(const AttributePropertiesList &otherlist, vertex_or_edge_t voe)
01365 {
01366     // copy the attributes from otherlist into this and create simple PNAttribute nodes.
01367 
01368     for(AttributePropertiesList::const_iterator ai = otherlist.begin(); ai != otherlist.end(); ai++)
01369     {
01370         // put into the parent-class
01371         attrlist::push_back(*ai);
01372 
01373         // create a selector node
01374         sellist::push_back( new AttributeParser::PNAttributeName(ai->name, otherlist, voe) );
01375     }
01376 
01377     assert( attrlist::size() == sellist::size() );
01378 }
01379 
01380 void AttributeSelectorList::addAttrsel(const class ParseNode *attrsel)
01381 {
01382     assert(attrsel);
01383 
01384     // calculate the resulting type and default value.
01385     AnyType rtype(ATTRTYPE_INVALID);
01386     attrsel->getConstVal(&rtype);
01387 
01388     std::string rstring = attrsel->toString();
01389     
01390     // put into parent class AttributePropertiesList a nearest representation
01391     // of this selection as an attribute.
01392     attrlist::push_back( AttributeProperties(rstring, rtype) );
01393 
01394     // and save this selection tree
01395     sellist::push_back( attrsel );
01396 
01397     assert( attrlist::size() == sellist::size() );
01398 }
01399 
01400 #ifdef BOOST_SPIRIT_DEBUG
01401 template <typename TreeInfo>
01402 static inline void debug_dump_xml(const std::string &input, const TreeInfo &info)
01403 {
01404     using namespace AttributeParser;
01405 
01406     // used by the xml dumper to label the nodes
01407 
01408     std::map<parser_id, std::string> rule_names;
01409 
01410     rule_names[integer_const_id] = "integer_const";
01411     rule_names[double_const_id] = "double_const";
01412     rule_names[string_const_id] = "string_const";
01413     rule_names[constant_id] = "constant";
01414 
01415     rule_names[function_call_id] = "function_call";
01416     rule_names[function_identifier_id] = "function_identifier";
01417 
01418     rule_names[attrname_id] = "attrname";
01419 
01420     rule_names[unary_expr_id] = "unary_expr";
01421     rule_names[mul_expr_id] = "mul_expr";
01422     rule_names[add_expr_id] = "add_expr";
01423 
01424     rule_names[cast_expr_id] = "cast_expr";
01425     rule_names[cast_spec_id] = "cast_spec";
01426 
01427     rule_names[comp_expr_id] = "comp_expr";
01428     rule_names[and_expr_id] = "and_expr";
01429     rule_names[or_expr_id] = "or_expr";
01430 
01431     rule_names[expr_id] = "expr";
01432 
01433     rule_names[attrlist_id] = "attrlist";
01434     rule_names[attrlist_exprlist_id] = "attrlist_exprlist";
01435     rule_names[attrlist_star_id] = "attrlist_star";
01436 
01437     rule_names[filter_expr_id] = "filter_expr";
01438 
01439     tree_to_xml(std::cout, info.trees, input.c_str(), rule_names);
01440 }
01441 #endif
01442 
01443 bool AttributeSelectorList::parseString(const std::string &input, const class GraphProperties &gp, vertex_or_edge_t voe)
01444 {
01445     using namespace AttributeParser;
01446 
01447     // instance of the grammar
01448     AttributeGrammar g;
01449 
01450 #ifdef BOOST_SPIRIT_DEBUG
01451     BOOST_SPIRIT_DEBUG_GRAMMAR(g);
01452 #endif
01453 
01454     tree_parse_info<> info =
01455         boost::spirit::ast_parse(input.c_str(),
01456                                  g.use_parser<0>(),     // use first entry point: attrlist
01457                                  boost::spirit::space_p);
01458 
01459     if (not info.full)
01460     {
01461         char synstr[256];
01462         g_snprintf(synstr, sizeof(synstr),
01463                    "Syntax error at position %d near %.10s",
01464                    static_cast<int>(info.stop - input.c_str()),
01465                    info.stop);
01466         throw (AttributeParseException(synstr));
01467     }
01468 
01469 #ifdef BOOST_SPIRIT_DEBUG
01470     debug_dump_xml(input, info);
01471 #endif
01472 
01473     return build_attrlist(info.trees.begin(), gp, voe, *this);
01474 }
01475 
01476 std::string AttributeSelectorList::toString() const
01477 {
01478     std::string sl;
01479 
01480     for(sellist::const_iterator i = sellist::begin(); i != sellist::end(); i++) {
01481 
01482         if (i != sellist::begin()) {
01483             sl += ", ";
01484         }
01485 
01486         sl += (*i)->toString();
01487     }
01488 
01489     return sl;
01490 }
01491 
01492 // *** FilterRoot methods
01493 
01494 bool FilterRoot::parseString(const std::string &input, const class GraphProperties &gp)
01495 {
01496     // clear filter
01497     vertexoredge = VE_VERTEX;
01498     if (filter) {
01499         delete filter;
01500         filter = NULL;
01501     }
01502 
01503     if (input.size() == 0) return true;
01504 
01505     using namespace AttributeParser;
01506 
01507     // instance of the grammar
01508     AttributeGrammar g;
01509 
01510 #ifdef BOOST_SPIRIT_DEBUG
01511     BOOST_SPIRIT_DEBUG_GRAMMAR(g);
01512 #endif
01513 
01514     tree_parse_info<> info =
01515         boost::spirit::ast_parse(input.c_str(),
01516                                  g.use_parser<1>(),     // use second entry point: filter_expr
01517                                  boost::spirit::space_p);
01518 
01519     if (not info.full)
01520     {
01521         char synstr[256];
01522         g_snprintf(synstr, sizeof(synstr),
01523                    "Syntax error at position %d near %.10s",
01524                    static_cast<int>(info.stop - input.c_str()),
01525                    info.stop);
01526         throw (AttributeParseException(synstr));
01527     }
01528 
01529 #ifdef BOOST_SPIRIT_DEBUG
01530     debug_dump_xml(input, info);
01531 #endif
01532 
01533     // used to be build_filterroot:
01534 
01535     // build_filterroot constructs the root object holding either an edge or a
01536     // vertex filter.
01537     {
01538         TreeIterT const &i = info.trees.begin();
01539 
01540 #ifdef BOOST_SPIRIT_DEBUG
01541         std::cout << "In build_filterroot. i->value = " <<
01542             std::string(i->value.begin(), i->value.end()) <<
01543             " i->children.size() = " << i->children.size() << 
01544             " i->value.id = " << i->value.id().to_long() << std::endl;
01545 #endif
01546 
01547         if (i->value.id().to_long() != filter_expr_id)
01548             throw(AttributeParseException("Unknown ast parse tree node found. This should never happen."));
01549 
01550         if (i->children.size() == 0)
01551         {
01552             // this is a NULL filter: always true
01553             return true;
01554         }
01555         else if (i->children.size() == 1)
01556         {
01557             // we have a vertex or an edge filter?
01558             char voeletter = *i->value.begin();
01559             vertexoredge = (voeletter == 'v') ? VE_VERTEX : VE_EDGE;
01560 
01561             // build up tree
01562             filter = build_expr(i->children.begin(), gp, vertexoredge);
01563 
01564             // type-check the the filter once, this is needed if the top node
01565             // are logic operators
01566             AnyType tc(ATTRTYPE_INVALID);
01567             filter->getConstVal(&tc);
01568 
01569             if (tc.getType() != ATTRTYPE_BOOL)
01570                 throw(AttributeParseException("The filter expression must be of type bool. Remember there is no automatic comparison != 0 as in C."));
01571 
01572             return true;
01573         }
01574         else {
01575             throw(AttributeParseException("Unknown ast parse tree node found. This should never happen."));
01576         }
01577     }
01578 }
01579 
01580 std::string FilterRoot::toString() const
01581 {
01582     if (!filter) return "null-filter";
01583 
01584     return std::string(vertexoredge == VE_VERTEX ? "vertex: " : "edge: ") + filter->toString();
01585 }
01586 
01587 } // namespace VGServer

Generated on Wed Sep 27 14:34:00 2006 for VGServer by  doxygen 1.4.7