opspace/src/parse_yaml.cpp

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2011 The Board of Trustees of The Leland Stanford Junior University. All rights reserved.
00003  *
00004  * Author: Roland Philippsen
00005  *         http://cs.stanford.edu/group/manips/
00006  *
00007  * This program is free software: you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License
00009  * as published by the Free Software Foundation, either version 3 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this program.  If not, see
00019  * <http://www.gnu.org/licenses/>
00020  */
00021 
00022 #include <opspace/parse_yaml.hpp>
00023 #include <opspace/Factory.hpp>
00024 #include <opspace/Task.hpp>
00025 #include <opspace/Skill.hpp>
00026 #include <stdexcept>
00027 
00028 using jspace::pretty_print;
00029 using boost::shared_ptr;
00030 using std::string;
00031 
00032 
00033 namespace opspace {
00034   
00035   
00036   Parser::
00037   Parser(Factory const & factory_, std::ostream * optional_dbg_os)
00038     : factory(factory_),
00039       dbg(optional_dbg_os)
00040   {
00041   }
00042   
00043   
00044   Parser::
00045   ~Parser()
00046   {
00047   }
00048   
00049   
00050   TaskParser::
00051   TaskParser(Factory const & factory, std::ostream * optional_dbg_os)
00052     : Parser(factory, optional_dbg_os),
00053       type("void"),
00054       name(""),
00055       task(0)
00056   {
00057   }
00058   
00059   
00060   SkillParser::
00061   SkillParser(Factory const & factory, std::ostream * optional_dbg_os)
00062     : Parser(factory, optional_dbg_os),
00063       type("void"),
00064       name(""),
00065       skill(0)
00066   {
00067   }
00068   
00069   
00070   TaskTableParser::
00071   TaskTableParser(Factory const & factory,
00072       Factory::task_table_t & task_table_,
00073       std::ostream * optional_dbg_os)
00074     : Parser(factory, optional_dbg_os),
00075       task_parser(factory, optional_dbg_os),
00076       task_table(task_table_)
00077   {
00078   }
00079   
00080   
00081   SkillTableParser::
00082   SkillTableParser(Factory const & factory,
00083           Factory::skill_table_t & skill_table_,
00084           std::ostream * optional_dbg_os)
00085     : Parser(factory, optional_dbg_os),
00086       skill_parser(factory, optional_dbg_os),
00087       skill_table(skill_table_)
00088   {
00089   }
00090   
00091   
00092   static char const * yaml_type_name(YAML::Node const & node)
00093   {
00094     switch (node.GetType()) {
00095     case YAML::CT_NONE:
00096       return "NONE";
00097     case YAML::CT_SCALAR:
00098       return "SCALAR";
00099     case YAML::CT_SEQUENCE:
00100       return "SEQUENCE";
00101     case YAML::CT_MAP:
00102       return "MAP";
00103     }
00104     return "unknown";
00105   }
00106   
00107   
00108   void operator >> (YAML::Node const & node, Vector & vector)
00109   {
00110     vector.resize(node.size());
00111     for (size_t ii(0); ii < node.size(); ++ii) {
00112       node[ii] >> vector.coeffRef(ii);
00113     }
00114   }
00115   
00116   
00117   static Parameter * parse_parameter(std::string const & com_type,
00118              std::string const & com_name,
00119              ParameterReflection & pr,
00120              std::string const & key,
00121              YAML::Node const & value)
00122     throw(std::runtime_error)
00123   {
00124     Parameter * param(pr.lookupParameter(key));
00125     if ( ! param) {
00126       throw std::runtime_error("no parameter called `" + key + "' in " + com_type
00127              + " `" + com_name + "'");
00128     }
00129     
00130     if (PARAMETER_TYPE_INTEGER == param->type_) {
00131       if (YAML::CT_SCALAR != value.GetType()) {
00132   throw std::runtime_error("parameter `" + key
00133          + "' of " + com_type + " `" + com_name
00134          + "' should be scalar (integer) but is "
00135          + string(yaml_type_name(value)));
00136       }
00137       int integer;
00138       value >> integer;
00139       Status const st(param->set(integer));
00140       if ( ! st) {
00141   throw std::runtime_error("setting integer parameter `" + key
00142          + "' of " + com_type + " `" + com_name
00143          + "' failed: " + st.errstr);
00144       }
00145     }
00146     
00147     else if (PARAMETER_TYPE_STRING == param->type_) {
00148       if (YAML::CT_SCALAR != value.GetType()) {
00149   throw std::runtime_error("parameter `" + key
00150          + "' of " + com_type + " `" + com_name
00151          + "' should be scalar (string) but is "
00152          + string(yaml_type_name(value)));
00153       }
00154       std::string foo;
00155       value >> foo;
00156       Status const st(param->set(foo));
00157       if ( ! st) {
00158   throw std::runtime_error("setting string parameter `" + key
00159          + "' of " + com_type + " `" + com_name
00160          + "' failed: " + st.errstr);
00161       }
00162     }
00163     
00164     else if (PARAMETER_TYPE_REAL == param->type_) {
00165       if (YAML::CT_SCALAR != value.GetType()) {
00166   throw std::runtime_error("parameter `" + key
00167          + "' of " + com_type + " `" + com_name
00168          + "' should be scalar (real) but is "
00169          + string(yaml_type_name(value)));
00170       }
00171       double real;
00172       value >> real;
00173       Status const st(param->set(real));
00174       if ( ! st) {
00175   throw std::runtime_error("setting real parameter `" + key
00176          + "' of " + com_type + " `" + com_name
00177          + "' failed: " + st.errstr);
00178       }
00179     }
00180     
00181     else if (PARAMETER_TYPE_VECTOR == param->type_) {
00182       if (YAML::CT_SEQUENCE != value.GetType()) {
00183   throw std::runtime_error("parameter `" + key
00184          + "' of " + com_type + " `" + com_name
00185          + "' should be sequence (vector) but is "
00186          + string(yaml_type_name(value)));
00187       }
00188       Vector vector;
00189       value >> vector;
00190       Status const st(param->set(vector));
00191       if ( ! st) {
00192   throw std::runtime_error("setting vector parameter `" + key
00193          + "' of " + com_type + " `" + com_name
00194          + "' failed: " + st.errstr);
00195       }
00196     }
00197     
00198     else if (PARAMETER_TYPE_MATRIX == param->type_) {
00199       throw std::runtime_error("setting parameter `" + key
00200              + "' of " + com_type + " `" + com_name
00201              + "' requires MATRIX type which is not (yet) supported");
00202     }
00203     
00204     else {
00205       throw std::runtime_error("setting parameter `" + key
00206              + "' of " + com_type + " `" + com_name
00207              + "' invalid or VOID type (need to update parse_yaml.cpp maybe?)");
00208     }
00209     
00210     return param;
00211   }
00212   
00213   
00214   void operator >> (YAML::Node const & node, TaskParser & parser)
00215   {
00216     parser.task = 0;    // in case type or name is undefined
00217     if (parser.dbg) {
00218       *parser.dbg << "DEBUG opspace::operator>>(YAML::Node &, task_parser_s &)\n"
00219       << "  reading type and name\n";
00220     }
00221     node["type"] >> parser.type;
00222     node["name"] >> parser.name;
00223 
00224     if (parser.dbg) {
00225       *parser.dbg << "  type = " << parser.type << "  name = " << parser.name << "\n";
00226     }
00227     parser.task = Factory::createTask(parser.type, parser.name);
00228     if ( ! parser.task) {
00229       throw std::runtime_error("createTask(`" + parser.type + "', `" + parser.name + "') failed");
00230     }
00231     
00232     if (parser.dbg) {
00233       *parser.dbg << "  created task `" << parser.name << "' of type " << parser.type << "\n"
00234       << "    parsing parameters:\n";
00235     }
00236     for (YAML::Iterator it(node.begin()); it != node.end(); ++it) {
00237       std::string key;
00238       it.first() >> key;
00239       if (("type" == key) || ("name" == key)) {
00240   continue;
00241       }
00242       YAML::Node const & value(it.second());
00243       
00244       if (parser.dbg) {
00245   *parser.dbg << "    trying `" << key << "' (YAML type " << yaml_type_name(value) << ")\n";
00246       }
00247       
00248       Parameter const * param(parse_parameter("task", parser.name, *parser.task, key, value));
00249       if (parser.dbg) {
00250   param->dump(*parser.dbg, "    ");
00251       }
00252       
00253     } // end for (YAML::Iterator ... )
00254   }
00255   
00256   
00257   void operator >> (YAML::Node const & node, SkillParser & parser)
00258   {
00259     parser.skill = 0;   // in case type or name is undefined
00260     if (parser.dbg) {
00261       *parser.dbg << "DEBUG opspace::operator>>(YAML::Node &, skill_parser_s &)\n"
00262       << "  reading type and name\n";
00263     }
00264     node["type"] >> parser.type;
00265     node["name"] >> parser.name;
00266 
00267     if (parser.dbg) {
00268       *parser.dbg << "  type = " << parser.type << "  name = " << parser.name << "\n";
00269     }
00270     parser.skill = Factory::createSkill(parser.type, parser.name);
00271     if ( ! parser.skill) {
00272       throw std::runtime_error("createSkill(`" + parser.type + "', `" + parser.name + "') failed");
00273     }
00274     
00275     if (parser.dbg) {
00276       *parser.dbg << "  created skill `" << parser.name
00277       << "' of type " << parser.type << "\n"
00278       << "    parsing slots and parameters:\n";
00279     }
00280     for (YAML::Iterator it(node.begin()); it != node.end(); ++it) {
00281       std::string key;
00282       it.first() >> key;
00283       if (("type" == key) || ("name" == key)) {
00284   continue;
00285       }
00286       
00287       if ("slots" == key) {
00288   YAML::Node const & slotlist(it.second());
00289   for (YAML::Iterator slot_it(slotlist.begin()); slot_it != slotlist.end(); ++slot_it) {
00290     std::string slot_name;
00291     std::string task_name;
00292 
00293     if (YAML::CT_MAP == slotlist.GetType()) {
00294       slot_it.first() >> slot_name;
00295       slot_it.second() >> task_name;
00296     }
00297     else if (YAML::CT_SEQUENCE == slotlist.GetType()) {
00298       if (YAML::CT_MAP != slot_it->GetType()) {
00299         throw std::runtime_error("list item for `" + key + "' is a "
00300              + string(yaml_type_name(slotlist))
00301                + " but should be a map with one key/value pair");
00302       }
00303       YAML::Iterator slot_it_it(slot_it->begin());
00304       if (slot_it->end() == slot_it_it) {
00305         throw std::runtime_error("list item for `" + key
00306                + "' is empty but should have one key/value pair");
00307       }
00308       slot_it_it.first() >> slot_name;
00309       slot_it_it.second() >> task_name;
00310       ++slot_it_it;
00311       if (slot_it->end() != slot_it_it) {
00312         throw std::runtime_error("list item for `" + key
00313                + "' has more than one key/value pair");
00314       }
00315     }
00316     else {
00317       throw std::runtime_error("entry for `" + key + "' is a "
00318              + string(yaml_type_name(slotlist))
00319              + " but should be a map or a list");
00320     }
00321     
00322     shared_ptr<TaskSlotAPI> slot(parser.skill->lookupSlot(slot_name));
00323     if ( ! slot) {
00324       throw std::runtime_error("skill `" + parser.name + "' has no slot `"
00325              + slot_name + "'");
00326     }
00327     
00328     shared_ptr<Task> task(parser.factory.findTask(task_name));
00329     if ( ! task) {
00330       throw std::runtime_error("no task instance `" + task_name + "' for skill `"
00331              + parser.name + "' slot `" + slot_name + "'");
00332     }
00333     
00334     Status const st(slot->assign(task));
00335     if ( ! st) {
00336       throw std::runtime_error("oops assigning task instance `" + task_name
00337              + "' to skill `" + parser.name
00338              + "' slot `" + slot_name + "': " + st.errstr);
00339     }
00340     
00341     if (parser.dbg) {
00342       *parser.dbg << "  assigned task instance `" << task_name
00343       << "' to slot `" << slot_name << "' in skill `"
00344       << parser.name << "'\n";
00345     }
00346   }
00347       } // end if ("slots" ...)
00348       
00349       else {
00350   // assume it's a parameter
00351   Parameter const * param(parse_parameter("skill", parser.name,
00352             *parser.skill, key, it.second()));
00353   if (parser.dbg) {
00354     param->dump(*parser.dbg, "    ");
00355   }
00356       }
00357       
00358     } // end for (YAML::Iterator ...)
00359   }
00360   
00361   
00362   void operator >> (YAML::Node const & node, TaskTableParser & parser)
00363   {
00364     for (size_t ii(0); ii < node.size(); ++ii) {
00365       YAML::Node const & entry(node[ii]);
00366       entry >> parser.task_parser;
00367       if ( ! parser.task_parser.task) {
00368   throw std::runtime_error("failed to create task instance");
00369       }
00370       parser.task_table.push_back(shared_ptr<Task>(parser.task_parser.task));
00371     }
00372   }
00373   
00374   
00375   void operator >> (YAML::Node const & node, SkillTableParser & parser)
00376   {
00377     if (parser.dbg) {
00378       *parser.dbg << "DEBUG opspace::operator>>(YAML::Node &, SkillTableParser &)\n"
00379       << "  parsing " << node.size() << " nodes\n";
00380     }
00381     for (size_t ii(0); ii < node.size(); ++ii) {
00382       YAML::Node const & entry(node[ii]);
00383       entry >> parser.skill_parser;
00384       if ( ! parser.skill_parser.skill) {
00385   throw std::runtime_error("failed to create skill instance");
00386       }
00387       if (parser.dbg) {
00388   parser.skill_parser.skill->dump(*parser.dbg, "  adding to table: skill", "    ");
00389       }
00390       parser.skill_table.push_back(shared_ptr<Skill>(parser.skill_parser.skill));
00391     }
00392   }
00393   
00394 }

Generated on Fri Aug 26 01:31:17 2011 for Stanford Whole-Body Control Framework by  doxygen 1.5.4