/* vim: set sw=4 sts=4 et foldmethod=syntax : *//* * Copyright (c) 2005, 2006, 2007 Ciaran McCreesh <ciaranm@ciaranm.org> * * This file is part of the Paludis package manager. Paludis is free software; * you can redistribute it and/or modify it under the terms of the GNU General * Public License version 2, as published by the Free Software Foundation. * * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place, Suite 330, Boston, MA 02111-1307 USA */#include<paludis/dep_spec.hh>#include<paludis/portage_dep_lexer.hh>#include<paludis/portage_dep_parser.hh>#include<paludis/util/exception.hh>#include<paludis/util/stringify.hh>#include<stack>/** \file * Implementation for dep_parser.hh things. * * \ingroup grpdepparser */usingnamespacepaludis;DepStringParseError::DepStringParseError(conststd::string&d,conststd::string&m)throw():DepStringError(d,"in parse phase: "+m){}DepStringNestingError::DepStringNestingError(conststd::string&dep_string)throw():DepStringParseError(dep_string,"improperly balanced parentheses"){}namespace{/** * Our current state. * * \ingroup grpdepparser */enumPortageDepParserState{dps_initial,dps_had_double_bar,dps_had_double_bar_space,dps_had_paren,dps_had_use_flag,dps_had_use_flag_space};}std::tr1::shared_ptr<CompositeDepSpec>PortageDepParser::parse(conststd::string&s,constPortageDepParserPolicyInterface*constpolicy){Contextcontext("When parsing dependency string '"+s+"':");std::stack<std::tr1::shared_ptr<CompositeDepSpec>>stack;stack.push(std::tr1::shared_ptr<CompositeDepSpec>(newAllDepSpec));PortageDepParserStatestate(dps_initial);PortageDepLexerlexer(s);PortageDepLexer::Iteratori(lexer.begin()),i_end(lexer.end());for(;i!=i_end;++i){Contextlocal_context("When handling lexer token '"+i->second+"' ("+stringify(i->first)+"):");do{switch(state){casedps_initial:do{switch(i->first){casedpl_whitespace:continue;casedpl_text:{if(i->second.empty())throwDepStringParseError(i->second,"Empty text entry");stack.top()->add_child(policy->new_text_spec(i->second));}continue;casedpl_open_paren:{std::tr1::shared_ptr<CompositeDepSpec>a(newAllDepSpec);stack.top()->add_child(a);stack.push(a);state=dps_had_paren;}continue;casedpl_close_paren:if(stack.empty())throwDepStringNestingError(s);stack.pop();if(stack.empty())throwDepStringNestingError(s);state=dps_had_paren;continue;casedpl_double_bar:if(policy->permit_any_deps()){std::tr1::shared_ptr<CompositeDepSpec>a(newAnyDepSpec);stack.top()->add_child(a);stack.push(a);state=dps_had_double_bar;}elsethrowDepStringParseError(s,"|| is not allowed here");continue;casedpl_use_flag:{std::stringf(i->second);boolinv(f.length()&&('!'==f.at(0)));if(inv)f.erase(0,1);if(f.empty())throwDepStringParseError(s,"Bad use flag name '"+i->second+"'");if('?'!=f.at(f.length()-1))throwDepStringParseError(s,"Use flag name '"+i->second+"' missing '?'");f.erase(f.length()-1);std::tr1::shared_ptr<CompositeDepSpec>a(newUseDepSpec(UseFlagName(f),inv));stack.top()->add_child(a);stack.push(a);state=dps_had_use_flag;}continue;}throwInternalError(PALUDIS_HERE,"dps_initial: i->first is "+stringify(i->first));}while(0);continue;casedps_had_double_bar:do{switch(i->first){casedpl_whitespace:state=dps_had_double_bar_space;continue;casedpl_text:casedpl_use_flag:casedpl_double_bar:casedpl_open_paren:casedpl_close_paren:throwDepStringParseError(s,"Expected space after '||'");}throwInternalError(PALUDIS_HERE,"dps_had_double_bar: i->first is "+stringify(i->first));}while(0);continue;casedps_had_double_bar_space:do{switch(i->first){casedpl_open_paren:state=dps_initial;continue;casedpl_whitespace:casedpl_text:casedpl_use_flag:casedpl_double_bar:casedpl_close_paren:throwDepStringParseError(s,"Expected '(' after '|| '");}throwInternalError(PALUDIS_HERE,"dps_had_double_bar_space: i->first is "+stringify(i->first));}while(0);continue;casedps_had_paren:do{switch(i->first){casedpl_whitespace:state=dps_initial;continue;casedpl_text:casedpl_use_flag:casedpl_double_bar:casedpl_open_paren:casedpl_close_paren:throwDepStringParseError(s,"Expected space after '(' or ')'");}throwInternalError(PALUDIS_HERE,"dps_had_paren: i->first is "+stringify(i->first));}while(0);continue;casedps_had_use_flag:do{switch(i->first){casedpl_whitespace:state=dps_had_use_flag_space;continue;casedpl_text:casedpl_use_flag:casedpl_double_bar:casedpl_open_paren:casedpl_close_paren:throwDepStringParseError(s,"Expected space after use flag");}throwInternalError(PALUDIS_HERE,"dps_had_use_flag: i->first is "+stringify(i->first));}while(0);continue;casedps_had_use_flag_space:do{switch(i->first){casedpl_open_paren:state=dps_had_paren;continue;casedpl_whitespace:casedpl_text:casedpl_use_flag:casedpl_double_bar:casedpl_close_paren:throwDepStringParseError(s,"Expected '(' after use flag");}throwInternalError(PALUDIS_HERE,"dps_had_use_flag_space: i->first is "+stringify(i->first));}while(0);continue;}throwInternalError(PALUDIS_HERE,"state is "+stringify(state));}while(0);}if(stack.empty())throwDepStringNestingError(s);std::tr1::shared_ptr<CompositeDepSpec>result(stack.top());stack.pop();if(!stack.empty())throwDepStringNestingError(s);returnresult;}std::tr1::shared_ptr<constCompositeDepSpec>PortageDepParser::parse_depend(conststd::string&s){returnPortageDepParser::parse(s);}std::tr1::shared_ptr<constCompositeDepSpec>PortageDepParser::parse_license(conststd::string&s){returnPortageDepParser::parse(s,PortageDepParserPolicy<PlainTextDepSpec,true>::get_instance());}