[asterisk-scf-commits] asterisk-scf/release/ice.git branch "slice-plugins" created.

Commits to the Asterisk SCF project code repositories asterisk-scf-commits at lists.digium.com
Wed Jan 19 13:20:41 CST 2011


branch "slice-plugins" has been created
        at  490e1ba4fec8eef351aeeafe6b0e4844b169ffdd (commit)

- Log -----------------------------------------------------------------
commit 490e1ba4fec8eef351aeeafe6b0e4844b169ffdd
Author: Kevin P. Fleming <kpfleming at digium.com>
Date:   Wed Jan 19 13:18:52 2011 -0600

    Add support for Slice translator plugins to slice2cpp, slice2java,
    slice2cs and slice2py (including dynamic translation for Python).

diff --git a/cpp/include/Slice/CsUtil.h b/cpp/include/Slice/CsUtil.h
index eaa767d..2f3b729 100644
--- a/cpp/include/Slice/CsUtil.h
+++ b/cpp/include/Slice/CsUtil.h
@@ -32,10 +32,11 @@ public:
     //
     static void validateMetaData(const UnitPtr&);
 
+    static std::string typeToString(const TypePtr&);
+
 protected:
     static std::string fixId(const std::string&, int = 0, bool = false);
     static std::string fixId(const ContainedPtr&, int = 0, bool = false);
-    static std::string typeToString(const TypePtr&);
     static bool isValueType(const TypePtr&);
 
     //
diff --git a/cpp/include/Slice/JavaUtil.h b/cpp/include/Slice/JavaUtil.h
index c1fdd50..0bbd18f 100644
--- a/cpp/include/Slice/JavaUtil.h
+++ b/cpp/include/Slice/JavaUtil.h
@@ -54,6 +54,20 @@ public:
 
     void close();
 
+    //
+    // Get the Java name for a type. If an optional scope is provided,
+    // the scope will be removed from the result if possible.
+    //
+    enum TypeMode
+    {
+        TypeModeIn,
+        TypeModeOut,
+        TypeModeMember,
+        TypeModeReturn
+    };
+    static std::string typeToString(const TypePtr&, TypeMode, const std::string& = std::string(),
+                             const StringList& = StringList(), bool = true);
+
 protected:
 
     JavaGenerator(const std::string&);
@@ -70,57 +84,43 @@ protected:
     // Check a symbol against any of the Java keywords. If a
     // match is found, return the symbol with a leading underscore.
     //
-    std::string fixKwd(const std::string&) const;
+    static std::string fixKwd(const std::string&);
 
     //
     // Convert a Slice scoped name into a Java name.
     //
-    std::string convertScopedName(const std::string&,
-                                  const std::string& = std::string(),
-                                  const std::string& = std::string()) const;
+    static std::string convertScopedName(const std::string&,
+                                         const std::string& = std::string(),
+                                         const std::string& = std::string());
 
 
     //
     // Returns the package prefix for a give Slice file.
     //
-    std::string getPackagePrefix(const ContainedPtr&) const;
+    static std::string getPackagePrefix(const ContainedPtr&);
 
     //
     // Returns the Java package of a Contained entity.
     //
-    std::string getPackage(const ContainedPtr&) const;
+    static std::string getPackage(const ContainedPtr&);
 
     //
     // Returns the Java name for a Contained entity. If the optional
     // package argument matches the entity's package name, then the
     // package is removed from the result.
     //
-    std::string getAbsolute(const ContainedPtr&,
-                            const std::string& = std::string(),
-                            const std::string& = std::string(),
-                            const std::string& = std::string()) const;
-
-    //
-    // Get the Java name for a type. If an optional scope is provided,
-    // the scope will be removed from the result if possible.
-    //
-    enum TypeMode
-    {
-        TypeModeIn,
-        TypeModeOut,
-        TypeModeMember,
-        TypeModeReturn
-    };
-    std::string typeToString(const TypePtr&, TypeMode, const std::string& = std::string(),
-                             const StringList& = StringList(), bool = true) const;
+    static std::string getAbsolute(const ContainedPtr&,
+                                   const std::string& = std::string(),
+                                   const std::string& = std::string(),
+                                   const std::string& = std::string());
 
     //
     // Get the Java object name for a type. For primitive types, this returns the
     // Java class type (e.g., Integer). For all other types, this function delegates
     // to typeToString.
     //
-    std::string typeToObjectString(const TypePtr&, TypeMode, const std::string& = std::string(),
-                                   const StringList& = StringList(), bool = true) const;
+    static std::string typeToObjectString(const TypePtr&, TypeMode, const std::string& = std::string(),
+                                          const StringList& = StringList(), bool = true);
 
     //
     // Generate code to marshal or unmarshal a type.
@@ -183,9 +183,9 @@ protected:
     // The functions return true if a custom type was defined and false to indicate
     // the default mapping was used.
     //
-    bool getDictionaryTypes(const DictionaryPtr&, const std::string&, const StringList&,
-                            std::string&, std::string&) const;
-    bool getSequenceTypes(const SequencePtr&, const std::string&, const StringList&, std::string&, std::string&) const;
+    static bool getDictionaryTypes(const DictionaryPtr&, const std::string&, const StringList&,
+                            std::string&, std::string&);
+    static bool getSequenceTypes(const SequencePtr&, const std::string&, const StringList&, std::string&, std::string&);
 
     virtual JavaOutput* createOutput();
 
@@ -223,7 +223,7 @@ private:
 
     std::string _dir;
     ::IceUtilInternal::Output* _out;
-    mutable std::map<std::string, std::string> _filePackagePrefix;
+    static std::map<std::string, std::string> _filePackagePrefix;
 };
 
 }
diff --git a/cpp/include/Slice/Parser.h b/cpp/include/Slice/Parser.h
index ad390b1..86ee25b 100644
--- a/cpp/include/Slice/Parser.h
+++ b/cpp/include/Slice/Parser.h
@@ -83,6 +83,7 @@ class Proxy;
 class Exception;
 class Struct;
 class Operation;
+class GeneratedOperation;
 class ParamDecl;
 class DataMember;
 class Sequence;
@@ -109,6 +110,7 @@ typedef ::IceUtil::Handle<Proxy> ProxyPtr;
 typedef ::IceUtil::Handle<Exception> ExceptionPtr;
 typedef ::IceUtil::Handle<Struct> StructPtr;
 typedef ::IceUtil::Handle<Operation> OperationPtr;
+typedef ::IceUtil::Handle<GeneratedOperation> GeneratedOperationPtr;
 typedef ::IceUtil::Handle<ParamDecl> ParamDeclPtr;
 typedef ::IceUtil::Handle<DataMember> DataMemberPtr;
 typedef ::IceUtil::Handle<Sequence> SequencePtr;
@@ -135,6 +137,7 @@ typedef std::list<DictionaryPtr> DictionaryList;
 typedef std::list<EnumPtr> EnumList;
 typedef std::list<ConstPtr> ConstList;
 typedef std::list<OperationPtr> OperationList;
+typedef std::list<GeneratedOperationPtr> GeneratedOperationList;
 typedef std::list<DataMemberPtr> DataMemberList;
 typedef std::list<ParamDeclPtr> ParamDeclList;
 typedef std::list<EnumeratorPtr> EnumeratorList;
@@ -199,6 +202,7 @@ public:
     virtual bool visitStructStart(const StructPtr&) { return true; }
     virtual void visitStructEnd(const StructPtr&) { }
     virtual void visitOperation(const OperationPtr&) { }
+    virtual void visitGeneratedOperation(const GeneratedOperationPtr&) { }
     virtual void visitParamDecl(const ParamDeclPtr&) { }
     virtual void visitDataMember(const DataMemberPtr&) { }
     virtual void visitSequence(const SequencePtr&) { }
@@ -365,6 +369,7 @@ public:
         ContainedTypeException,
         ContainedTypeStruct,
         ContainedTypeOperation,
+	ContainedTypeGeneratedOperation,
         ContainedTypeParamDecl,
         ContainedTypeDataMember,
         ContainedTypeConstant
@@ -452,12 +457,12 @@ public:
     bool checkIntroduced(const std::string&, ContainedPtr = 0);
     bool nameIsLegal(const std::string&, const char *);
     bool checkForGlobalDef(const std::string&, const char *);
+    void checkIdentifier(const std::string&) const;
 
 protected:
 
     Container(const UnitPtr&);
 
-    void checkIdentifier(const std::string&) const;
     bool checkInterfaceAndLocal(const std::string&, bool, bool, bool, bool, bool);
     bool checkGlobalMetaData(const StringList&, const StringList&);
     bool validateConstant(const std::string&, const TypePtr&, const SyntaxTreeBasePtr&, const std::string&, bool);
@@ -594,6 +599,57 @@ protected:
 };
 
 // ----------------------------------------------------------------------
