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


typelib
Author(s): Sylvain Joyeux/sylvain.joyeux@m4x.org
autogenerated on Sat Jun 8 2019 18:49:22