export.cc
Go to the documentation of this file.
00001 #include "export.hh"
00002 #include <iostream>
00003 #include <utilmm/stringtools.hh>
00004 
00005 #include <typelib/typevisitor.hh>
00006 #include <typelib/plugins.hh>
00007 
00008 #include <boost/algorithm/string.hpp>
00009 
00010 namespace
00011 {
00012     using namespace std;
00013     using namespace Typelib;
00014 
00015     static string normalizeIDLName(std::string const& name)
00016     {
00017         unsigned int template_mark;
00018         string result = name;
00019         while ((template_mark = result.find_first_of("<>/,")) < result.length())
00020             result.replace(template_mark, 1, "_");
00021         return result;
00022     }
00023 
00024     static string getIDLAbsoluteNamespace(std::string const& type_ns, IDLExport const& exporter)
00025     {
00026         string ns = type_ns;
00027         string prefix = exporter.getNamespacePrefix();
00028         string suffix = exporter.getNamespaceSuffix();
00029         if (!prefix.empty())
00030             ns = prefix + ns;
00031         if (!suffix.empty())
00032             ns += suffix;
00033         return ns;
00034     }
00035 
00036     class IDLTypeIdentifierVisitor : public TypeVisitor
00037     {
00038     public:
00039         IDLExport const& m_exporter;
00040         string    m_front, m_back;
00041         string    m_namespace;
00042 
00043         bool visit_(OpaqueType const& type);
00044         bool visit_(NullType const& type);
00045         bool visit_(Container const& type);
00046         bool visit_(Compound const& type);
00047 
00048         bool visit_(Numeric const& type);
00049 
00050         bool visit_(Pointer const& type);
00051         bool visit_(Array const& type);
00052 
00053         bool visit_(Enum const& type);
00054 
00055         IDLTypeIdentifierVisitor(IDLExport const& exporter)
00056             : m_exporter(exporter) {}
00057         string getTargetNamespace() const { return m_namespace; }
00058         std::string getIDLAbsolute(Type const& type, std::string const& field_name = "");
00059         std::string getIDLRelative(Type const& type, std::string const& field_name = "");
00060         pair<string, string> getIDLBase(Type const& type, std::string const& field_name = "");
00061         void apply(Type const& type)
00062         {
00063             m_namespace = getIDLAbsoluteNamespace(type.getNamespace(), m_exporter);
00064             TypeVisitor::apply(type);
00065             m_front = normalizeIDLName(m_front);
00066         }
00067     };
00068 
00069     static bool isIDLBuiltinType(Type const& type)
00070     {
00071         if (type.getCategory() == Type::Numeric || type.getName() == "/std/string")
00072             return true;
00073         else if (type.getCategory() == Type::Array)
00074         {
00075             Type const& element_type = static_cast<Array const&>(type).getIndirection();
00076             return isIDLBuiltinType(element_type);
00077         }
00078         return false;
00079     }
00080 
00084     static pair<string, string> getIDLBase(Type const& type, IDLExport const& exporter, std::string const& field_name = std::string())
00085     {
00086         std::string type_name;
00087         IDLTypeIdentifierVisitor visitor(exporter);
00088         visitor.apply(type);
00089         if (field_name.empty())
00090             return make_pair(visitor.getTargetNamespace(), visitor.m_front + visitor.m_back);
00091         else
00092             return make_pair(visitor.getTargetNamespace(), visitor.m_front + " " + field_name + visitor.m_back);
00093     }
00094 
00098     static string getIDLRelative(Type const& type, std::string const& relative_to, IDLExport const& exporter, std::string const& field_name = std::string())
00099     {
00100         pair<string, string> base = getIDLBase(type, exporter, field_name);
00101         if (!base.first.empty())
00102         {
00103             std::string ns = getMinimalPathTo(base.first + type.getBasename(), relative_to);
00104             boost::replace_all(ns, Typelib::NamespaceMarkString, "::");
00105             return normalizeIDLName(ns) + base.second;
00106         }
00107         else return base.second;
00108     }
00109 
00113     static string getIDLAbsolute(Type const& type, IDLExport const& exporter, std::string const& field_name = std::string())
00114     {
00115         pair<string, string> base = getIDLBase(type, exporter, field_name);
00116         if (!base.first.empty())
00117         {
00118             std::string ns = base.first;
00119             boost::replace_all(ns, Typelib::NamespaceMarkString, "::");
00120             return normalizeIDLName(ns) + base.second;
00121         }
00122         else return base.second;
00123     }
00124 
00125     std::string IDLTypeIdentifierVisitor::getIDLAbsolute(Type const& type, std::string const& field_name)
00126     {
00127         return ::getIDLAbsolute(type, m_exporter, field_name);
00128     }
00129     std::string IDLTypeIdentifierVisitor::getIDLRelative(Type const& type, std::string const& field_name)
00130     {
00131         return ::getIDLRelative(type, m_namespace, m_exporter, field_name);
00132     }
00133     pair<string, string> IDLTypeIdentifierVisitor::getIDLBase(Type const& type, std::string const& field_name)
00134     {
00135         return ::getIDLBase(type, m_exporter, field_name);
00136     }
00137 
00138     bool IDLTypeIdentifierVisitor::visit_(OpaqueType const& type)
00139     {
00140         if (m_exporter.marshalOpaquesAsAny())
00141         {
00142             m_namespace = "";
00143             m_front = "any";
00144         }
00145         else
00146             throw UnsupportedType(type, "opaque types are not allowed in IDL");
00147 
00148         return true;
00149     }
00150     bool IDLTypeIdentifierVisitor::visit_(NullType const& type)
00151     { throw UnsupportedType(type, "null types are not supported for export in IDL"); }
00152     bool IDLTypeIdentifierVisitor::visit_(Container const& type)
00153     {
00154         if (type.getName() == "/std/string")
00155         {
00156             m_namespace = "";
00157             m_front = "string";
00158         }
00159         else
00160         {
00161             // Get the basename for "kind"
00162             m_namespace = getIDLBase(type.getIndirection()).first;
00163             // We generate all containers in orogen::Corba, even if their
00164             // element type is a builtin
00165             if (m_namespace.empty())
00166                 m_namespace = getIDLAbsoluteNamespace("/", m_exporter);
00167 
00168             std::string container_kind = Typelib::getTypename(type.kind());
00169             std::string element_name   = type.getIndirection().getName();
00170             boost::replace_all(element_name, Typelib::NamespaceMarkString, "_");
00171             boost::replace_all(element_name, " ", "_");
00172             m_front = container_kind + "_" + element_name + "_";
00173         }
00174 
00175         return true;
00176     }
00177     bool IDLTypeIdentifierVisitor::visit_(Compound const& type)
00178     { m_front = type.getBasename();
00179         return true; }
00180     bool IDLTypeIdentifierVisitor::visit_(Numeric const& type)
00181     {
00182         m_namespace = "";
00183         if (type.getName() == "/bool")
00184         {
00185             m_front = "boolean";
00186         }
00187         else if (type.getNumericCategory() != Numeric::Float)
00188         {
00189             if (type.getNumericCategory() == Numeric::UInt && type.getSize() != 1)
00190                 m_front = "unsigned ";
00191             switch (type.getSize())
00192             {
00193                 case 1: m_front += "octet"; break;
00194                 case 2: m_front += "short"; break;
00195                 case 4: m_front += "long"; break;
00196                 case 8: m_front += "long long"; break;
00197             }
00198         }
00199         else
00200         {
00201             if (type.getSize() == 4)
00202                 m_front = "float";
00203             else
00204                 m_front = "double";
00205         }
00206         return true;
00207     }
00208     bool IDLTypeIdentifierVisitor::visit_(Pointer const& type)
00209     { throw UnsupportedType(type, "pointer types are not supported for export in IDL"); }
00210     bool IDLTypeIdentifierVisitor::visit_(Array const& type)
00211     {
00212         if (type.getIndirection().getCategory() == Type::Array)
00213             throw UnsupportedType(type, "multi-dimensional arrays are not supported in IDL");
00214 
00215         pair<string, string> element_t = getIDLBase(type.getIndirection());
00216         m_namespace = element_t.first;
00217         m_front = element_t.second;
00218         m_back = "[" + boost::lexical_cast<string>(type.getDimension()) + "]";
00219         return true;
00220     }
00221     bool IDLTypeIdentifierVisitor::visit_(Enum const& type)
00222     { m_front = type.getBasename();
00223         return true; }
00224 
00225     class IDLExportVisitor : public TypeVisitor
00226     {
00227     public:
00228         IDLExport const& m_exporter;
00229         ostringstream  m_stream;
00230         string    m_indent;
00231         string    m_namespace;
00232         std::map<std::string, Type const*>& m_exported_typedefs;
00233 
00234         bool visit_(OpaqueType const& type);
00235         bool visit_(Container const& type);
00236         bool visit_(Compound const& type);
00237         bool visit_(Compound const& type, Field const& field);
00238 
00239         bool visit_(Numeric const& type);
00240 
00241         bool visit_(Pointer const& type);
00242         bool visit_(Array const& type);
00243 
00244         bool visit_(Enum const& type);
00245 
00246         IDLExportVisitor(Registry const& registry, IDLExport const& exporter, std::map<std::string, Type const*>& exported_typedefs);
00247         std::string getResult() const { return m_stream.str(); }
00248         std::string getTargetNamespace() const { return m_namespace; }
00249         void setTargetNamespace(std::string const& target_namespace)
00250         {
00251             size_t ns_size = utilmm::split(target_namespace, "/").size();
00252             m_indent = string(ns_size * 4, ' ');
00253             m_namespace = target_namespace;
00254         }
00255         std::string getIDLAbsolute(Type const& type, std::string const& field_name = "");
00256         std::string getIDLRelative(Type const& type, std::string const& field_name = "");
00257         pair<string, string> getIDLBase(Type const& type, std::string const& field_name = "");
00258         void apply(Type const& type)
00259         {
00260             setTargetNamespace(getIDLAbsoluteNamespace(type.getNamespace(), m_exporter));
00261             TypeVisitor::apply(type);
00262         }
00263     };
00264 
00265     std::string IDLExportVisitor::getIDLAbsolute(Type const& type,
00266             std::string const& field_name)
00267     {
00268         return ::getIDLAbsolute(type, m_exporter, field_name);
00269     }
00270     std::string IDLExportVisitor::getIDLRelative(Type const& type,
00271             std::string const& field_name)
00272     {
00273         return ::getIDLRelative(type, m_namespace, m_exporter, field_name);
00274     }
00275     pair<string, string> IDLExportVisitor::getIDLBase(Type const& type,
00276             std::string const& field_name)
00277     {
00278         return ::getIDLBase(type, m_exporter, field_name);
00279     }
00280 
00281     struct Indent
00282     {
00283         string& m_indent;
00284         string  m_save;
00285         Indent(string& current)
00286             : m_indent(current), m_save(current)
00287         { m_indent += "    "; }
00288         ~Indent() { m_indent = m_save; }
00289     };
00290 
00291     IDLExportVisitor::IDLExportVisitor(Registry const& registry, IDLExport const& exporter,
00292             std::map<std::string, Type const*>& exported_typedefs)
00293         : m_exporter(exporter)
00294         , m_exported_typedefs(exported_typedefs) {}
00295 
00296     bool IDLExportVisitor::visit_(Compound const& type)
00297     { 
00298         m_stream << m_indent << "struct " << normalizeIDLName(type.getBasename()) << " {\n";
00299         
00300         { Indent indenter(m_indent);
00301             TypeVisitor::visit_(type);
00302         }
00303 
00304         m_stream << m_indent
00305             << "};\n";
00306 
00307         return true;
00308     }
00309     bool IDLExportVisitor::visit_(Compound const& type, Field const& field)
00310     { 
00311         m_stream
00312             << m_indent
00313             << getIDLAbsolute(field.getType(), field.getName())
00314             << ";\n";
00315 
00316         return true;
00317     }
00318 
00319     bool IDLExportVisitor::visit_(Numeric const& type)
00320     {
00321         // no need to export Numeric types, they are already defined by IDL
00322         // itself
00323         return true;
00324     }
00325 
00326     bool IDLExportVisitor::visit_ (Pointer const& type)
00327     {
00328         throw UnsupportedType(type, "pointers are not allowed in IDL");
00329         return true;
00330     }
00331     bool IDLExportVisitor::visit_ (Array const& type)
00332     {
00333         throw UnsupportedType(type, "top-level arrays are not handled by the IDLExportVisitor");
00334         return true;
00335     }
00336 
00337     bool IDLExportVisitor::visit_ (Enum const& type)
00338     {
00339         m_stream << m_indent << "enum " << type.getBasename() << " { ";
00340 
00341         utilmm::stringlist symbols;
00342         Enum::ValueMap const& values = type.values();
00343         Enum::ValueMap::const_iterator it, end = values.end();
00344         for (it = values.begin(); it != end; ++it)
00345             symbols.push_back(it->first);
00346         m_stream << utilmm::join(symbols, ", ") << " };\n";
00347 
00348         return true;
00349     }
00350 
00351     bool IDLExportVisitor::visit_(Container const& type)
00352     {
00353         // sequence<> can be used as-is, but in order to be as cross-ORB
00354         // compatible as possible we generate sequence typedefs and use them in
00355         // the compounds. Emit the sequence right now.
00356         string target_namespace  = getIDLBase(type.getIndirection()).first;
00357         // We never emit sequences into the main namespace, even if their
00358         // element is a builtin
00359         if (target_namespace.empty())
00360             target_namespace = getIDLAbsoluteNamespace("/", m_exporter);
00361         setTargetNamespace(target_namespace);
00362 
00363         std::string element_name = getIDLAbsolute(type.getIndirection());
00364         std::string typedef_name = getIDLBase(type).second;
00365         boost::replace_all(typedef_name, "::", "_");
00366         m_stream << m_indent << "typedef sequence<" << element_name << "> " << typedef_name << ";\n";
00367         m_exported_typedefs.insert(make_pair(type.getIndirection().getNamespace() + typedef_name, &type));
00368 
00369         return true;
00370     }
00371     bool IDLExportVisitor::visit_(OpaqueType const& type)
00372     {
00373         if (m_exporter.marshalOpaquesAsAny())
00374             return true;
00375 
00376         throw UnsupportedType(type, "opaque types are not supported for export in IDL");
00377     }
00378 }
00379 
00380 using namespace std;
00381 IDLExport::IDLExport() 
00382     : m_namespace("/"), m_opaque_as_any(false) {}
00383 
00384 bool IDLExport::marshalOpaquesAsAny() const { return m_opaque_as_any; }
00385 
00386 void IDLExport::end
00387     ( ostream& stream
00388     , Typelib::Registry const& /*registry*/ )
00389 {
00390     generateTypedefs(stream);
00391 
00392     // Close the remaining namespaces
00393     utilmm::stringlist
00394         ns_levels = utilmm::split(m_namespace, "/");
00395     closeNamespaces(stream, ns_levels.size());
00396 }
00397 
00398 void IDLExport::closeNamespaces(ostream& stream, int levels)
00399 {
00400     for (int i = 0; i < levels; ++i)
00401     {
00402         m_indent = std::string(m_indent, 0, m_indent.size() - 4);
00403         stream << "\n" << m_indent << "};\n";
00404     }
00405 }
00406 
00407 void IDLExport::checkType(Type const& type)
00408 {
00409     if (type.getCategory() == Type::Pointer)
00410         throw UnsupportedType(type, "pointers are not allowed in IDL");
00411     if (type.getCategory() == Type::Array)
00412     {
00413         Type::Category pointed_to = static_cast<Indirect const&>(type).getIndirection().getCategory();
00414         if (pointed_to == Type::Array || pointed_to == Type::Pointer)
00415             throw UnsupportedType(type, "multi-dimensional arrays are not supported yet");
00416     }
00417 
00418 }
00419 
00420 void IDLExport::adaptNamespace(ostream& stream, string const& ns)
00421 {
00422     if (m_namespace != ns)
00423     {
00424         utilmm::stringlist
00425             old_namespace = utilmm::split(m_namespace, "/"),
00426             new_namespace = utilmm::split(ns, "/");
00427 
00428         while(!old_namespace.empty() && !new_namespace.empty() && old_namespace.front() == new_namespace.front())
00429         {
00430             old_namespace.pop_front();
00431             new_namespace.pop_front();
00432         }
00433 
00434         closeNamespaces(stream, old_namespace.size());
00435 
00436         while (!new_namespace.empty())
00437         {
00438             stream << m_indent << "module " << normalizeIDLName(new_namespace.front()) << " {\n";
00439             m_indent += "    ";
00440             new_namespace.pop_front();
00441         }
00442     }
00443     m_namespace = ns;
00444 }
00445 
00446 std::string IDLExport::getIDLAbsolute(Type const& type) const
00447 {
00448     return ::getIDLAbsolute(type, *this);
00449 }
00450 
00451 std::string IDLExport::getIDLRelative(Type const& type, std::string const& relative_to) const
00452 {
00453     return ::getIDLRelative(type, relative_to, *this);
00454 }
00455 
00456 void IDLExport::save
00457     ( ostream& stream
00458     , utilmm::config_set const& config
00459     , Typelib::Registry const& type )
00460 {
00461     m_ns_prefix = config.get<std::string>("namespace_prefix", "");
00462     if (!m_ns_prefix.empty() && string(m_ns_prefix, 0, 1) != Typelib::NamespaceMarkString)
00463         m_ns_prefix = Typelib::NamespaceMarkString + m_ns_prefix;
00464     m_ns_suffix = config.get<std::string>("namespace_suffix", "");
00465     if (!m_ns_suffix.empty() && string(m_ns_suffix, m_ns_suffix.length() - 1, 1) != Typelib::NamespaceMarkString)
00466         m_ns_suffix += Typelib::NamespaceMarkString;
00467     m_blob_threshold = config.get<int>("blob_threshold", 0);
00468     m_opaque_as_any  = config.get<bool>("opaque_as_any", false);
00469     list<string> selection = config.get< list<string> >("selected");
00470     m_selected_types = set<string>(selection.begin(), selection.end());
00471     return Exporter::save(stream, config, type);
00472 }
00473 
00474 void IDLExport::generateTypedefs(ostream& stream)
00475 {
00476     for (TypedefMap::const_iterator it = m_typedefs.begin();
00477             it != m_typedefs.end(); ++it)
00478     {
00479         adaptNamespace(stream, it->first);
00480 
00481         list<string> const& lines = it->second;
00482         for (list<string>::const_iterator str_it = lines.begin(); str_it != lines.end(); ++str_it)
00483             stream << m_indent << "typedef " << *str_it << std::endl;
00484     }
00485 }
00486 
00487 std::string IDLExport::getNamespacePrefix() const
00488 {
00489     return m_ns_prefix;
00490 }
00491 std::string IDLExport::getNamespaceSuffix() const
00492 {
00493     return m_ns_suffix;
00494 }
00495 
00496 bool IDLExport::save
00497     ( ostream& stream
00498     , Typelib::RegistryIterator const& type )
00499 {
00500     if (! m_selected_types.empty())
00501     {
00502         if (m_selected_types.count(type->getName()) == 0)
00503         {
00504             return false;
00505         }
00506     }
00507 
00508     if (type.isAlias())
00509     {
00510         // IDL has C++-like rules for struct and enums. Do not alias a "struct A" to "A";
00511         if (type->getNamespace() != type.getNamespace()
00512                 || (type->getBasename() != "struct " + type.getBasename()
00513                     && type->getBasename() != "enum " + type.getBasename()
00514                     && type.getBasename() != "struct " + type->getBasename()
00515                     && type.getBasename() != "enum " + type->getBasename()))
00516         {
00517             IDLExport::checkType(*type);
00518             ostringstream stream;
00519 
00520             std::string type_namespace = getIDLAbsoluteNamespace(type.getNamespace(), *this);
00521 
00522             map<string, Type const*>::const_iterator already_exported =
00523                 m_exported_typedefs.find(type.getName());
00524             if (already_exported != m_exported_typedefs.end())
00525             {
00526                 if (*already_exported->second != *type)
00527                     throw UnsupportedType(*type, "the typedef name " + type.getName() + " is reserved by the IDL exporter");
00528                 return false;
00529             }
00530             else if (type.getBasename().find_first_of("/<>") != std::string::npos)
00531             {
00532                 return false;
00533             }
00534 
00535             // Alias types using typedef, taking into account that the aliased type
00536             // may not be in the same module than the new alias.
00537             if (type->getCategory() == Type::Array)
00538             {
00539                 Array const& array_t = dynamic_cast<Array const&>(*type);
00540                 stream 
00541                     << getIDLAbsolute(array_t.getIndirection())
00542                     << " " << type.getBasename() << "[" << array_t.getDimension() << "];";
00543             }
00544             else if (type->getCategory() == Type::Container)
00545             {
00546                 // Generate a sequence, regardless of the actual container type
00547                 Container const& container_t = dynamic_cast<Container const&>(*type);
00548                 stream << "sequence<" << getIDLAbsolute(container_t.getIndirection()) << "> " << type.getBasename() << ";";
00549             }
00550             else if (type->getCategory() == Type::Opaque)
00551             {
00552                 if (marshalOpaquesAsAny())
00553                     stream << "any " << type.getBasename() << ";";
00554             }
00555             else if (type.getBasename().find_first_of(" ") == string::npos)
00556                 stream << getIDLAbsolute(*type) << " " << type.getBasename() << ";";
00557 
00558             std::string def = stream.str();
00559             if (!def.empty())
00560                 m_typedefs[type_namespace].push_back(def);
00561             return true;
00562         }
00563         else return false;
00564     }
00565     else
00566     {
00567         // Don't call adaptNamespace right now, since some types can be simply
00568         // ignored by the IDLExportVisitor -- resulting in an empty module,
00569         // which is not accepted in IDL
00570         //
00571         // Instead, act "as if" the namespace was changed, capturing the output
00572         // in a temporary ostringstream and change namespace only if some output
00573         // has actually been generated
00574         
00575         if (m_blob_threshold && static_cast<int>(type->getSize()) > m_blob_threshold)
00576         {
00577             string target_namespace = getIDLAbsoluteNamespace(type.getNamespace(), *this);
00578             size_t ns_size = utilmm::split(target_namespace, "/").size();
00579             string indent_string = string(ns_size * 4, ' ');
00580 
00581             adaptNamespace(stream, target_namespace);
00582             stream << indent_string << "typedef sequence<octet> " << type->getBasename() << ";\n";
00583             return true;
00584         }
00585         else
00586         {
00587             IDLExportVisitor exporter(type.getRegistry(), *this, m_exported_typedefs);
00588             exporter.apply(*type);
00589 
00590             string result = exporter.getResult();
00591             if (result.empty())
00592                 return false;
00593             else
00594             {
00595                 adaptNamespace(stream, exporter.getTargetNamespace());
00596                 stream << result;
00597                 return true;
00598             }
00599         }
00600     }
00601 }
00602 
00603 TYPELIB_REGISTER_IO1(idl, IDLExport)
00604 


typelib
Author(s): Sylvain Joyeux/sylvain.joyeux@m4x.org
autogenerated on Thu Jan 2 2014 11:38:41