+// GeneratedOperation
+//
+// Note: These are operations generated by translator code, not defined
+// in the Slice source file. In addition, they are *local* operations
+// on the class, not part of the remote interface to the class if it
+// has one.
+//
+// GeneratedOperations can be either abstract (no body specified) or
+// concrete (body specified). If the body is specified, it will be a
+// StringList, and each string in the list will be emitted into the
+// function body in a manner specific to the language the translator
+// writes. An empty list will be treated as 'no body', so if you want to
+// have a non-abstract operation generated without any code in the body
+// you'll need to provide a StringList with an empty string in it.
+// ----------------------------------------------------------------------
+
+class SLICE_API GeneratedOperation : virtual public Contained, virtual public Container
+{
+public:
+    
+    enum Mode
+    {
+        Normal,
+        Nonmutating
+    };
+
+    TypePtr returnType() const;
+    Mode mode() const;
+    ParamDeclPtr createParamDecl(const std::string&, const TypePtr&, bool);
+    ParamDeclList parameters() const;
+    virtual ContainedType containedType() const;
+    virtual bool uses(const ContainedPtr&) const;
+    StringList body() const;
+    bool isAbstract() const;
+    bool isOverride() const;
+    void setOverride(bool);
+    virtual std::string kindOf() const;
+    virtual void visit(ParserVisitor*, bool);
+
+protected:
+
+    GeneratedOperation(const ContainerPtr&, const std::string&, const TypePtr&, const StringList&, Mode);
+    friend class ClassDef;
+
+    TypePtr _returnType;
+    Mode _mode;
+    StringList _body;
+    bool _override;
+};
+
+// ----------------------------------------------------------------------
 // ClassDef
 // ----------------------------------------------------------------------
 
@@ -610,6 +666,8 @@ public:
 
     virtual void destroy();
     OperationPtr createOperation(const std::string&, const TypePtr&, Operation::Mode = Operation::Normal);
+    GeneratedOperationPtr createGeneratedOperation(const std::string&, const TypePtr&, const StringList&,
+                                                   GeneratedOperation::Mode = GeneratedOperation::Normal);
     DataMemberPtr createDataMember(const std::string&, const TypePtr&, const SyntaxTreeBasePtr&, const std::string&,
                                    const std::string&);
     ClassDeclPtr declaration() const;
@@ -617,6 +675,7 @@ public:
     ClassList allBases() const;
     OperationList operations() const;
     OperationList allOperations() const;
+    GeneratedOperationList generatedOperations() const;
     DataMemberList dataMembers() const;
     DataMemberList allDataMembers() const;
     DataMemberList classDataMembers() const;
@@ -628,6 +687,7 @@ public:
     virtual bool isLocal() const;
     bool hasDataMembers() const;
     bool hasOperations() const;
+    bool hasGeneratedOperations() const;
     bool hasDefaultValues() const;
     virtual ContainedType containedType() const;
     virtual bool uses(const ContainedPtr&) const;
@@ -643,6 +703,7 @@ protected:
     bool _interface;
     bool _hasDataMembers;
     bool _hasOperations;
+    bool _hasGeneratedOperations;
     ClassList _bases;
     bool _local;
 };
@@ -894,7 +955,11 @@ public:
 protected:
 
     ParamDecl(const ContainerPtr&, const std::string&, const TypePtr&, bool isOutParam);
+    static ParamDeclPtr createCommon(const std::string&, const TypePtr&, bool,
+                                     ContainedList&, const ContainerPtr&, const ContainedPtr&,
+                                     const UnitPtr&, bool);
     friend class Operation;
+    friend class GeneratedOperation;
 
     TypePtr _type;
     bool _isOutParam;
diff --git a/cpp/include/Slice/Plugin.h b/cpp/include/Slice/Plugin.h
new file mode 100644
index 0000000..7649d90
--- /dev/null
+++ b/cpp/include/Slice/Plugin.h
@@ -0,0 +1,30 @@
+#ifndef SLICE_PLUGIN_H
+#define SLICE_PLUGIN_H
+
+#include <Slice/Parser.h>
+
+namespace Slice
+{
+
+namespace Plugin
+{
+
+    enum Language
+    {
+        LanguageCPlusPlus,
+        LanguageCs,
+        LanguageJava,
+        LanguagePython,
+        LanguageRuby,
+        LanguagePHP
+    };
+
+    typedef std::list<ParserVisitor *> VisitorList;
+
+    typedef VisitorList* (*FACTORY)(Plugin::Language);
+
+}
+
+}
+
+#endif
diff --git a/cpp/include/Slice/PythonUtil.h b/cpp/include/Slice/PythonUtil.h
index bd6bab1..a104de9 100644
--- a/cpp/include/Slice/PythonUtil.h
+++ b/cpp/include/Slice/PythonUtil.h
@@ -21,7 +21,8 @@ namespace Python
 //
 // Generate Python code for a translation unit.
 //
-SLICE_API void generate(const Slice::UnitPtr&, bool, bool, const std::vector<std::string>&, IceUtilInternal::Output&);
+SLICE_API void generate(const Slice::UnitPtr&, bool, bool, const std::vector<std::string>&, IceUtilInternal::Output&,
+                        const std::vector<std::string>&);
 
 //
 // Convert a scoped name into a Python name.
diff --git a/cpp/src/Slice/JavaUtil.cpp b/cpp/src/Slice/JavaUtil.cpp
index 5c06896..51ecce4 100644
--- a/cpp/src/Slice/JavaUtil.cpp
+++ b/cpp/src/Slice/JavaUtil.cpp
@@ -169,6 +169,8 @@ Slice::JavaOutput::printHeader()
 
 const string Slice::JavaGenerator::_getSetMetaData = "java:getset";
 
+map<string, string> Slice::JavaGenerator::_filePackagePrefix;
+
 Slice::JavaGenerator::JavaGenerator(const string& dir) :
     _dir(dir),
     _out(0)
@@ -292,7 +294,7 @@ splitScopedName(const string& scoped)
 // otherwise, return the name unchanged.
 //
 string
