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         if (type.getName() == "/std/string")
00354             return true;
00355                 
00356         // sequence<> can be used as-is, but in order to be as cross-ORB
00357         // compatible as possible we generate sequence typedefs and use them in
00358         // the compounds. Emit the sequence right now.
00359         string target_namespace  = getIDLBase(type.getIndirection()).first;
00360         // We never emit sequences into the main namespace, even if their
00361         // element is a builtin
00362         if (target_namespace.empty())
00363             target_namespace = getIDLAbsoluteNamespace("/", m_exporter);
00364         setTargetNamespace(target_namespace);
00365 
00366         std::string element_name = getIDLAbsolute(type.getIndirection());
00367         std::string typedef_name = getIDLBase(type).second;
00368         boost::replace_all(typedef_name, "::", "_");
00369         m_stream << m_indent << "typedef sequence<" << element_name << "> " << typedef_name << ";\n";
00370         m_exported_typedefs.insert(make_pair(type.getIndirection().getNamespace() + typedef_name, &type));
00371 
00372         return true;
00373     }
00374     bool IDLExportVisitor::visit_(OpaqueType const& type)
00375     {
00376         if (m_exporter.marshalOpaquesAsAny())
00377             return true;
00378 
00379         throw UnsupportedType(type, "opaque types are not supported for export in IDL");
00380     }
00381 }
00382 
00383 using namespace std;
00384 IDLExport::IDLExport() 
00385     : m_namespace("/"), m_opaque_as_any(false) {}
00386 
00387 bool IDLExport::marshalOpaquesAsAny() const { return m_opaque_as_any; }
00388 
00389 void IDLExport::end
00390     ( ostream& stream
00391     , Typelib::Registry const& /*registry*/ )
00392 {
00393     generateTypedefs(stream);
00394 
00395     // Close the remaining namespaces
00396     utilmm::stringlist
00397         ns_levels = utilmm::split(m_namespace, "/");
00398     closeNamespaces(stream, ns_levels.size());
00399 }
00400 
00401 void IDLExport::closeNamespaces(ostream& stream, int levels)
00402 {
00403     for (int i = 0; i < levels; ++i)
00404     {
00405         m_indent = std::string(m_indent, 0, m_indent.size() - 4);
00406         stream << "\n" << m_indent << "};\n";
00407     }
00408 }
00409 
00410 void IDLExport::checkType(Type const& type)
00411 {
00412     if (type.getCategory() == Type::Pointer)
00413         throw UnsupportedType(type, "pointers are not allowed in IDL");
00414     if (type.getCategory() == Type::Array)
00415     {
00416         Type::Category pointed_to = static_cast<Indirect const&>(type).getIndirection().getCategory();
00417         if (pointed_to == Type::Array || pointed_to == Type::Pointer)
00418             throw UnsupportedType(type, "multi-dimensional arrays are not supported yet");
00419     }
00420 
00421 }
00422 
00423 void IDLExport::adaptNamespace(ostream& stream, string const& ns)
00424 {
00425     if (m_namespace != ns)
00426     {
00427         utilmm::stringlist
00428             old_namespace = utilmm::split(m_namespace, "/"),
00429             new_namespace = utilmm::split(ns, "/");
00430 
00431         while(!old_namespace.empty() && !new_namespace.empty() && old_namespace.front() == new_namespace.front())
00432         {
00433             old_namespace.pop_front();
00434             new_namespace.pop_front();
00435         }
00436 
00437         closeNamespaces(stream, old_namespace.size());
00438 
00439         while (!new_namespace.empty())
00440         {
00441             stream << m_indent << "module " << normalizeIDLName(new_namespace.front()) << " {\n";
00442             m_indent += "    ";
00443             new_namespace.pop_front();
00444         }
00445     }
00446     m_namespace = ns;
00447 }
00448 
00449 std::string IDLExport::getIDLAbsolute(Type const& type) const
00450 {
00451     return ::getIDLAbsolute(type, *this);
00452 }
00453 
00454 std::string IDLExport::getIDLRelative(Type const& type, std::string const& relative_to) const
00455 {
00456     return ::getIDLRelative(type, relative_to, *this);
00457 }
00458 
00459 void IDLExport::save
00460     ( ostream& stream
00461     , utilmm::config_set const& config
00462     , Typelib::Registry const& type )
00463 {
00464     m_ns_prefix = config.get<std::string>("namespace_prefix", "");
00465     if (!m_ns_prefix.empty() && string(m_ns_prefix, 0, 1) != Typelib::NamespaceMarkString)
00466         m_ns_prefix = Typelib::NamespaceMarkString + m_ns_prefix;
00467     m_ns_suffix = config.get<std::string>("namespace_suffix", "");
00468     if (!m_ns_suffix.empty() && string(m_ns_suffix, m_ns_suffix.length() - 1, 1) != Typelib::NamespaceMarkString)
00469         m_ns_suffix += Typelib::NamespaceMarkString;
00470     m_blob_threshold = config.get<int>("blob_threshold", 0);
00471     m_opaque_as_any  = config.get<bool>("opaque_as_any", false);
00472     list<string> selection = config.get< list<string> >("selected");
00473     m_selected_types = set<string>(selection.begin(), selection.end());
00474     return Exporter::save(stream, config, type);
00475 }
00476 
00477 void IDLExport::generateTypedefs(ostream& stream)
00478 {
00479     for (TypedefMap::const_iterator it = m_typedefs.begin();
00480             it != m_typedefs.end(); ++it)
00481     {
00482         adaptNamespace(stream, it->first);
00483 
00484         list<string> const& lines = it->second;
00485         for (list<string>::const_iterator str_it = lines.begin(); str_it != lines.end(); ++str_it)
00486             stream << m_indent << "typedef " << *str_it << std::endl;
00487     }
00488 }
00489 
00490 std::string IDLExport::getNamespacePrefix() const
00491 {
00492     return m_ns_prefix;
00493 }
00494 std::string IDLExport::getNamespaceSuffix() const
00495 {
00496     return m_ns_suffix;
00497 }
00498 
00499 bool IDLExport::save
00500     ( ostream& stream
00501     , Typelib::RegistryIterator const& type )
00502 {
00503     if (! m_selected_types.empty())
00504     {
00505         if (m_selected_types.count(type->getName()) == 0)
00506         {
00507             return false;
00508         }
00509     }
00510 
00511     if (type.isAlias())
00512     {
00513         // IDL has C++-like rules for struct and enums. Do not alias a "struct A" to "A";
00514         if (type->getNamespace() != type.getNamespace()
00515                 || (type->getBasename() != "struct " + type.getBasename()
00516                     && type->getBasename() != "enum " + type.getBasename()
00517                     && type.getBasename() != "struct " + type->getBasename()
00518                     && type.getBasename() != "enum " + type->getBasename()))
00519         {
00520             IDLExport::checkType(*type);
00521             ostringstream stream;
00522 
00523             std::string type_namespace = getIDLAbsoluteNamespace(type.getNamespace(), *this);
00524 
00525             map<string, Type const*>::const_iterator already_exported =
00526                 m_exported_typedefs.find(type.getName());
00527             if (already_exported != m_exported_typedefs.end())
00528             {
00529                 if (*already_exported->second != *type)
00530                     throw UnsupportedType(*type, "the typedef name " + type.getName() + " is reserved by the IDL exporter");
00531                 return false;
00532             }
00533             else if (type.getBasename().find_first_of("/<>") != std::string::npos)
00534             {
00535                 return false;
00536             }
00537 
00538             // Alias types using typedef, taking into account that the aliased type
00539             // may not be in the same module than the new alias.
00540             if (type->getCategory() == Type::Array)
00541             {
00542                 Array const& array_t = dynamic_cast<Array const&>(*type);
00543                 stream 
00544                     << getIDLAbsolute(array_t.getIndirection())
00545                     << " " << type.getBasename() << "[" << array_t.getDimension() << "];";
00546             }
00547             else if (type->getCategory() == Type::Container && type->getName() != "/std/string")
00548             {
00549                 // Generate a sequence, regardless of the actual container type
00550                 Container const& container_t = dynamic_cast<Container const&>(*type);
00551                 stream << "sequence<" << getIDLAbsolute(container_t.getIndirection()) << "> " << type.getBasename() << ";";
00552             }
00553             else if (type->getCategory() == Type::Opaque)
00554             {
00555                 if (marshalOpaquesAsAny())
00556                     stream << "any " << type.getBasename() << ";";
00557             }
00558             else if (type.getBasename().find_first_of(" ") == string::npos)
00559                 stream << getIDLAbsolute(*type) << " " << type.getBasename() << ";";
00560 
00561             std::string def = stream.str();
00562             if (!def.empty())
00563                 m_typedefs[type_namespace].push_back(def);
00564             return true;
00565         }
00566         else return false;
00567     }
00568     else
00569     {
00570         // Don't call adaptNamespace right now, since some types can be simply
00571         // ignored by the IDLExportVisitor -- resulting in an empty module,
00572         // which is not accepted in IDL
00573         //
00574         // Instead, act "as if" the namespace was changed, capturing the output
00575         // in a temporary ostringstream and change namespace only if some output
00576         // has actually been generated
00577         
00578         if (m_blob_threshold && static_cast<int>(type->getSize()) > m_blob_threshold)
00579         {
00580             string target_namespace = getIDLAbsoluteNamespace(type.getNamespace(), *this);
00581             size_t ns_size = utilmm::split(target_namespace, "/").size();
00582             string indent_string = string(ns_size * 4, ' ');
00583 
00584             adaptNamespace(stream, target_namespace);
00585             stream << indent_string << "typedef sequence<octet> " << type->getBasename() << ";\n";
00586             return true;
00587         }
00588         else
00589         {
00590             IDLExportVisitor exporter(type.getRegistry(), *this, m_exported_typedefs);
00591             exporter.apply(*type);
00592 
00593             string result = exporter.getResult();
00594             if (result.empty())
00595                 return false;
00596             else
00597             {
00598                 adaptNamespace(stream, exporter.getTargetNamespace());
00599                 stream << result;
00600                 return true;
00601             }
00602         }
00603     }
00604 }
00605 
00606 TYPELIB_REGISTER_IO1(idl, IDLExport)
00607 


typelib
Author(s): Sylvain Joyeux/sylvain.joyeux@m4x.org
autogenerated on Mon Sep 14 2015 15:08:17