-Slice::JavaGenerator::fixKwd(const string& name) const
+Slice::JavaGenerator::fixKwd(const string& name)
 {
     if(name.empty())
     {
@@ -313,7 +315,7 @@ Slice::JavaGenerator::fixKwd(const string& name) const
 }
 
 string
-Slice::JavaGenerator::convertScopedName(const string& scoped, const string& prefix, const string& suffix) const
+Slice::JavaGenerator::convertScopedName(const string& scoped, const string& prefix, const string& suffix)
 {
     string result;
     string::size_type start = 0;
@@ -363,7 +365,7 @@ Slice::JavaGenerator::convertScopedName(const string& scoped, const string& pref
 }
 
 string
-Slice::JavaGenerator::getPackagePrefix(const ContainedPtr& cont) const
+Slice::JavaGenerator::getPackagePrefix(const ContainedPtr& cont)
 {
     UnitPtr unit = cont->container()->unit();
     string file = cont->file();
@@ -388,7 +390,7 @@ Slice::JavaGenerator::getPackagePrefix(const ContainedPtr& cont) const
 }
 
 string
-Slice::JavaGenerator::getPackage(const ContainedPtr& cont) const
+Slice::JavaGenerator::getPackage(const ContainedPtr& cont)
 {
     string scope = convertScopedName(cont->scope());
     string prefix = getPackagePrefix(cont);
@@ -411,7 +413,7 @@ string
 Slice::JavaGenerator::getAbsolute(const ContainedPtr& cont,
                                   const string& package,
                                   const string& prefix,
-                                  const string& suffix) const
+                                  const string& suffix)
 {
     string name = cont->name();
     if(prefix == "" && suffix == "")
@@ -438,7 +440,7 @@ Slice::JavaGenerator::typeToString(const TypePtr& type,
                                    TypeMode mode,
                                    const string& package,
                                    const StringList& metaData,
-                                   bool formal) const
+                                   bool formal)
 {
     static const char* builtinTable[] =
     {
@@ -619,7 +621,7 @@ Slice::JavaGenerator::typeToObjectString(const TypePtr& type,
                                          TypeMode mode,
                                          const string& package,
                                          const StringList& metaData,
-                                         bool formal) const
+                                         bool formal)
 {
     static const char* builtinTable[] =
     {
@@ -2458,7 +2460,7 @@ Slice::JavaGenerator::getDictionaryTypes(const DictionaryPtr& dict,
                                          const string& package,
                                          const StringList& metaData,
                                          string& instanceType,
-                                         string& formalType) const
+                                         string& formalType)
 {
     bool customType = false;
 
@@ -2516,7 +2518,7 @@ Slice::JavaGenerator::getSequenceTypes(const SequencePtr& seq,
                                        const string& package,
                                        const StringList& metaData,
                                        string& instanceType,
-                                       string& formalType) const
+                                       string& formalType)
 {
     bool customType = false;
 
diff --git a/cpp/src/Slice/Parser.cpp b/cpp/src/Slice/Parser.cpp
index 5711c7b..8eac593 100644
--- a/cpp/src/Slice/Parser.cpp
+++ b/cpp/src/Slice/Parser.cpp
@@ -2955,6 +2955,94 @@ Slice::ClassDef::createOperation(const string& name,
     return op;
 }
 
+GeneratedOperationPtr
+Slice::ClassDef::createGeneratedOperation(const string& name,
+					  const TypePtr& returnType,
+					  const StringList& body,
+                                          GeneratedOperation::Mode mode)
+{
+    checkIdentifier(name);
+
+    ContainedList matches = _unit->findContents(thisScope() + name);
+    if(!matches.empty())
+    {
+        if(matches.front()->name() != name)
+        {
+            string msg = "operation `" + name + "' differs only in capitalization from ";
+            msg += matches.front()->kindOf() + " `" + matches.front()->name() + "'";
+            _unit->error(msg);
+        }
+        string msg = "redefinition of " + matches.front()->kindOf() + " `" + matches.front()->name();
+        msg += "' as operation `" + name + "'";
+        _unit->error(msg);
+        return 0;
+    }
+
+    //
+    // Check whether enclosing interface/class has the same name.
+    //
+    if(name == this->name())
+    {
+        string msg = isInterface() ? "interface" : "class";
+        msg += " name `" + name + "' cannot be used as operation name";
+        _unit->error(msg);
+        return 0;
+    }
+
+    string newName = IceUtilInternal::toLower(name);
+    string thisName = IceUtilInternal::toLower(this->name());
+    if(newName == thisName)
+    {
+        string msg = "operation `" + name + "' differs only in capitalization from enclosing ";
+        msg += isInterface() ? "interface" : "class";
+        msg += " name `" + this->name() + "'";
+        _unit->error(msg);
+    }
+
+    //
+    // Check whether any bases have defined something with the same name already.
+    //
+    for(ClassList::const_iterator p = _bases.begin(); p != _bases.end(); ++p)
+    {
+        ContainedList cl;
+        OperationList ol = (*p)->allOperations();
+        copy(ol.begin(), ol.end(), back_inserter(cl));
+        DataMemberList dml = (*p)->allDataMembers();
+        copy(dml.begin(), dml.end(), back_inserter(cl));
+        for(ContainedList::const_iterator q = cl.begin(); q != cl.end(); ++q)
+        {
+            if((*q)->name() == name)
+            {
+                string msg = "operation `" + name;
+                msg += "' is already defined as a";
+                static const string vowels = "aeiou";
+                string kindOf = (*q)->kindOf();
+                if(vowels.find_first_of(kindOf[0]) != string::npos)
+                {
+                    msg += "n";
+                }
+                msg += " " + kindOf + " in a base interface or class";
+                _unit->error(msg);
+                return 0;
+            }
+
+            string baseName = IceUtilInternal::toLower((*q)->name());
+            string newName = IceUtilInternal::toLower(name);
+            if(baseName == newName)
+            {
+                string msg = "operation `" + name + "' differs only in capitalization from " + (*q)->kindOf();
+                msg += " `" + (*q)->name() + "', which is defined in a base interface or class";
+                _unit->error(msg);
+            }
+        }
+    }
+
+    _hasGeneratedOperations = true;
+    GeneratedOperationPtr gop = new GeneratedOperation(this, name, returnType, body, mode);
+    _contents.push_back(gop);
+    return gop;
+}
+
 DataMemberPtr
 Slice::ClassDef::createDataMember(const string& name, const TypePtr& type, const SyntaxTreeBasePtr& defaultLiteralType,
                                   const string& defaultValue, const string& defaultLiteral)
@@ -3248,6 +3336,21 @@ Slice::ClassDef::allClassDataMembers() const
     return result;
 }
 
+GeneratedOperationList
+Slice::ClassDef::generatedOperations() const
+{
+    GeneratedOperationList result;
+    for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p)
+    {
+        GeneratedOperationPtr q = GeneratedOperationPtr::dynamicCast(*p);
+        if(q)
+        {
+            result.push_back(q);
+        }
+    }
+    return result;
+}
+
 bool
 Slice::ClassDef::canBeCyclic() const
 {
@@ -3285,6 +3388,13 @@ Slice::ClassDef::isAbstract() const
         {
             return true;
         }
+        if(GeneratedOperationPtr gop = GeneratedOperationPtr::dynamicCast(*p))
+        {
+            if(gop->isAbstract())
+            {
+                return true;
+            }
+        }
     }
 
     return false;
@@ -3332,6 +3442,12 @@ Slice::ClassDef::hasOperations() const
 }
 
 bool
+Slice::ClassDef::hasGeneratedOperations() const
+{
+    return _hasGeneratedOperations;
+}
+
+bool
 Slice::ClassDef::hasDefaultValues() const
 {
     DataMemberList dml = dataMembers();
@@ -4564,106 +4680,7 @@ Slice::Operation::sendMode() const
 ParamDeclPtr
 Slice::Operation::createParamDecl(const string& name, const TypePtr& type, bool isOutParam)
 {
-    checkIdentifier(name);
-
-    if(_unit->profile() == IceE)
-    {
-        ClassDefPtr cl = ClassDefPtr::dynamicCast(this->container());
-        assert(cl);
-        if(!cl->isLocal())
-        {
-            BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
-            if((builtin && builtin->kind() == Builtin::KindObject))
-            {
-                string msg = "Object `" + name + "' cannot be passed by value.";
-                _unit->error(msg);
-                return 0;
-            }
-            ClassDeclPtr classDecl =  ClassDeclPtr::dynamicCast(type);
-            if(classDecl != 0 && !classDecl->isLocal())
-            {
-                string msg = "Object `" + name + "' cannot be passed by value.";
-                _unit->error(msg);
-                return 0;
-            }
-        }
-    }
-
-    ContainedList matches = _unit->findContents(thisScope() + name);
-    if(!matches.empty())
-    {
-        ParamDeclPtr p = ParamDeclPtr::dynamicCast(matches.front());
-        if(p)
-        {
-            if(_unit->ignRedefs())
-            {
-                p->updateIncludeLevel();
-                return p;
-            }
-        }
-        if(matches.front()->name() != name)
-        {
-            string msg = "parameter `" + name + "' differs only in capitalization from ";
-            msg += "parameter `" + matches.front()->name() + "'";
-            _unit->error(msg);
-        }
-        else
-        {
-            string msg = "redefinition of parameter `" + name + "'";
-            _unit->error(msg);
-            return 0;
-        }
-    }
-
-    //
-    // Check whether enclosing operation has the same name.
-    //
-    if(name == this->name())
-    {
-        string msg = "operation name `";
-        msg += name;
-        msg += "' cannot be used as parameter name";
-        _unit->error(msg);
-        return 0;
-    }
-
-    string newName = IceUtilInternal::toLower(name);
-    string thisName = IceUtilInternal::toLower(this->name());
-    if(newName == thisName)
-    {
-        string msg = "parameter `" + name + "' differs only in capitalization from operation name `";
-        msg += this->name() + "'";
-        _unit->error(msg);
-    }
-
-    //
-    // Check that in parameters don't follow out parameters.
-    //
-    if(!_contents.empty())
-    {
-        ParamDeclPtr p = ParamDeclPtr::dynamicCast(_contents.back());
-        assert(p);
-        if(p->isOutParam() && !isOutParam)
-        {
-            _unit->error("`" + name + "': in parameters cannot follow out parameters");
-        }
-    }
-
-    //
-    // Non-local class/interface cannot have operation with local parameters.
-    //
-    ClassDefPtr cl = ClassDefPtr::dynamicCast(this->container());
-    assert(cl);
-    if(type->isLocal() && !cl->isLocal())
-    {
-        string msg = "non-local " + cl->kindOf() + " `" + cl->name() + "' cannot have local parameter `";
-        msg += name + "' in operation `" + this->name() + "'";
-        _unit->error(msg);
-    }
-
-    ParamDeclPtr p = new ParamDecl(this, name, type, isOutParam);
-    _contents.push_back(p);
-    return p;
+    return ParamDecl::createCommon(name, type, isOutParam, _contents, this, this, _unit, true);
 }
 
 ParamDeclList
@@ -4965,9 +4982,227 @@ Slice::Operation::Operation(const ContainerPtr& container,
 }
 
 // ----------------------------------------------------------------------
+// GeneratedOperation
+// ----------------------------------------------------------------------
+
+TypePtr
+Slice::GeneratedOperation::returnType() const
+{
+    return _returnType;
+}
+
+GeneratedOperation::Mode
+Slice::GeneratedOperation::mode() const
+{
+    return _mode;
+}
+
+ParamDeclPtr
+Slice::GeneratedOperation::createParamDecl(const string& name, const TypePtr& type, bool isOutParam)
+{
+    return ParamDecl::createCommon(name, type, isOutParam, _contents, this, this, _unit, false);
+}
+
+ParamDeclList
+Slice::GeneratedOperation::parameters() const
+{
+    ParamDeclList result;
+    for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p)
+    {
+        ParamDeclPtr q = ParamDeclPtr::dynamicCast(*p);
+        if(q)
+        {
+            result.push_back(q);
+        }
+    }
+    return result;
+}
+
+Contained::ContainedType
+Slice::GeneratedOperation::containedType() const
+{
+    return ContainedTypeGeneratedOperation;
+}
+
+bool
+Slice::GeneratedOperation::uses(const ContainedPtr& contained) const
+{
+    {
+        ContainedPtr contained2 = ContainedPtr::dynamicCast(_returnType);
+        if(contained2 && contained2 == contained)
+        {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+bool
+Slice::GeneratedOperation::isAbstract() const
+{
+    return _body.empty();
+}
+
+StringList
+Slice::GeneratedOperation::body() const
+{
+    return _body;
+}
+
+string
+Slice::GeneratedOperation::kindOf() const
+{
+    return "generated operation";
+}
+
+void
+Slice::GeneratedOperation::visit(ParserVisitor* visitor, bool)
+{
+    visitor->visitGeneratedOperation(this);
+}
+
+bool
+Slice::GeneratedOperation::isOverride() const
+{
+    return _override;
+}
+
+void
+Slice::GeneratedOperation::setOverride(bool override)
+{
+    _override = override;
+}
+
+Slice::GeneratedOperation::GeneratedOperation(const ContainerPtr& container,
+					      const string& name,
+					      const TypePtr& returnType,
+					      const StringList& body,
+                                              Mode mode) :
+    SyntaxTreeBase(container->unit()),
+    Contained(container, name),
+    Container(container->unit()),
+    _returnType(returnType),
+    _mode(mode),
+    _body(body),
+    _override(false)
+{
+}
+
+// ----------------------------------------------------------------------
 // ParamDecl
 // ----------------------------------------------------------------------
 
+ParamDeclPtr
+Slice::ParamDecl::createCommon(const string& name, const TypePtr& type, bool isOutParam,
+                               ContainedList& contents, const ContainerPtr& ctr, const ContainedPtr& cont,
+                               const UnitPtr& unit, bool restrictLocal)
+{
+    ctr->checkIdentifier(name);
+
+    if(unit->profile() == IceE)
+    {
+        ClassDefPtr cl = ClassDefPtr::dynamicCast(cont->container());
+        assert(cl);
+        if(!cl->isLocal())
+        {
+            BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
+            if((builtin && builtin->kind() == Builtin::KindObject))
+            {
+                string msg = "Object `" + name + "' cannot be passed by value.";
+                unit->error(msg);
+                return 0;
+            }
+            ClassDeclPtr classDecl =  ClassDeclPtr::dynamicCast(type);
+            if(classDecl != 0 && !classDecl->isLocal())
+            {
+                string msg = "Object `" + name + "' cannot be passed by value.";
+                unit->error(msg);
+                return 0;
+            }
+        }
+    }
+
+    ContainedList matches = unit->findContents(ctr->thisScope() + name);
+    if(!matches.empty())
+    {
+        ParamDeclPtr p = ParamDeclPtr::dynamicCast(matches.front());
+        if(p)
+        {
+            if(unit->ignRedefs())
+            {
+                p->updateIncludeLevel();
+                return p;
+            }
+        }
+        if(matches.front()->name() != name)
+        {
+            string msg = "parameter `" + name + "' differs only in capitalization from ";
+            msg += "parameter `" + matches.front()->name() + "'";
+            unit->error(msg);
+        }
+        else
+        {
+            string msg = "redefinition of parameter `" + name + "'";
+            unit->error(msg);
+            return 0;
+        }
+    }
+
+    //
+    // Check whether enclosing operation has the same name.
+    //
+    if(name == cont->name())
+    {
+        string msg = "operation name `";
+        msg += name;
+        msg += "' cannot be used as parameter name";
+        unit->error(msg);
+        return 0;
+    }
+
+    string newName = IceUtilInternal::toLower(name);
+    string thisName = IceUtilInternal::toLower(cont->name());
+    if(newName == thisName)
+    {
+        string msg = "parameter `" + name + "' differs only in capitalization from operation name `";
+        msg += cont->name() + "'";
+        unit->error(msg);
+    }
+
+    //
+    // Check that in parameters don't follow out parameters.
+    //
+    if(!contents.empty())
+    {
+        ParamDeclPtr p = ParamDeclPtr::dynamicCast(contents.back());
+        assert(p);
+        if(p->isOutParam() && !isOutParam)
+        {
+            unit->error("`" + name + "': in parameters cannot follow out parameters");
+        }
+    }
+
+    if(restrictLocal)
+    {
+        //
+        // Non-local class/interface cannot have operation with local parameters.
+        //
+        ClassDefPtr cl = ClassDefPtr::dynamicCast(cont->container());
+        assert(cl);
+        if(type->isLocal() && !cl->isLocal())
+        {
+            string msg = "non-local " + cl->kindOf() + " `" + cl->name() + "' cannot have local parameter `";
+            msg += name + "' in operation `" + cont->name() + "'";
+            unit->error(msg);
+        }
+    }
+
+    ParamDeclPtr p = new ParamDecl(ctr, name, type, isOutParam);
+    contents.push_back(p);
+    return p;
+}
+
 TypePtr
 Slice::ParamDecl::type() const
 {
diff --git a/cpp/src/Slice/PythonUtil.cpp b/cpp/src/Slice/PythonUtil.cpp
index 08c30f4..8cf0296 100644
--- a/cpp/src/Slice/PythonUtil.cpp
+++ b/cpp/src/Slice/PythonUtil.cpp
@@ -10,9 +10,11 @@
 #include <Slice/PythonUtil.h>
 #include <Slice/Checksum.h>
 #include <Slice/Util.h>
+#include <Slice/Plugin.h>
 #include <IceUtil/IceUtil.h>
 #include <IceUtil/StringUtil.h>
 #include <IceUtil/InputUtil.h>
+#include <IceUtil/DynamicLibrary.h>
 #include <climits>
 #include <iterator>
 
@@ -409,7 +411,9 @@ Slice::Python::CodeVisitor::visitClassDefStart(const ClassDefPtr& p)
     ClassList bases = p->bases();
     ClassDefPtr base;
     OperationList ops = p->operations();
-    OperationList::iterator oli;
+    OperationList::const_iterator oli;
+    GeneratedOperationList gops = p->generatedOperations();
+    GeneratedOperationList::const_iterator goli;
     bool isAbstract = p->isInterface() || p->allOperations().size() > 0; // Don't use isAbstract() - see bug 3739
 
     //
@@ -480,7 +484,7 @@ Slice::Python::CodeVisitor::visitClassDefStart(const ClassDefPtr& p)
         if(base)
         {
             _out << nl << getSymbol(base) << ".__init__(self";
-            for(MemberInfoList::iterator q = allMembers.begin(); q != allMembers.end(); ++q)
+            for(MemberInfoList::const_iterator q = allMembers.begin(); q != allMembers.end(); ++q)
             {
                 if(q->inherited)
                 {
@@ -489,7 +493,7 @@ Slice::Python::CodeVisitor::visitClassDefStart(const ClassDefPtr& p)
             }
             _out << ')';
         }
-        for(MemberInfoList::iterator q = allMembers.begin(); q != allMembers.end(); ++q)
+        for(MemberInfoList::const_iterator q = allMembers.begin(); q != allMembers.end(); ++q)
         {
             if(!q->inherited)
             {
@@ -526,7 +530,7 @@ Slice::Python::CodeVisitor::visitClassDefStart(const ClassDefPtr& p)
         _out << sp << nl << "def ice_ids(self, current=None):";
         _out.inc();
         _out << nl << "return (";
-        for(StringList::iterator q = ids.begin(); q != ids.end(); ++q)
+        for(StringList::const_iterator q = ids.begin(); q != ids.end(); ++q)
         {
             if(q != ids.begin())
             {
@@ -569,7 +573,7 @@ Slice::Python::CodeVisitor::visitClassDefStart(const ClassDefPtr& p)
 
                 ParamDeclList params = (*oli)->parameters();
 
-                for(ParamDeclList::iterator pli = params.begin(); pli != params.end(); ++pli)
+                for(ParamDeclList::const_iterator pli = params.begin(); pli != params.end(); ++pli)
                 {
                     if(!(*pli)->isOutParam())
                     {
@@ -596,7 +600,7 @@ Slice::Python::CodeVisitor::visitClassDefStart(const ClassDefPtr& p)
 
                 ParamDeclList params = (*oli)->parameters();
 
-                for(ParamDeclList::iterator pli = params.begin(); pli != params.end(); ++pli)
+                for(ParamDeclList::const_iterator pli = params.begin(); pli != params.end(); ++pli)
                 {
                     if(!(*pli)->isOutParam())
                     {
@@ -620,6 +624,48 @@ Slice::Python::CodeVisitor::visitClassDefStart(const ClassDefPtr& p)
         }
     }
 
+    if(!gops.empty())
+    {
+        //
+        // Emit each GeneratedOperation.
+        //
+        for(goli = gops.begin(); goli != gops.end(); ++goli)
+        {
+            string fixedOpName = fixIdent((*goli)->name());
+            _out << sp << nl << "def " << fixedOpName << "(self";
+
+            ParamDeclList params = (*goli)->parameters();
+
+            for(ParamDeclList::const_iterator pli = params.begin(); pli != params.end(); ++pli)
+            {
+                if(!(*pli)->isOutParam())
+                {
+                    _out << ", " << fixIdent((*pli)->name());
+                }
+            }
+            _out << "):";
+            _out.inc();
+            if((*goli)->isAbstract())
+            {
+                _out << nl << "pass";
+            }
+            else
+            {
+                StringList body = (*goli)->body();
+                for(StringList::const_iterator it = body.begin(); it != body.end(); it++)
+                {
+                    _out << nl << *it;
+                }
+            }
+            comment = (*goli)->comment();
+            if(!comment.empty())
+            {
+                _out << nl << "'''" << editComment(comment) << "'''";
+            }
+            _out.dec();
+        }
+    }
+
     //
     // __str__
     //
@@ -842,7 +888,7 @@ Slice::Python::CodeVisitor::visitClassDefStart(const ClassDefPtr& p)
         _out << nl;
     }
     bool isProtected = p->hasMetaData("protected");
-    for(DataMemberList::iterator r = members.begin(); r != members.end(); ++r)
+    for(DataMemberList::const_iterator r = members.begin(); r != members.end(); ++r)
     {
         if(r != members.begin())
         {
@@ -885,10 +931,10 @@ Slice::Python::CodeVisitor::visitClassDefStart(const ClassDefPtr& p)
         {
             _out << sp;
         }
-        for(OperationList::iterator s = ops.begin(); s != ops.end(); ++s)
+        for(OperationList::const_iterator s = ops.begin(); s != ops.end(); ++s)
         {
             ParamDeclList params = (*s)->parameters();
-            ParamDeclList::iterator t;
+            ParamDeclList::const_iterator t;
             int count;
 
             _out << nl << name << "._op_" << (*s)->name() << " = IcePy.Operation('" << (*s)->name() << "', "
@@ -949,7 +995,7 @@ Slice::Python::CodeVisitor::visitClassDefStart(const ClassDefPtr& p)
             }
             _out << ", (";
             ExceptionList exceptions = (*s)->throws();
-            for(ExceptionList::iterator u = exceptions.begin(); u != exceptions.end(); ++u)
+            for(ExceptionList::const_iterator u = exceptions.begin(); u != exceptions.end(); ++u)
             {
                 if(u != exceptions.begin())
                 {
@@ -2194,11 +2240,37 @@ Slice::Python::CodeVisitor::editComment(const string& comment)
 }
 
 void
-Slice::Python::generate(const UnitPtr& un, bool all, bool checksum, const vector<string>& includePaths, Output& out)
+Slice::Python::generate(const UnitPtr& un, bool all, bool checksum, const vector<string>& includePaths, Output& out,
+                        const vector<string>& plugins)
 {
     Slice::Python::MetaDataVisitor visitor;
     un->visit(&visitor, false);
 
+    for(vector<string>::const_iterator plugin = plugins.begin(); plugin != plugins.end(); plugin++)
+    {
+        IceUtil::DynamicLibraryPtr library = new IceUtil::DynamicLibrary();
+        IceUtil::DynamicLibrary::symbol_type sym = library->loadEntryPoint(*plugin, false);
+        if(sym == 0)
+        {
+            string msg = library->getErrorMessage();
+            cerr << "Unable to find " << *plugin << " = " << msg << endl;
+        }
+        
+        Plugin::VisitorList* pluginVisitors;
+        Plugin::FACTORY factory = (Plugin::FACTORY) sym;
+        pluginVisitors = factory(Plugin::LanguagePython);
+        
+        if(pluginVisitors)
+        {
+            for(Plugin::VisitorList::const_iterator it = pluginVisitors->begin(); it != pluginVisitors->end(); it++)
+            {
+                un->visit(*it, true);
+                delete *it;
+            }
+            delete pluginVisitors;
+        }
+    }
+
     out << nl << "import Ice, IcePy, __builtin__";
 
     if(!all)
diff --git a/cpp/src/slice2cpp/Gen.cpp b/cpp/src/slice2cpp/Gen.cpp
index 9442aea..21476de 100644
--- a/cpp/src/slice2cpp/Gen.cpp
+++ b/cpp/src/slice2cpp/Gen.cpp
@@ -8,6 +8,7 @@
 // **********************************************************************
 
 #include <IceUtil/DisableWarnings.h>
+#include <IceUtil/DynamicLibrary.h>
 #include <Gen.h>
 #include <Slice/Util.h>
 #include <Slice/CPlusPlusUtil.h>
@@ -15,6 +16,7 @@
 #include <IceUtil/Iterator.h>
 #include <Slice/Checksum.h>
 #include <Slice/FileTracker.h>
+#include <Slice/Plugin.h>
 
 #include <limits>
 
@@ -128,7 +130,7 @@ writeDataMemberInitializers(IceUtilInternal::Output& C, const DataMemberList& me
 Slice::Gen::Gen(const string& base, const string& headerExtension, const string& sourceExtension,
                 const vector<string>& extraHeaders, const string& include,
                 const vector<string>& includePaths, const string& dllExport, const string& dir,
-                bool imp, bool checksum, bool stream, bool ice) :
+                bool imp, bool checksum, bool stream, bool ice, const vector<string>& plugins) :
     _base(base),
     _headerExtension(headerExtension),
     _implHeaderExtension(headerExtension),
@@ -141,7 +143,8 @@ Slice::Gen::Gen(const string& base, const string& headerExtension, const string&
     _impl(imp),
     _checksum(checksum),
     _stream(stream),
-    _ice(ice)
+    _ice(ice),
+    _plugins(plugins)
 {
     for(vector<string>::iterator p = _includePaths.begin(); p != _includePaths.end(); ++p)
     {
@@ -171,6 +174,31 @@ void
 Slice::Gen::generate(const UnitPtr& p)
 {
     string file = p->topLevelFile();
+    
+    for(vector<string>::const_iterator plugin = _plugins.begin(); plugin != _plugins.end(); plugin++)
+    {
+        IceUtil::DynamicLibraryPtr library = new IceUtil::DynamicLibrary();
+        IceUtil::DynamicLibrary::symbol_type sym = library->loadEntryPoint(*plugin, false);
+        if(sym == 0)
+        {
+            string msg = library->getErrorMessage();
+            cerr << "Unable to find " << *plugin << " = " << msg << endl;
+        }
+        
+        Plugin::VisitorList* pluginVisitors;
+        Plugin::FACTORY factory = (Plugin::FACTORY) sym;
+        pluginVisitors = factory(Plugin::LanguageCPlusPlus);
+        
+        if(pluginVisitors)
+        {
+            for(Plugin::VisitorList::const_iterator it = pluginVisitors->begin(); it != pluginVisitors->end(); it++)
+            {
+                p->visit(*it, true);
+                delete *it;
+            }
+            delete pluginVisitors;
+        }
+    }
 
     //
     // Give precedence to header-ext global metadata.
@@ -4803,6 +4831,90 @@ Slice::Gen::ObjectVisitor::visitOperation(const OperationPtr& p)
     }
 }
 
+// This is just a cut-down version of visitOperation, since this only
+// has to support local operations (no proxies, no AMI/AMD, etc.)
+void
+Slice::Gen::ObjectVisitor::visitGeneratedOperation(const GeneratedOperationPtr& p)
+{
+    string name = p->name();
+    string scoped = fixKwd(p->scoped());
+    string scope = fixKwd(p->scope());
+
+    TypePtr ret = p->returnType();
+    string retS = returnTypeToString(ret, p->getMetaData(), _useWstring);
+
+    string params = "(";
+    string paramsDecl = "(";
+
+    ContainerPtr container = p->container();
+    ClassDefPtr cl = ClassDefPtr::dynamicCast(container);
+    string classScope = fixKwd(cl->scope());
+
+    ParamDeclList inParams;
+    ParamDeclList outParams;
+    ParamDeclList paramList = p->parameters();
+    for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q)
+    {
+        string paramName = fixKwd((*q)->name());
+        TypePtr type = (*q)->type();
+        bool isOutParam = (*q)->isOutParam();
+        string typeString;
+        if(isOutParam)
+        {
+            outParams.push_back(*q);
+            typeString = outputTypeToString(type, (*q)->getMetaData(), _useWstring);
+        }
+        else
+        {
+            inParams.push_back(*q);
+            typeString = inputTypeToString((*q)->type(), (*q)->getMetaData(), _useWstring);
+        }
+
+        if(q != paramList.begin())
+        {
+            params += ", ";
+	    paramsDecl += ", ";
+        }
+
+        params += typeString;
+        paramsDecl += typeString;
+        paramsDecl += ' ';
+        paramsDecl += paramName;
+    }
+
+    params += ')';
+    paramsDecl += ')';
+
+    bool isConst = (p->mode() == GeneratedOperation::Nonmutating);
+
+    string deprecateSymbol = getDeprecateSymbol(p, cl);
+
+    H << sp;
+    H << nl << deprecateSymbol << "virtual " << retS << ' ' << fixKwd(name) << params
+      << (isConst ? " const" : "");
+
+    if(!p->isAbstract())
+    {
+        // The operation has a body, so just leave the declaration as virtual
+        // and place the body in the code file.
+        H << ";";
+
+        StringList body = p->body();
+        C << nl << retS << nl << scoped << paramsDecl;
+        C << sb;
+        for(StringList::const_iterator it = body.begin(); it != body.end(); it++)
+        {
+            C << nl << *it;
+        }
+        C << eb;
+    }
+    else
+    {
+        // The operation is abstract, so mark it as 'pure virtual'.
+        H << " = 0;";
+    }
+}
+
 void
 Slice::Gen::ObjectVisitor::emitGCFunctions(const ClassDefPtr& p)
 {
diff --git a/cpp/src/slice2cpp/Gen.h b/cpp/src/slice2cpp/Gen.h
index b262fba..8b2cd0b 100644
--- a/cpp/src/slice2cpp/Gen.h
+++ b/cpp/src/slice2cpp/Gen.h
@@ -31,7 +31,8 @@ public:
         bool,
         bool,
         bool,
-        bool);
+        bool,
+        const std::vector<std::string>&);
     ~Gen();
 
     void generate(const UnitPtr&);
@@ -70,6 +71,7 @@ private:
     bool _checksum;
     bool _stream;
     bool _ice;
+    std::vector<std::string> _plugins;
 
     class TypesVisitor : private ::IceUtil::noncopyable, public ParserVisitor
     {
@@ -252,6 +254,7 @@ private:
         virtual bool visitExceptionStart(const ExceptionPtr&);
         virtual bool visitStructStart(const StructPtr&);
         virtual void visitOperation(const OperationPtr&);
+        virtual void visitGeneratedOperation(const GeneratedOperationPtr&);
 
     private:
 
diff --git a/cpp/src/slice2cpp/Main.cpp b/cpp/src/slice2cpp/Main.cpp
index 0ca754b..3381bfa 100644
--- a/cpp/src/slice2cpp/Main.cpp
+++ b/cpp/src/slice2cpp/Main.cpp
@@ -79,6 +79,7 @@ usage(const char* n)
         "--underscore             Permit underscores in Slice identifiers.\n"
         "--checksum               Generate checksums for Slice definitions.\n"
         "--stream                 Generate marshaling support for public stream API.\n"
+        "--plugin PATH            Load and apply plugin before generating output.\n"
         ;
 }
 
@@ -105,6 +106,7 @@ compile(int argc, char* argv[])
     opts.addOpt("", "underscore");
     opts.addOpt("", "checksum");
     opts.addOpt("", "stream");
+    opts.addOpt("", "plugin", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat);
 
     vector<string> args;
     try
@@ -156,6 +158,8 @@ compile(int argc, char* argv[])
 	cppArgs.push_back("-I" + Preprocessor::normalizeIncludePath(*i));
     }
 
+    vector<string> plugins = opts.argVec("plugin");
+
     bool preprocess = opts.isSet("E");
 
     string include = opts.optArg("include-dir");
@@ -275,7 +279,7 @@ compile(int argc, char* argv[])
                     try
                     {
                         Gen gen(icecpp->getBaseName(), headerExtension, sourceExtension, extraHeaders, include,
-                                includePaths, dllExport, output, impl, checksum, stream, ice);
+                                includePaths, dllExport, output, impl, checksum, stream, ice, plugins);
                         gen.generate(u);
                     }
                     catch(const Slice::FileException& ex)
diff --git a/cpp/src/slice2cs/Gen.cpp b/cpp/src/slice2cs/Gen.cpp
index 7a089e9..de88696 100644
--- a/cpp/src/slice2cs/Gen.cpp
+++ b/cpp/src/slice2cs/Gen.cpp
@@ -10,6 +10,7 @@
 #include <IceUtil/DisableWarnings.h>
 #include <IceUtil/Functional.h>
 #include <IceUtil/StringUtil.h>
+#include <IceUtil/DynamicLibrary.h>
 #include <Gen.h>
 #include <limits>
 #include <sys/stat.h>
@@ -24,6 +25,7 @@
 #include <Slice/DotNetNames.h>
 #include <Slice/FileTracker.h>
 #include <Slice/Util.h>
+#include <Slice/Plugin.h>
 #include <string.h>
 
 using namespace std;
@@ -982,6 +984,24 @@ Slice::CsVisitor::getParams(const OperationPtr& op)
 }
 
 vector<string>
+Slice::CsVisitor::getParams(const GeneratedOperationPtr& op)
+{
+    vector<string> params;
+    ParamDeclList paramList = op->parameters();
+    for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q)
+    {
+        string param = getParamAttributes(*q);
+        if((*q)->isOutParam())
+        {
+            param += "out ";
+        }
+        param += typeToString((*q)->type()) + " " + fixId((*q)->name());
+        params.push_back(param);
+    }
+    return params;
+}
+
+vector<string>
 Slice::CsVisitor::getParamsAsync(const OperationPtr& op, bool amd, bool newAMI)
 {
     vector<string> params;
@@ -1063,6 +1083,23 @@ Slice::CsVisitor::getArgs(const OperationPtr& op)
 }
 
 vector<string>
+Slice::CsVisitor::getArgs(const GeneratedOperationPtr& op)
+{
+    vector<string> args;
+    ParamDeclList paramList = op->parameters();
+    for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q)
+    {
+        string arg = fixId((*q)->name());
+        if((*q)->isOutParam())
+        {
+            arg = "out " + arg;
+        }
+        args.push_back(arg);
+    }
+    return args;
+}
+
+vector<string>
 Slice::CsVisitor::getArgsAsync(const OperationPtr& op, bool newAMI)
 {
     vector<string> args;
@@ -1849,9 +1886,10 @@ Slice::CsVisitor::writeDocCommentParam(const OperationPtr& p, ParamDir paramType
 }
 
 Slice::Gen::Gen(const string& base, const vector<string>& includePaths, const string& dir,
-                bool impl, bool implTie, bool stream)
+                bool impl, bool implTie, bool stream, const vector<string>& plugins)
     : _includePaths(includePaths),
-      _stream(stream)
+    _stream(stream),
+    _plugins(plugins)
 {
     string fileBase = base;
     string::size_type pos = base.find_last_of("/\\");
@@ -1924,6 +1962,31 @@ Slice::Gen::generate(const UnitPtr& p)
 {
     CsGenerator::validateMetaData(p);
 
+    for(vector<string>::const_iterator plugin = _plugins.begin(); plugin != _plugins.end(); plugin++)
+    {
+        IceUtil::DynamicLibraryPtr library = new IceUtil::DynamicLibrary();
+        IceUtil::DynamicLibrary::symbol_type sym = library->loadEntryPoint(*plugin, false);
+        if(sym == 0)
+        {
+            string msg = library->getErrorMessage();
+            cerr << "Unable to find " << *plugin << " = " << msg << endl;
+        }
+        
+        Plugin::VisitorList* pluginVisitors;
+        Plugin::FACTORY factory = (Plugin::FACTORY) sym;
+        pluginVisitors = factory(Plugin::LanguageCs);
+        
+        if(pluginVisitors)
+        {
+            for(Plugin::VisitorList::const_iterator it = pluginVisitors->begin(); it != pluginVisitors->end(); it++)
+            {
+                p->visit(*it, true);
+                delete *it;
+            }
+            delete pluginVisitors;
+        }
+    }
+
     UnitVisitor unitVisitor(_out);
     p->visit(&unitVisitor, false);
 
@@ -2275,7 +2338,7 @@ Slice::Gen::TypesVisitor::visitClassDefStart(const ClassDefPtr& p)
 
     if(!p->isInterface())
     {
-        if(p->hasDataMembers() && !p->hasOperations())
+        if(p->hasDataMembers() && !(p->hasOperations() || p->hasGeneratedOperations()))
         {
             _out << sp << nl << "#region Slice data members";
         }
@@ -2283,14 +2346,14 @@ Slice::Gen::TypesVisitor::visitClassDefStart(const ClassDefPtr& p)
         {
             _out << sp << nl << "#region Slice data members and operations";
         }
-        else if(p->hasOperations())
+        else if(p->hasOperations() || p->hasGeneratedOperations())
         {
             _out << sp << nl << "#region Slice operations";
         }
     }
     else
     {
-        if(p->isLocal() && p->hasOperations())
+        if(p->isLocal() && (p->hasOperations() || p->hasGeneratedOperations()))
         {
             _out << sp << nl << "#region Slice operations";
         }
@@ -2313,7 +2376,7 @@ Slice::Gen::TypesVisitor::visitClassDefEnd(const ClassDefPtr& p)
 
     if(!p->isInterface())
     {
-        if(p->hasDataMembers() && !p->hasOperations())
+        if(p->hasDataMembers() && !(p->hasOperations() || p->hasGeneratedOperations()))
         {
             _out << sp << nl << "#endregion"; // Slice data members"
         }
@@ -2321,7 +2384,7 @@ Slice::Gen::TypesVisitor::visitClassDefEnd(const ClassDefPtr& p)
         {
             _out << sp << nl << "#endregion"; // Slice data members and operations"
         }
-        else if(p->hasOperations())
+        else if(p->hasOperations() || p->hasGeneratedOperations())
         {
             _out << sp << nl << "#endregion"; // Slice operations"
         }
@@ -2382,7 +2445,7 @@ Slice::Gen::TypesVisitor::visitClassDefEnd(const ClassDefPtr& p)
     }
     else
     {
-        if(p->isLocal() && p->hasOperations())
+        if(p->isLocal() && (p->hasOperations() || p->hasGeneratedOperations()))
         {
             _out << sp << nl << "#endregion"; // Slice operations"
         }
@@ -2404,7 +2467,7 @@ Slice::Gen::TypesVisitor::visitOperation(const OperationPtr& p)
     bool isInterface = classDef->isInterface();
 
     //
-    // Non-local classes and interfaces get the operations from their
+    // Non-local interfaces get the operations from their
     // Operations base interfaces.
     //
     if(isInterface && !isLocal)
@@ -2522,6 +2585,72 @@ Slice::Gen::TypesVisitor::visitOperation(const OperationPtr& p)
 }
 
 void
+Slice::Gen::TypesVisitor::visitGeneratedOperation(const GeneratedOperationPtr& p)
+{
+    ClassDefPtr classDef = ClassDefPtr::dynamicCast(p->container());
+    bool isLocal = classDef->isLocal();
+    bool isInterface = classDef->isInterface();
+
+    //
+    // Non-local interfaces get the operations from their
+    // Operations base interfaces.
+    //
+    if(isInterface && !isLocal)
+    {
+        return;
+    }
+
+    string name = p->name();
+    ParamDeclList paramList = p->parameters();
+    vector<string> params;
+    vector<string> args;
+    string retS;
+
+    params = getParams(p);
+    args = getArgs(p);
+    name = fixId(name, DotNet::ICloneable, true);
+    retS = typeToString(p->returnType());
+
+    _out << sp;
+    if(isInterface && isLocal)
+    {
+        _out << nl;
+    }
+
+    writeDocComment(p, getDeprecateReason(p, classDef, "generatedOperation"));
+    emitAttributes(p);
+    emitGeneratedCodeAttribute();
+    _out << nl << "public ";
+    if(p->isAbstract())
+    {
+        _out << "abstract ";
+    }
+    else if(p->isOverride())
+    {
+        _out << "override ";
+    }
+    else
+    {
+        _out << "virtual ";
+    }
+    _out << retS << " " << name << spar << params << epar;
+    if(p->isAbstract())
+    {
+        _out << ";";
+    }
+    else
+    {
+        _out << sb;
+        StringList body = p->body();
+        for(StringList::const_iterator it = body.begin(); it != body.end(); it++)
+        {
+            _out << nl << *it;
+        }
+        _out << eb;
+    }
+}
+
+void
 Slice::Gen::TypesVisitor::visitSequence(const SequencePtr& p)
 {
     //
diff --git a/cpp/src/slice2cs/Gen.h b/cpp/src/slice2cs/Gen.h
index 7e30421..d4c98df 100644
--- a/cpp/src/slice2cs/Gen.h
+++ b/cpp/src/slice2cs/Gen.h
@@ -28,9 +28,11 @@ protected:
     virtual void writeInheritedOperations(const ClassDefPtr&);
     virtual void writeDispatchAndMarshalling(const ClassDefPtr&, bool);
     virtual std::vector<std::string> getParams(const OperationPtr&);
+    virtual std::vector<std::string> getParams(const GeneratedOperationPtr&);
     virtual std::vector<std::string> getParamsAsync(const OperationPtr&, bool, bool = false);
     virtual std::vector<std::string> getParamsAsyncCB(const OperationPtr&, bool = false, bool = true);
     virtual std::vector<std::string> getArgs(const OperationPtr&);
+    virtual std::vector<std::string> getArgs(const GeneratedOperationPtr&);
     virtual std::vector<std::string> getArgsAsync(const OperationPtr&, bool = false);
     virtual std::vector<std::string> getArgsAsyncCB(const OperationPtr&, bool = false, bool = false);
 
@@ -74,7 +76,8 @@ public:
         const std::string&,
         bool,
         bool,
-        bool);
+        bool,
+        const std::vector<std::string>&);
     ~Gen();
 
     void generate(const UnitPtr&);
@@ -93,6 +96,8 @@ private:
 
     bool _stream;
 
+    std::vector<std::string> _plugins;
+
     void printHeader();
 
     class UnitVisitor : public CsVisitor
@@ -114,6 +119,7 @@ private:
         virtual void visitModuleEnd(const ModulePtr&);
         virtual bool visitClassDefStart(const ClassDefPtr&);
         virtual void visitOperation(const OperationPtr&);
+        virtual void visitGeneratedOperation(const GeneratedOperationPtr&);
         virtual void visitClassDefEnd(const ClassDefPtr&);
         virtual bool visitExceptionStart(const ExceptionPtr&);
         virtual void visitExceptionEnd(const ExceptionPtr&);
diff --git a/cpp/src/slice2cs/Main.cpp b/cpp/src/slice2cs/Main.cpp
index 87ed3c6..b8be8ab 100644
--- a/cpp/src/slice2cs/Main.cpp
+++ b/cpp/src/slice2cs/Main.cpp
@@ -76,6 +76,7 @@ usage(const char* n)
         "--underscore            Permit underscores in Slice identifiers.\n"
         "--checksum              Generate checksums for Slice definitions.\n"
         "--stream                Generate marshaling support for public stream API.\n"
+        "--plugin PATH            Load and apply plugin before generating output.\n"
         ;
 }
 
@@ -99,6 +100,7 @@ compile(int argc, char* argv[])
     opts.addOpt("", "underscore");
     opts.addOpt("", "checksum");
     opts.addOpt("", "stream");
+    opts.addOpt("", "plugin", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat);
 
     vector<string> args;
     try
@@ -144,6 +146,8 @@ compile(int argc, char* argv[])
         cppArgs.push_back("-I" + Preprocessor::normalizeIncludePath(*i));
     }
 
+    vector<string> plugins = opts.argVec("plugin");
+
     bool preprocess = opts.isSet("E");
 
     string output = opts.optArg("output-dir");
@@ -268,7 +272,7 @@ compile(int argc, char* argv[])
                 {
                     try
                     {
-                        Gen gen(icecpp->getBaseName(), includePaths, output, impl, implTie, stream);
+                        Gen gen(icecpp->getBaseName(), includePaths, output, impl, implTie, stream, plugins);
                         gen.generate(p);
                         if(tie)
                         {
diff --git a/cpp/src/slice2java/Gen.cpp b/cpp/src/slice2java/Gen.cpp
index 2564f7e..3f49ed2 100644
--- a/cpp/src/slice2java/Gen.cpp
+++ b/cpp/src/slice2java/Gen.cpp
@@ -11,9 +11,11 @@
 #include <Gen.h>
 #include <Slice/Checksum.h>
 #include <Slice/Util.h>
+#include <Slice/Plugin.h>
 #include <IceUtil/Functional.h>
 #include <IceUtil/Iterator.h>
 #include <IceUtil/StringUtil.h>
+#include <IceUtil/DynamicLibrary.h>
 #include <cstring>
 
 #include <limits>
@@ -111,6 +113,27 @@ Slice::JavaVisitor::getParams(const OperationPtr& op, const string& package, boo
 }
 
 vector<string>
+Slice::JavaVisitor::getParams(const GeneratedOperationPtr& gop, const string& package, bool final)
+{
+    vector<string> params;
+
+    ParamDeclList paramList = gop->parameters();
+    for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q)
+    {
+        StringList metaData = (*q)->getMetaData();
+        string typeString = typeToString((*q)->type(), (*q)->isOutParam() ? TypeModeOut : TypeModeIn, package,
+                                         metaData);
+        if(final)
+        {
+            typeString = "final " + typeString;
+        }
+        params.push_back(typeString + ' ' + fixKwd((*q)->name()));
+    }
+
+    return params;
+}
+
+vector<string>
 Slice::JavaVisitor::getInOutParams(const OperationPtr& op, const string& package, ParamDir paramType)
 {
     vector<string> params;
@@ -1721,10 +1744,11 @@ Slice::JavaVisitor::writeDocCommentParam(Output& out, const OperationPtr& p, Par
     }
 }
 
-Slice::Gen::Gen(const string& name, const string& base, const vector<string>& includePaths, const string& dir) :
+Slice::Gen::Gen(const string& name, const string& base, const vector<string>& includePaths, const string& dir, const vector<string>& plugins) :
     _base(base),
     _includePaths(includePaths),
-    _dir(dir)
+    _dir(dir),
+    _plugins(plugins)
 {
 }
 
@@ -1735,6 +1759,31 @@ Slice::Gen::~Gen()
 void
 Slice::Gen::generate(const UnitPtr& p, bool stream)
 {
+    for(vector<string>::const_iterator plugin = _plugins.begin(); plugin != _plugins.end(); plugin++)
+    {
+        IceUtil::DynamicLibraryPtr library = new IceUtil::DynamicLibrary();
+        IceUtil::DynamicLibrary::symbol_type sym = library->loadEntryPoint(*plugin, false);
+        if(sym == 0)
+        {
+            string msg = library->getErrorMessage();
+            cerr << "Unable to find " << *plugin << " = " << msg << endl;
+        }
+        
+        Plugin::VisitorList* pluginVisitors;
+        Plugin::FACTORY factory = (Plugin::FACTORY) sym;
+        pluginVisitors = factory(Plugin::LanguageJava);
+        
+        if(pluginVisitors)
+        {
+            for(Plugin::VisitorList::const_iterator it = pluginVisitors->begin(); it != pluginVisitors->end(); it++)
+            {
+                p->visit(*it, true);
+                delete *it;
+            }
+            delete pluginVisitors;
+        }
+    }
+
     JavaGenerator::validateMetaData(p);
 
     OpsVisitor opsVisitor(_dir);
@@ -2447,6 +2496,37 @@ Slice::Gen::TypesVisitor::visitClassDefStart(const ClassDefPtr& p)
         }
     }
 
+    // Emit GeneratedOperations, which are always generated as local members
+    // even for abstract classes.
+    if(!p->isInterface())
+    {
+        GeneratedOperationList gops = p->generatedOperations();
+        for(GeneratedOperationList::const_iterator it = gops.begin(); it != gops.end(); it++)
+        {
+            GeneratedOperationPtr gop = *it;
+            string opname = gop->name();
+            TypePtr ret = gop->returnType();
+            string retS = typeToString(ret, TypeModeReturn, package, gop->getMetaData());
+            out << nl;
+            out << "public ";
+            if(gop->isAbstract())
+            {
+                out << "abstract ";
+            }
+            out << retS << ' ' << fixKwd(opname) << spar << getParams(gop, package) << epar;
+            if(!gop->isAbstract())
+            {
+                StringList body = gop->body();
+                out << sb;
+                for(StringList::const_iterator it = body.begin(); it != body.end(); it++)
+                {
+                    out << nl << *it;
+                }
+                out << eb;
+            }
+        }
+    }
+
     if(!p->isInterface() && !allDataMembers.empty())
     {
         //
diff --git a/cpp/src/slice2java/Gen.h b/cpp/src/slice2java/Gen.h
index 5e3f828..fab7fda 100644
--- a/cpp/src/slice2java/Gen.h
+++ b/cpp/src/slice2java/Gen.h
@@ -33,6 +33,7 @@ protected:
     // Compose the parameter lists for an operation.
     //
     std::vector<std::string> getParams(const OperationPtr&, const std::string&, bool = false);
+    std::vector<std::string> getParams(const GeneratedOperationPtr&, const std::string&, bool = false);
     std::vector<std::string> getInOutParams(const OperationPtr&, const std::string&, ParamDir);
     std::vector<std::string> getParamsAsync(const OperationPtr&, const std::string&, bool);
     std::vector<std::string> getParamsAsyncCB(const OperationPtr&, const std::string&);
@@ -99,7 +100,8 @@ public:
     Gen(const std::string&,
         const std::string&,
         const std::vector<std::string>&,
-        const std::string&);
+        const std::string&,
+        const std::vector<std::string>&);
     ~Gen();
 
     void generate(const UnitPtr&, bool);
@@ -114,6 +116,7 @@ private:
     std::string _base;
     std::vector<std::string> _includePaths;
     std::string _dir;
+    std::vector<std::string> _plugins;
 
     class OpsVisitor : public JavaVisitor
     {
diff --git a/cpp/src/slice2java/Main.cpp b/cpp/src/slice2java/Main.cpp
index 90978cf..281464d 100644
--- a/cpp/src/slice2java/Main.cpp
+++ b/cpp/src/slice2java/Main.cpp
@@ -80,6 +80,7 @@ usage(const char* n)
         "--checksum CLASS        Generate checksums for Slice definitions into CLASS.\n"
         "--stream                Generate marshaling support for public stream API.\n"
         "--meta META             Define global metadata directive META.\n"
+        "--plugin PATH            Load and apply plugin before generating output.\n"
         ;
 }
 
@@ -106,6 +107,7 @@ compile(int argc, char* argv[])
     opts.addOpt("", "checksum", IceUtilInternal::Options::NeedArg);
     opts.addOpt("", "stream");
     opts.addOpt("", "meta", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat);
+    opts.addOpt("", "plugin", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat);
 
     vector<string>args;
     try
@@ -151,6 +153,8 @@ compile(int argc, char* argv[])
         cppArgs.push_back("-I" + Preprocessor::normalizeIncludePath(*i));
     }
 
+    vector<string> plugins = opts.argVec("plugin");
+
     bool preprocess = opts.isSet("E");
 
     string output = opts.optArg("output-dir");
@@ -308,7 +312,7 @@ compile(int argc, char* argv[])
                 {
                     try
                     {
-                        Gen gen(argv[0], icecpp->getBaseName(), includePaths, output);
+                        Gen gen(argv[0], icecpp->getBaseName(), includePaths, output, plugins);
                         gen.generate(p, stream);
                         if(tie)
                         {
diff --git a/cpp/src/slice2py/Main.cpp b/cpp/src/slice2py/Main.cpp
index 0eed265..e31e8a8 100644
--- a/cpp/src/slice2py/Main.cpp
+++ b/cpp/src/slice2py/Main.cpp
@@ -378,6 +378,7 @@ usage(const char* n)
         "--all                Generate code for Slice definitions in included files.\n"
         "--checksum           Generate checksums for Slice definitions.\n"
         "--prefix PREFIX      Prepend filenames of Python modules with PREFIX.\n"
+        "--plugin PATH            Load and apply plugin before generating output.\n"
         ;
 }
 
@@ -400,6 +401,7 @@ compile(int argc, char* argv[])
     opts.addOpt("", "no-package");
     opts.addOpt("", "checksum");
     opts.addOpt("", "prefix", IceUtilInternal::Options::NeedArg);
+    opts.addOpt("", "plugin", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat);
 
     vector<string> args;
     try
@@ -445,6 +447,8 @@ compile(int argc, char* argv[])
         cppArgs.push_back("-I" + Preprocessor::normalizeIncludePath(*i));
     }
 
+    vector<string> plugins = opts.argVec("plugin");
+
     bool preprocess = opts.isSet("E");
 
     string output = opts.optArg("output-dir");
@@ -597,7 +601,7 @@ compile(int argc, char* argv[])
                         //
                         // Generate the Python mapping.
                         //
-                        generate(u, all, checksum, includePaths, out);
+                        generate(u, all, checksum, includePaths, out, plugins);
     
                         out.close();
 
diff --git a/py/modules/IcePy/Slice.cpp b/py/modules/IcePy/Slice.cpp
index b0d33be..ddeb3a4 100644
--- a/py/modules/IcePy/Slice.cpp
+++ b/py/modules/IcePy/Slice.cpp
@@ -71,6 +71,7 @@ IcePy_loadSlice(PyObject* /*self*/, PyObject* args)
     opts.addOpt("", "underscore");
     opts.addOpt("", "checksum");
     opts.addOpt("", "all");
+    opts.addOpt("", "plugin", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat);
 
     vector<string> files;
     try
@@ -129,6 +130,8 @@ IcePy_loadSlice(PyObject* /*self*/, PyObject* args)
     all = opts.isSet("all");
     checksum = opts.isSet("checksum");
 
+    vector<string> plugins = opts.argVec("plugin");
+
     bool ignoreRedefs = false;
     bool keepComments = true;
 
@@ -160,7 +163,7 @@ IcePy_loadSlice(PyObject* /*self*/, PyObject* args)
         ostringstream codeStream;
         IceUtilInternal::Output out(codeStream);
         out.setUseTab(false);
-        generate(u, all, checksum, includePaths, out);
+        generate(u, all, checksum, includePaths, out, plugins);
         u->destroy();
 
         string code = codeStream.str();

-----------------------------------------------------------------------


-- 
asterisk-scf/release/ice.git



More information about the asterisk-scf-commits mailing list