summaryrefslogtreecommitdiff
path: root/cpp/src/slice2matlab/Main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cpp/src/slice2matlab/Main.cpp')
-rw-r--r--cpp/src/slice2matlab/Main.cpp2993
1 files changed, 2993 insertions, 0 deletions
diff --git a/cpp/src/slice2matlab/Main.cpp b/cpp/src/slice2matlab/Main.cpp
new file mode 100644
index 00000000000..26ee9ae092c
--- /dev/null
+++ b/cpp/src/slice2matlab/Main.cpp
@@ -0,0 +1,2993 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2017 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+#include <IceUtil/DisableWarnings.h>
+#include <IceUtil/CtrlCHandler.h>
+#include <IceUtil/IceUtil.h>
+#include <IceUtil/InputUtil.h>
+#include <IceUtil/Options.h>
+#include <IceUtil/OutputUtil.h>
+#include <IceUtil/StringUtil.h>
+#include <IceUtil/Mutex.h>
+#include <IceUtil/MutexPtrLock.h>
+#include <IceUtil/ConsoleUtil.h>
+#include <IceUtil/FileUtil.h>
+#include <Slice/Checksum.h>
+#include <Slice/Preprocessor.h>
+#include <Slice/FileTracker.h>
+#include <Slice/Parser.h>
+#include <Slice/Util.h>
+#include <cstring>
+#include <climits>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef _WIN32
+# include <direct.h>
+#else
+# include <unistd.h>
+#endif
+
+using namespace std;
+using namespace Slice;
+using namespace IceUtilInternal;
+
+namespace
+{
+
+string
+lowerCase(const string& s)
+{
+ string result(s);
+ transform(result.begin(), result.end(), result.begin(), ::tolower);
+ return result;
+}
+
+string
+lookupKwd(const string& name)
+{
+ //
+ // Keyword list. *Must* be kept in alphabetical order.
+ //
+ static const string keywordList[] =
+ {
+ "break", "case", "catch", "classdef", "continue", "else", "elseif", "end", "for", "function", "global",
+ "if", "otherwise", "parfor", "persistent", "return", "spmd", "switch", "try", "while"
+ };
+ bool found = binary_search(&keywordList[0],
+ &keywordList[sizeof(keywordList) / sizeof(*keywordList)],
+ name);
+ return found ? "slice_" + name : name;
+}
+
+//
+// Split a scoped name into its components and return the components as a list of (unscoped) identifiers.
+//
+vector<string>
+splitScopedName(const string& scoped)
+{
+ assert(scoped[0] == ':');
+ vector<string> ids;
+ string::size_type next = 0;
+ string::size_type pos;
+ while((pos = scoped.find("::", next)) != string::npos)
+ {
+ pos += 2;
+ if(pos != scoped.size())
+ {
+ string::size_type endpos = scoped.find("::", pos);
+ if(endpos != string::npos)
+ {
+ ids.push_back(scoped.substr(pos, endpos - pos));
+ }
+ }
+ next = pos;
+ }
+ if(next != scoped.size())
+ {
+ ids.push_back(scoped.substr(next));
+ }
+ else
+ {
+ ids.push_back("");
+ }
+
+ return ids;
+}
+
+string
+fixIdent(const string& ident)
+{
+ if(ident[0] != ':')
+ {
+ return lookupKwd(ident);
+ }
+ vector<string> ids = splitScopedName(ident);
+ transform(ids.begin(), ids.end(), ids.begin(), ptr_fun(lookupKwd));
+ stringstream result;
+ for(vector<string>::const_iterator i = ids.begin(); i != ids.end(); ++i)
+ {
+ result << "::" + *i;
+ }
+ return result.str();
+}
+
+string
+replace(string s, string patt, string val)
+{
+ string r = s;
+ string::size_type pos = r.find(patt);
+ while(pos != string::npos)
+ {
+ r.replace(pos, patt.size(), val);
+ pos += val.size();
+ pos = r.find(patt, pos);
+ }
+ return r;
+}
+
+string
+scopedToName(const string& scoped)
+{
+ string str = scoped;
+ if(str.find("::") == 0)
+ {
+ str.erase(0, 2);
+ }
+
+ str = replace(str, "::", ".");
+
+ return fixIdent(str);
+}
+
+//
+// Get the fully-qualified name of the given definition. If a suffix is provided,
+// it is prepended to the definition's unqualified name. If the nameSuffix
+// is provided, it is appended to the container's name.
+//
+string
+getAbsolute(const ContainedPtr& cont, const string& pfx = std::string(), const string& suffix = std::string())
+{
+ return scopedToName(cont->scope() + pfx + cont->name() + suffix);
+}
+
+void
+printHeader(IceUtilInternal::Output& out)
+{
+ static const char* header =
+ "%{\n"
+ "**********************************************************************\n"
+ "\n"
+ "Copyright (c) 2003-2017 ZeroC, Inc. All rights reserved.\n"
+ "\n"
+ "This copy of Ice is licensed to you under the terms described in the\n"
+ "ICE_LICENSE file included in this distribution.\n"
+ "\n"
+ "**********************************************************************\n"
+ "%}\n"
+ ;
+
+ out << header;
+ out << "%\n";
+ out << "% Ice version " << ICE_STRING_VERSION << "\n";
+ out << "%\n";
+}
+
+string
+typeToString(const TypePtr& type)
+{
+ static const char* builtinTable[] =
+ {
+ "uint8",
+ "logical",
+ "int16",
+ "int32",
+ "int64",
+ "single",
+ "double",
+ "char",
+ "Ice.Object",
+ "Ice.ObjectPrx",
+ "",
+ "Ice.Value"
+ };
+
+ if(!type)
+ {
+ return "void";
+ }
+
+ BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
+ if(builtin)
+ {
+ return builtinTable[builtin->kind()];
+ }
+
+ ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
+ if(cl)
+ {
+ return getAbsolute(cl);
+ }
+
+ ProxyPtr proxy = ProxyPtr::dynamicCast(type);
+ if(proxy)
+ {
+ return getAbsolute(proxy->_class(), "", "Prx");
+ }
+
+ DictionaryPtr dict = DictionaryPtr::dynamicCast(type);
+ if(dict)
+ {
+ return "containers.Map";
+ }
+
+ SequencePtr seq = SequencePtr::dynamicCast(type);
+ if(seq)
+ {
+ return "???";
+ }
+
+ ContainedPtr contained = ContainedPtr::dynamicCast(type);
+ if(contained)
+ {
+ return getAbsolute(contained);
+ }
+
+ return "???";
+}
+
+string
+dictionaryTypeToString(const TypePtr& type, bool key)
+{
+ assert(type);
+
+ BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
+ if(builtin)
+ {
+ switch(builtin->kind())
+ {
+ case Builtin::KindBool:
+ case Builtin::KindByte:
+ case Builtin::KindShort:
+ {
+ //
+ // containers.Map supports a limited number of key types.
+ //
+ return key ? "int32" : typeToString(type);
+ }
+ case Builtin::KindInt:
+ case Builtin::KindLong:
+ case Builtin::KindString:
+ {
+ return typeToString(type);
+ }
+ case Builtin::KindFloat:
+ case Builtin::KindDouble:
+ {
+ assert(!key);
+ return typeToString(type);
+ }
+ case Builtin::KindObject:
+ case Builtin::KindObjectProxy:
+ case Builtin::KindLocalObject:
+ case Builtin::KindValue:
+ {
+ assert(!key);
+ return "any";
+ }
+ default:
+ {
+ return "???";
+ }
+ }
+ }
+
+ EnumPtr en = EnumPtr::dynamicCast(type);
+ if(en)
+ {
+ //
+ // containers.Map doesn't natively support enumerators as keys but we can work around it using int32.
+ //
+ return key ? "int32" : "any";
+ }
+
+ return "any";
+}
+
+bool
+declarePropertyType(const TypePtr& type, bool optional)
+{
+ return !optional && !SequencePtr::dynamicCast(type) && !ProxyPtr::dynamicCast(type) &&
+ !ClassDefPtr::dynamicCast(type);
+}
+
+string
+constantValue(const TypePtr& type, const SyntaxTreeBasePtr& valueType, const string& value)
+{
+ ConstPtr constant = ConstPtr::dynamicCast(valueType);
+ if(constant)
+ {
+ return getAbsolute(constant) + ".value";
+ }
+ else
+ {
+ BuiltinPtr bp;
+ if((bp = BuiltinPtr::dynamicCast(type)))
+ {
+ switch(bp->kind())
+ {
+ case Builtin::KindString:
+ {
+ return "sprintf('" + toStringLiteral(value, "\a\b\f\n\r\t\v", "", Matlab, 255) + "')";
+ }
+ case Builtin::KindBool:
+ case Builtin::KindByte:
+ case Builtin::KindShort:
+ case Builtin::KindInt:
+ case Builtin::KindLong:
+ case Builtin::KindFloat:
+ case Builtin::KindDouble:
+ case Builtin::KindObject:
+ case Builtin::KindObjectProxy:
+ case Builtin::KindLocalObject:
+ case Builtin::KindValue:
+ {
+ return value;
+ }
+
+ default:
+ {
+ return "???";
+ }
+ }
+
+ }
+ else if(EnumPtr::dynamicCast(type))
+ {
+ EnumeratorPtr e = EnumeratorPtr::dynamicCast(valueType);
+ assert(e);
+ return getAbsolute(e);
+ }
+ else
+ {
+ return value;
+ }
+ }
+}
+
+string
+defaultValue(const DataMemberPtr& m)
+{
+ if(m->defaultValueType())
+ {
+ return constantValue(m->type(), m->defaultValueType(), m->defaultValue());
+ }
+ else if(m->optional())
+ {
+ return "[]";
+ }
+ else
+ {
+ BuiltinPtr builtin = BuiltinPtr::dynamicCast(m->type());
+ if(builtin)
+ {
+ switch(builtin->kind())
+ {
+ case Builtin::KindString:
+ return "''";
+ case Builtin::KindBool:
+ return "false";
+ case Builtin::KindByte:
+ case Builtin::KindShort:
+ case Builtin::KindInt:
+ case Builtin::KindLong:
+ case Builtin::KindFloat:
+ case Builtin::KindDouble:
+ return "0";
+ case Builtin::KindObject:
+ case Builtin::KindObjectProxy:
+ case Builtin::KindLocalObject:
+ case Builtin::KindValue:
+ return "[]";
+ }
+ }
+
+ DictionaryPtr dict = DictionaryPtr::dynamicCast(m->type());
+ if(dict)
+ {
+ return "containers.Map('KeyType', '" + typeToString(dict->keyType()) + "', 'ValueType', '" +
+ typeToString(dict->valueType()) + "')";
+ }
+
+ return "[]";
+ }
+}
+
+}
+
+//
+// CodeVisitor generates the Matlab mapping for a translation unit.
+//
+class CodeVisitor : public ParserVisitor
+{
+public:
+
+ CodeVisitor(const string&);
+
+ virtual bool visitClassDefStart(const ClassDefPtr&);
+ virtual bool visitExceptionStart(const ExceptionPtr&);
+ virtual bool visitStructStart(const StructPtr&);
+ virtual void visitSequence(const SequencePtr&);
+ virtual void visitDictionary(const DictionaryPtr&);
+ virtual void visitEnum(const EnumPtr&);
+ virtual void visitConst(const ConstPtr&);
+
+private:
+
+ void openClass(const string&, IceUtilInternal::Output&);
+
+ struct MemberInfo
+ {
+ string fixedName;
+ bool inherited;
+ DataMemberPtr dataMember;
+ };
+ typedef list<MemberInfo> MemberInfoList;
+
+ //
+ // Convert an operation mode into a string.
+ //
+ string getOperationMode(Slice::Operation::Mode);
+
+ void collectClassMembers(const ClassDefPtr&, MemberInfoList&, bool);
+ void collectExceptionMembers(const ExceptionPtr&, MemberInfoList&, bool);
+
+ struct ParamInfo
+ {
+ string fixedName;
+ TypePtr type;
+ bool optional;
+ int tag;
+ ParamDeclPtr param; // 0 == return value
+ };
+ typedef list<ParamInfo> ParamInfoList;
+
+ ParamInfoList getInParams(const OperationPtr&);
+ ParamInfoList getOutParams(const OperationPtr&);
+
+ string getOptionalFormat(const TypePtr&);
+ string getFormatType(FormatType);
+
+ void marshal(IceUtilInternal::Output&, const string&, const string&, const TypePtr&, bool, int, int&);
+ void unmarshal(IceUtilInternal::Output&, const string&, const string&, const TypePtr&, bool, int, int&);
+
+ const string _dir;
+};
+
+//
+// CodeVisitor implementation.
+//
+CodeVisitor::CodeVisitor(const string& dir) :
+ _dir(dir)
+{
+}
+
+bool
+CodeVisitor::visitClassDefStart(const ClassDefPtr& p)
+{
+ const string name = fixIdent(p->name());
+ const string scoped = p->scoped();
+ const ClassList bases = p->bases();
+ const string self = name == "obj" ? "this" : "obj";
+
+ if(p->hasMetaData("matlab:internal"))
+ {
+ return false;
+ }
+
+ if(!p->isInterface())
+ {
+ ClassDefPtr base;
+ if(!bases.empty() && !bases.front()->isInterface())
+ {
+ base = bases.front();
+ }
+
+ IceUtilInternal::Output out;
+ openClass(scoped, out);
+
+ out << nl << "classdef " << name;
+ if(base)
+ {
+ out << " < " << getAbsolute(base);
+ }
+ else if(!p->isLocal())
+ {
+ out << " < Ice.Value";
+ }
+
+ const DataMemberList members = p->dataMembers();
+ if(!members.empty())
+ {
+ out.inc();
+ out << nl << "properties";
+ out.inc();
+ for(DataMemberList::const_iterator q = members.begin(); q != members.end(); ++q)
+ {
+ out << nl << fixIdent((*q)->name());
+ if(declarePropertyType((*q)->type(), (*q)->optional()))
+ {
+ out << " " << typeToString((*q)->type());
+ }
+ }
+ out.dec();
+ out << nl << "end";
+ }
+
+ MemberInfoList allMembers;
+ collectClassMembers(p, allMembers, false);
+
+ if(!allMembers.empty() || !p->isLocal())
+ {
+ out << nl << "methods";
+ out.inc();
+ }
+
+ if(!allMembers.empty())
+ {
+ vector<string> allNames;
+ for(MemberInfoList::const_iterator q = allMembers.begin(); q != allMembers.end(); ++q)
+ {
+ allNames.push_back(q->fixedName);
+ }
+ //
+ // Constructor
+ //
+ out << nl << "function " << self << " = " << name << spar << allNames << epar;
+ out.inc();
+ out << nl << "if nargin == 0";
+ out.inc();
+ for(MemberInfoList::const_iterator q = allMembers.begin(); q != allMembers.end(); ++q)
+ {
+ out << nl << q->fixedName << " = " << defaultValue(q->dataMember) << ';';
+ }
+ out.dec();
+ out << nl << "end";
+ if(base || !p->isLocal())
+ {
+ out << nl << self << " = " << self << "@" << (base ? getAbsolute(base) : "Ice.Value") << spar;
+ for(MemberInfoList::const_iterator q = allMembers.begin(); q != allMembers.end(); ++q)
+ {
+ if(q->inherited)
+ {
+ out << q->fixedName;
+ }
+ }
+ out << epar << ';';
+ }
+ for(MemberInfoList::const_iterator q = allMembers.begin(); q != allMembers.end(); ++q)
+ {
+ if(!q->inherited)
+ {
+ out << nl << self << "." << q->fixedName << " = " << q->fixedName << ';';
+ }
+ }
+ out.dec();
+ out << nl << "end";
+ }
+
+ if(!p->isLocal())
+ {
+ const DataMemberList optionalMembers = p->orderedOptionalDataMembers();
+
+ out << nl << "function id = ice_id(obj)";
+ out.inc();
+ out << nl << "id = obj.ice_staticId();";
+ out.dec();
+ out << nl << "end";
+ out << nl << "function iceWriteImpl_(obj, os)";
+ out.inc();
+ out << nl << "os.startSlice(obj.ice_staticId(), " << p->compactId() << (!base ? ", true" : ", false")
+ << ");";
+ for(DataMemberList::const_iterator d = members.begin(); d != members.end(); ++d)
+ {
+ if(!(*d)->optional())
+ {
+ int idx = 0;
+ marshal(out, "os", "obj." + fixIdent((*d)->name()), (*d)->type(), false, 0, idx);
+ }
+ }
+ for(DataMemberList::const_iterator d = optionalMembers.begin(); d != optionalMembers.end(); ++d)
+ {
+ int idx = 0;
+ marshal(out, "os", "obj." + fixIdent((*d)->name()), (*d)->type(), true, (*d)->tag(), idx);
+ }
+ out << nl << "os.endSlice();";
+ if(base)
+ {
+ out << nl << "iceWriteImpl_@" << getAbsolute(base) << "(obj);";
+ }
+ out.dec();
+ out << nl << "end";
+ out << nl << "function obj = iceReadImpl_(obj, is)";
+ out.inc();
+ out << nl << "is.startSlice();";
+ for(DataMemberList::const_iterator d = members.begin(); d != members.end(); ++d)
+ {
+ if(!(*d)->optional())
+ {
+ int idx = 0;
+ unmarshal(out, "is", "obj." + fixIdent((*d)->name()), (*d)->type(), false, 0, idx);
+ }
+ }
+ for(DataMemberList::const_iterator d = optionalMembers.begin(); d != optionalMembers.end(); ++d)
+ {
+ int idx = 0;
+ unmarshal(out, "is", "obj." + fixIdent((*d)->name()), (*d)->type(), true, (*d)->tag(), idx);
+ }
+ out << nl << "os.endSlice();";
+ if(base)
+ {
+ out << nl << "obj = iceReadImpl_@" << getAbsolute(base) << "(obj);";
+ }
+ out.dec();
+ out << nl << "end";
+ }
+
+ if(!allMembers.empty() || !p->isLocal())
+ {
+ out.dec();
+ out << nl << "end";
+ }
+
+ if(!p->isLocal())
+ {
+ out << nl << "methods(Static)";
+ out.inc();
+ out << nl << "function id = ice_staticId()";
+ out.inc();
+ out << nl << "id = '" << scoped << "';";
+ out.dec();
+ out << nl << "end";
+ out.dec();
+ out << nl << "end";
+ out.dec();
+ }
+
+ out.dec();
+ out << nl << "end";
+ out << nl;
+
+ out.close();
+ }
+ else if(!p->isLocal())
+ {
+ //
+ // Generate proxy class.
+ //
+
+ IceUtilInternal::Output out;
+ openClass(scoped + "Prx", out);
+
+ const string prxName = name + "Prx";
+ const string abs = getAbsolute(p, "", "Prx");
+
+ out << nl << "classdef " << prxName << " < ";
+ if(!bases.empty())
+ {
+ for(ClassList::const_iterator q = bases.begin(); q != bases.end(); ++q)
+ {
+ if(q != bases.begin())
+ {
+ out << " & ";
+ }
+ out << getAbsolute(*q, "", "Prx");
+ }
+ }
+ else
+ {
+ out << "Ice.ObjectPrx";
+ }
+
+ out.inc();
+
+ out << nl << "methods";
+ out.inc();
+
+ //
+ // Constructor.
+ //
+ out << nl << "function obj = " << prxName << "(impl)";
+ out.inc();
+ if(!bases.empty())
+ {
+ for(ClassList::const_iterator q = bases.begin(); q != bases.end(); ++q)
+ {
+ out << nl << "obj = obj@" << getAbsolute(*q, "", "Prx") << "(impl);";
+ }
+ }
+ else
+ {
+ out << nl << "obj = obj@Ice.ObjectPrx(impl);";
+ }
+ out.dec();
+ out << nl << "end";
+
+ //
+ // Operations.
+ //
+ const OperationList ops = p->operations();
+ for(OperationList::const_iterator q = ops.begin(); q != ops.end(); ++q)
+ {
+ OperationPtr op = *q;
+ const ParamInfoList inParams = getInParams(op);
+ const ParamInfoList outParams = getOutParams(op);
+ const bool twowayOnly = !outParams.empty();
+
+ ExceptionList exceptions = op->throws();
+ exceptions.sort();
+ exceptions.unique();
+
+ //
+ // Arrange exceptions into most-derived to least-derived order. If we don't
+ // do this, a base exception handler can appear before a derived exception
+ // handler, causing compiler warnings and resulting in the base exception
+ // being marshaled instead of the derived exception.
+ //
+#if defined(__SUNPRO_CC)
+ exceptions.sort(Slice::derivedToBaseCompare);
+#else
+ exceptions.sort(Slice::DerivedToBaseCompare());
+#endif
+
+ //
+ // Ensure no parameter is named "obj".
+ //
+ string self = "obj";
+ for(ParamInfoList::const_iterator r = outParams.begin(); r != outParams.end(); ++r)
+ {
+ if(r->fixedName == "obj")
+ {
+ self = "obj_";
+ }
+ }
+ for(ParamInfoList::const_iterator r = inParams.begin(); r != inParams.end(); ++r)
+ {
+ if(r->fixedName == "obj")
+ {
+ self = "obj_";
+ }
+ }
+
+ //
+ // Synchronous method.
+ //
+ out << nl << "function ";
+ if(outParams.size() > 1)
+ {
+ out << "[";
+ for(ParamInfoList::const_iterator r = outParams.begin(); r != outParams.end(); ++r)
+ {
+ if(r != outParams.begin())
+ {
+ out << ", ";
+ }
+ out << r->fixedName;
+ }
+ out << "] = ";
+ }
+ else if(outParams.size() == 1)
+ {
+ out << outParams.begin()->fixedName << " = ";
+ }
+ out << fixIdent(op->name()) << spar;
+
+ out << self;
+ for(ParamInfoList::const_iterator r = inParams.begin(); r != inParams.end(); ++r)
+ {
+ out << r->fixedName;
+ }
+ out << "varargin"; // For the optional context
+ out << epar;
+ out.inc();
+
+ if(!inParams.empty())
+ {
+ if(op->format() == DefaultFormat)
+ {
+ out << nl << "os_ = " << self << ".startWriteParams_();";
+ }
+ else
+ {
+ out << nl << "os_ = " << self << ".startWriteParamsWithFormat_(" << getFormatType(op->format())
+ << ");";
+ }
+ for(ParamInfoList::const_iterator r = inParams.begin(); r != inParams.end(); ++r)
+ {
+ int idx = 0;
+ marshal(out, "os_", r->fixedName, r->type, r->optional, r->tag, idx);
+ }
+ out << nl << self << ".endWriteParams_(os_);";
+ }
+
+ out << nl << "[ok_, is_] = " << self << ".invoke_('" << op->name() << "', '"
+ << getOperationMode(op->sendMode()) << "', " << (twowayOnly ? "true" : "false")
+ << ", " << (inParams.empty() ? "[]" : "os_") << ", varargin{:});";
+
+ if(outParams.empty() && exceptions.empty())
+ {
+ out << nl << self << ".checkNoResponse_(ok_, is_);";
+ }
+ else
+ {
+ out << nl << "if ok_";
+ out.inc();
+ if(outParams.empty())
+ {
+ out << nl << "is_.skipEmptyEncapsulation();";
+ }
+ else
+ {
+ out << nl << "is_.startEncapsulation();";
+ //
+ // The return value (if any) appears first. We have to unmarshal any out parameters
+ // before the return value.
+ //
+ for(ParamInfoList::const_iterator r = outParams.begin(); r != outParams.end(); ++r)
+ {
+ if(r->param)
+ {
+ int idx = 0;
+ unmarshal(out, "is_", r->fixedName, r->type, r->optional, r->tag, idx);
+ }
+ }
+ //
+ // Now do the return value if necessary.
+ //
+ if(!outParams.begin()->param)
+ {
+ ParamInfoList::const_iterator r = outParams.begin();
+ int idx = 0;
+ unmarshal(out, "is_", r->fixedName, r->type, r->optional, r->tag, idx);
+ }
+ out << nl << "is_.endEncapsulation();";
+ }
+ out.dec();
+ out << nl << "else";
+ out.inc();
+ out << nl << self << ".throwUserException_" << spar << "is_";
+ for(ExceptionList::const_iterator e = exceptions.begin(); e != exceptions.end(); ++e)
+ {
+ out << "'" + getAbsolute(*e) + "'";
+ }
+ out << epar << ';';
+ out.dec();
+ out << nl << "end";
+ }
+
+ out.dec();
+ out << nl << "end";
+
+ //
+ // Asynchronous method.
+ //
+ out << nl << "function r_ = " << fixIdent(op->name()) << "Async" << spar;
+ out << self;
+ for(ParamInfoList::const_iterator r = inParams.begin(); r != inParams.end(); ++r)
+ {
+ out << r->fixedName;
+ }
+ out << "varargin"; // For the optional context
+ out << epar;
+ out.inc();
+
+ if(!inParams.empty())
+ {
+ if(op->format() == DefaultFormat)
+ {
+ out << nl << "os_ = " << self << ".startWriteParams_();";
+ }
+ else
+ {
+ out << nl << "os_ = " << self << ".startWriteParamsWithFormat_(" << getFormatType(op->format())
+ << ");";
+ }
+ for(ParamInfoList::const_iterator r = inParams.begin(); r != inParams.end(); ++r)
+ {
+ int idx = 0;
+ marshal(out, "os_", r->fixedName, r->type, r->optional, r->tag, idx);
+ }
+ out << nl << self << ".endWriteParams_(os_);";
+ }
+
+ if(!outParams.empty() || !exceptions.empty())
+ {
+ out << nl << "function varargout = unmarshal(ok_, is_)";
+ out.inc();
+ out << nl << "if ok_";
+ out.inc();
+ if(outParams.empty())
+ {
+ out << nl << "is_.skipEmptyEncapsulation();";
+ }
+ else
+ {
+ out << nl << "is_.startEncapsulation();";
+ int pos = op->returnType() ? 2 : 1;
+ //
+ // The return value (if any) appears first. We have to unmarshal any out parameters
+ // before the return value.
+ //
+ for(ParamInfoList::const_iterator r = outParams.begin(); r != outParams.end(); ++r)
+ {
+ if(r->param)
+ {
+ int idx = 0;
+ unmarshal(out, "is_", r->fixedName, r->type, r->optional, r->tag, idx);
+ out << nl << "varargout{" << pos++ << "} = " << r->fixedName << ';';
+ }
+ }
+ //
+ // Now do the return value if necessary.
+ //
+ if(!outParams.begin()->param)
+ {
+ ParamInfoList::const_iterator r = outParams.begin();
+ int idx = 0;
+ unmarshal(out, "is_", r->fixedName, r->type, r->optional, r->tag, idx);
+ out << nl << "varargout{1} = " << r->fixedName << ';';
+ }
+ out << nl << "is_.endEncapsulation();";
+ }
+ out.dec();
+ out << nl << "else";
+ out.inc();
+ out << nl << self << ".throwUserException_" << spar << "is_";
+ for(ExceptionList::const_iterator e = exceptions.begin(); e != exceptions.end(); ++e)
+ {
+ out << "'" + getAbsolute(*e) + "'";
+ }
+ out << epar << ';';
+ out.dec();
+ out << nl << "end";
+ out.dec();
+ out << nl << "end";
+ }
+
+ out << nl << "r_ = " << self << ".invokeAsync_('" << op->name() << "', '"
+ << getOperationMode(op->sendMode()) << "', " << (twowayOnly ? "true" : "false") << ", "
+ << (inParams.empty() ? "[]" : "os_") << ", " << outParams.size() << ", ";
+ if(!outParams.empty() || !exceptions.empty())
+ {
+ out << "@unmarshal";
+ }
+ else
+ {
+ out << "[]";
+ }
+ out << ", varargin{:});";
+
+ out.dec();
+ out << nl << "end";
+ }
+
+ out.dec();
+ out << nl << "end";
+
+ out << nl << "methods(Static)";
+ out.inc();
+ out << nl << "function id = ice_staticId()";
+ out.inc();
+ out << nl << "id = '" << scoped << "';";
+ out.dec();
+ out << nl << "end";
+ out << nl << "function r = ice_read(is_)";
+ out.inc();
+ out << nl << "r = Ice.ObjectPrx.read_(is_, '" << abs << "');";
+ out.dec();
+ out << nl << "end";
+ out << nl << "function r = checkedCast(p, varargin)";
+ out.inc();
+ out << nl << "r = Ice.ObjectPrx.checkedCast_(p, " << abs << ".ice_staticId(), '" << abs << "', varargin{:});";
+ out.dec();
+ out << nl << "end";
+ out << nl << "function r = uncheckedCast(p, varargin)";
+ out.inc();
+ out << nl << "r = Ice.ObjectPrx.uncheckedCast_(p, '" << abs << "', varargin{:});";
+ out.dec();
+ out << nl << "end";
+ out.dec();
+ out << nl << "end";
+
+ out.dec();
+ out << nl << "end";
+ out << nl;
+
+ out.close();
+ }
+ else
+ {
+ //
+ // Generate local abstract class.
+ //
+
+ IceUtilInternal::Output out;
+ openClass(scoped, out);
+
+ out << nl << "classdef (Abstract) " << name;
+ if(!bases.empty())
+ {
+ out << " < ";
+ for(ClassList::const_iterator q = bases.begin(); q != bases.end(); ++q)
+ {
+ if(q != bases.begin())
+ {
+ out << " & ";
+ }
+ out << " < " << getAbsolute(*q);
+ }
+ }
+
+ const OperationList ops = p->operations();
+ if(!ops.empty())
+ {
+ out.inc();
+ out << nl << "methods(Abstract)";
+ out.inc();
+ for(OperationList::const_iterator q = ops.begin(); q != ops.end(); ++q)
+ {
+ OperationPtr op = *q;
+ const ParamInfoList outParams = getOutParams(op);
+ out << nl;
+ if(outParams.size() > 1)
+ {
+ out << "[";
+ for(ParamInfoList::const_iterator r = outParams.begin(); r != outParams.end(); ++r)
+ {
+ if(r != outParams.begin())
+ {
+ out << ", ";
+ }
+ out << r->fixedName;
+ }
+ out << "] = ";
+ }
+ else if(outParams.size() == 1)
+ {
+ out << outParams.begin()->fixedName << " = ";
+ }
+ out << fixIdent(op->name()) << spar;
+ string self = "obj";
+ const ParamInfoList inParams = getInParams(op);
+ for(ParamInfoList::const_iterator r = outParams.begin(); r != outParams.end(); ++r)
+ {
+ if(r->fixedName == "obj")
+ {
+ self = "obj_";
+ }
+ }
+ for(ParamInfoList::const_iterator r = inParams.begin(); r != inParams.end(); ++r)
+ {
+ if(r->fixedName == "obj")
+ {
+ self = "obj_";
+ }
+ }
+ out << self;
+ for(ParamInfoList::const_iterator r = inParams.begin(); r != inParams.end(); ++r)
+ {
+ out << r->fixedName;
+ }
+ out << epar;
+ }
+ out.dec();
+ out << nl << "end";
+ out.dec();
+ }
+
+ out << nl << "end";
+ out << nl;
+
+ out.close();
+ }
+
+ return false;
+}
+
+bool
+CodeVisitor::visitExceptionStart(const ExceptionPtr& p)
+{
+ const string name = fixIdent(p->name());
+ const string scoped = p->scoped();
+
+ IceUtilInternal::Output out;
+ openClass(scoped, out);
+
+ ExceptionPtr base = p->base();
+
+ out << nl << "classdef " << name;
+ if(base)
+ {
+ out << " < " << getAbsolute(base);
+ }
+ else if(p->isLocal())
+ {
+ out << " < Ice.LocalException";
+ }
+ else
+ {
+ out << " < Ice.UserException";
+ }
+
+ const DataMemberList members = p->dataMembers();
+ if(!members.empty())
+ {
+ out.inc();
+ out << nl << "properties";
+ out.inc();
+ for(DataMemberList::const_iterator q = members.begin(); q != members.end(); ++q)
+ {
+ out << nl << fixIdent((*q)->name());
+ if(declarePropertyType((*q)->type(), (*q)->optional()))
+ {
+ out << " " << typeToString((*q)->type());
+ }
+ }
+ out.dec();
+ out << nl << "end";
+ }
+
+ MemberInfoList allMembers;
+ collectExceptionMembers(p, allMembers, false);
+
+ vector<string> allNames;
+ for(MemberInfoList::const_iterator q = allMembers.begin(); q != allMembers.end(); ++q)
+ {
+ allNames.push_back(q->fixedName);
+ }
+ out << nl << "methods";
+ out.inc();
+
+ const string self = name == "obj" ? "this" : "obj";
+
+ //
+ // Constructor
+ //
+ out << nl << "function " << self << " = " << name << spar << "ice_exid" << "ice_exmsg" << allNames << epar;
+ out.inc();
+ string exid = getAbsolute(p);
+ const string exmsg = getAbsolute(p); // TODO: Allow a message to be specified via metadata?
+ //
+ // The ID argument must use colon separators.
+ //
+ string::size_type pos = exid.find('.');
+ assert(pos != string::npos);
+ while(pos != string::npos)
+ {
+ exid[pos] = ':';
+ pos = exid.find('.', pos);
+ }
+
+ if(!allMembers.empty())
+ {
+ out << nl << "if nargin <= 2";
+ out.inc();
+ for(MemberInfoList::const_iterator q = allMembers.begin(); q != allMembers.end(); ++q)
+ {
+ out << nl << q->fixedName << " = " << defaultValue(q->dataMember) << ';';
+ }
+ out.dec();
+ out << nl << "end";
+ }
+
+ out << nl << "if nargin == 0 || isempty(ice_exid)";
+ out.inc();
+ out << nl << "ice_exid = '" << exid << "';";
+ out.dec();
+ out << nl << "end";
+
+ out << nl << "if nargin < 2 || isempty(ice_exmsg)";
+ out.inc();
+ out << nl << "ice_exmsg = '" << exmsg << "';";
+ out.dec();
+ out << nl << "end";
+
+ if(!base)
+ {
+ out << nl << self << " = " << self << "@" << (p->isLocal() ? "Ice.LocalException" : "Ice.UserException")
+ << spar << "ice_exid" << "ice_exmsg" << epar << ';';
+ }
+ else
+ {
+ out << nl << self << " = " << self << "@" << getAbsolute(base) << spar << "ice_exid" << "ice_exmsg";
+ for(MemberInfoList::const_iterator q = allMembers.begin(); q != allMembers.end(); ++q)
+ {
+ if(q->inherited)
+ {
+ out << q->fixedName;
+ }
+ }
+ out << epar << ';';
+ }
+ for(MemberInfoList::const_iterator q = allMembers.begin(); q != allMembers.end(); ++q)
+ {
+ if(!q->inherited)
+ {
+ out << nl << self << "." << q->fixedName << " = " << q->fixedName << ';';
+ }
+ }
+ out.dec();
+ out << nl << "end";
+
+ out << nl << "function id = ice_id(obj)";
+ out.inc();
+ out << nl << "id = '" << scoped << "';";
+ out.dec();
+ out << nl << "end";
+
+ out << nl << "function obj = readImpl_(obj, is_)";
+ out.inc();
+ out << nl << "is_.startSlice();";
+ for(DataMemberList::const_iterator q = members.begin(); q != members.end(); ++q)
+ {
+ int idx = 0;
+ unmarshal(out, "is_", "obj." + fixIdent((*q)->name()), (*q)->type(), false, 0, idx);
+ }
+ out << nl << "is_.endSlice();";
+ if(base)
+ {
+ out << nl << "obj = readImpl_@" << getAbsolute(base) << "(obj);";
+ }
+ out.dec();
+ out << nl << "end";
+
+ if(p->usesClasses(false))
+ {
+ if(!base || (base && !base->usesClasses(false)))
+ {
+ out << nl << "function r = usesClasses_(obj)";
+ out.inc();
+ out << nl << "r = true;";
+ out.dec();
+ out << nl << "end";
+ }
+ }
+
+ out.dec();
+ out << nl << "end";
+
+ out.dec();
+ out << nl << "end";
+ out << nl;
+
+ out.close();
+
+ return false;
+}
+
+bool
+CodeVisitor::visitStructStart(const StructPtr& p)
+{
+ const string name = fixIdent(p->name());
+ const string scoped = p->scoped();
+ const string abs = getAbsolute(p);
+
+ IceUtilInternal::Output out;
+ openClass(scoped, out);
+
+ out << nl << "classdef " << name;
+
+ const DataMemberList members = p->dataMembers();
+ out.inc();
+ out << nl << "properties";
+ out.inc();
+ vector<string> memberNames;
+ for(DataMemberList::const_iterator q = members.begin(); q != members.end(); ++q)
+ {
+ const string m = fixIdent((*q)->name());
+ memberNames.push_back(m);
+ out << nl << m;
+ if(declarePropertyType((*q)->type(), false))
+ {
+ out << " " << typeToString((*q)->type());
+ }
+ }
+ out.dec();
+ out << nl << "end";
+
+ out << nl << "methods";
+ out.inc();
+ string self = name == "obj" ? "this" : "obj";
+ out << nl << "function " << self << " = " << name << spar << memberNames << epar;
+ out.inc();
+ out << nl << "if nargin > 0";
+ out.inc();
+ for(vector<string>::const_iterator q = memberNames.begin(); q != memberNames.end(); ++q)
+ {
+ out << nl << self << "." << *q << " = " << *q << ';';
+ }
+ out.dec();
+ out << nl << "else";
+ out.inc();
+ for(DataMemberList::const_iterator q = members.begin(); q != members.end(); ++q)
+ {
+ out << nl << self << "." << fixIdent((*q)->name()) << " = " << defaultValue(*q) << ';';
+ }
+ out.dec();
+ out << nl << "end";
+ out.dec();
+ out << nl << "end";
+
+ out.dec();
+ out << nl << "end";
+
+ if(!p->isLocal())
+ {
+ out << nl << "methods(Static)";
+ out.inc();
+ out << nl << "function r = ice_read(is_)";
+ out.inc();
+ out << nl << "r = " << abs << "();";
+ for(DataMemberList::const_iterator q = members.begin(); q != members.end(); ++q)
+ {
+ int idx = 0;
+ unmarshal(out, "is_", "r." + fixIdent((*q)->name()), (*q)->type(), false, 0, idx);
+ }
+ out.dec();
+ out << nl << "end";
+ out << nl << "function ice_write(os_, v_)";
+ out.inc();
+ out << nl << "if isempty(v_)";
+ out.inc();
+ out << nl << "v_ = " << abs << "();";
+ out.dec();
+ out << nl << "end";
+ for(DataMemberList::const_iterator q = members.begin(); q != members.end(); ++q)
+ {
+ int idx = 0;
+ marshal(out, "os_", "v_." + fixIdent((*q)->name()), (*q)->type(), false, 0, idx);
+ }
+ out.dec();
+ out << nl << "end";
+ out.dec();
+ out << nl << "end";
+ }
+
+ out.dec();
+ out << nl << "end";
+ out << nl;
+
+ out.close();
+
+ return false;
+}
+
+void
+CodeVisitor::visitSequence(const SequencePtr& p)
+{
+ if(p->isLocal())
+ {
+ return;
+ }
+
+ const TypePtr content = p->type();
+
+ const BuiltinPtr bp = BuiltinPtr::dynamicCast(content);
+ if(bp)
+ {
+ switch(bp->kind())
+ {
+ case Builtin::KindBool:
+ case Builtin::KindByte:
+ case Builtin::KindShort:
+ case Builtin::KindInt:
+ case Builtin::KindLong:
+ case Builtin::KindFloat:
+ case Builtin::KindDouble:
+ case Builtin::KindString:
+ {
+ return;
+ }
+ case Builtin::KindObject:
+ case Builtin::KindObjectProxy:
+ case Builtin::KindValue:
+ {
+ break;
+ }
+ case Builtin::KindLocalObject:
+ {
+ assert(false);
+ }
+ }
+ }
+
+ const string name = fixIdent(p->name());
+ const string scoped = p->scoped();
+
+ IceUtilInternal::Output out;
+ openClass(scoped, out);
+
+ out << nl << "classdef " << name;
+ out.inc();
+ out << nl << "methods(Static)";
+ out.inc();
+
+ out << nl << "function write(os, seq)";
+ out.inc();
+ out << nl << "sz = length(seq);";
+ out << nl << "os.writeSize(sz);";
+ out << nl << "for i = 1:sz";
+ out.inc();
+ int idx = 0;
+ marshal(out, "os", "seq{i}", content, false, 0, idx);
+ out.dec();
+ out << nl << "end";
+ out.dec();
+ out << nl << "end";
+
+ out << nl << "function r = read(is)";
+ out.inc();
+ out << nl << "sz = is.readSize();";
+ out << nl << "r = {};";
+ out << nl << "for i = 1:sz";
+ out.inc();
+ idx = 0;
+ unmarshal(out, "is", "r{i}", content, false, 0, idx);
+ out.dec();
+ out << nl << "end";
+
+ out.dec();
+ out << nl << "end";
+ out.dec();
+ out << nl << "end";
+ out.dec();
+ out << nl << "end";
+ out << nl;
+
+ out.close();
+}
+
+void
+CodeVisitor::visitDictionary(const DictionaryPtr& p)
+{
+ const TypePtr key = p->keyType();
+ const TypePtr value = p->valueType();
+
+ const StructPtr st = StructPtr::dynamicCast(key);
+
+ const string name = fixIdent(p->name());
+ const string scoped = p->scoped();
+ const string abs = getAbsolute(p);
+ const string self = name == "obj" ? "this" : "obj";
+
+ IceUtilInternal::Output out;
+ openClass(scoped, out);
+
+ out << nl << "classdef " << name;
+ out.inc();
+ out << nl << "methods(Access=private)";
+ out.inc();
+ //
+ // Declare a private constructor so that programs can't instantiate this type. They need to use new().
+ //
+ out << nl << "function " << self << " = " << name << "()";
+ out.inc();
+ out << nl << "% Use new()";
+ out.dec();
+ out << nl << "end";
+ out.dec();
+ out << nl << "end";
+ out << nl << "methods(Static)";
+ out.inc();
+ out << nl << "function r = new()";
+ out.inc();
+ if(st)
+ {
+ out << nl << "r = struct();";
+ }
+ else
+ {
+ out << nl << "r = containers.Map('KeyType', '" << dictionaryTypeToString(key, true) << "', 'ValueType', '"
+ << dictionaryTypeToString(value, false) << "');";
+ }
+ out.dec();
+ out << nl << "end";
+
+ if(!p->isLocal())
+ {
+ out << nl << "function write(os, d)";
+ out.inc();
+ out << nl << "if isempty(d)";
+ out.inc();
+ out << nl << "os.writeSize(0);";
+ out.dec();
+ out << nl << "else";
+ out.inc();
+ if(st)
+ {
+ out << nl << "sz = length(d);";
+ out << nl << "os.writeSize(sz);";
+ out << nl << "for i = 1:sz";
+ out.inc();
+ int idx = 0;
+ marshal(out, "os", "d(i).key", key, false, 0, idx);
+ marshal(out, "os", "d(i).value", value, false, 0, idx);
+ out.dec();
+ out << nl << "end";
+ }
+ else
+ {
+ out << nl << "sz = d.Count;";
+ out << nl << "os.writeSize(sz);";
+ out << nl << "keys = d.keys();";
+ out << nl << "values = d.values();";
+ out << nl << "for i = 1:sz";
+ out.inc();
+ int idx = 0;
+ out << nl << "k = keys{i};";
+ out << nl << "v = values{i};";
+ marshal(out, "os", "k", key, false, 0, idx);
+ marshal(out, "os", "v", value, false, 0, idx);
+ out.dec();
+ out << nl << "end";
+ }
+ out.dec();
+ out << nl << "end";
+ out.dec();
+ out << nl << "end";
+
+ out << nl << "function r = read(is)";
+ out.inc();
+ out << nl << "sz = is.readSize();";
+ out << nl << "r = " << abs << ".new();";
+ out << nl << "for i = 1:sz";
+ out.inc();
+ int idx = 0;
+ unmarshal(out, "is", "k", key, false, 0, idx);
+ unmarshal(out, "is", "v", value, false, 0, idx);
+ if(st)
+ {
+ out << nl << "r(i).key = k;";
+ out << nl << "r(i).value = v;";
+ }
+ else if(EnumPtr::dynamicCast(key))
+ {
+ out << nl << "r(int32(k)) = v;";
+ }
+ else
+ {
+ out << nl << "r(k) = v;";
+ }
+ out.dec();
+ out << nl << "end";
+ out.dec();
+ out << nl << "end";
+ }
+
+ out.dec();
+ out << nl << "end";
+
+ out.dec();
+ out << nl << "end";
+ out << nl;
+
+ out.close();
+}
+
+void
+CodeVisitor::visitEnum(const EnumPtr& p)
+{
+ const string name = fixIdent(p->name());
+ const string scoped = p->scoped();
+ const string abs = getAbsolute(p);
+
+ IceUtilInternal::Output out;
+ openClass(scoped, out);
+
+ out << nl << "classdef " << name << " < int32";
+
+ const EnumeratorList enumerators = p->enumerators();
+ out.inc();
+ out << nl << "enumeration";
+ out.inc();
+ for(EnumeratorList::const_iterator q = enumerators.begin(); q != enumerators.end(); ++q)
+ {
+ out << nl << fixIdent((*q)->name()) << " (" << (*q)->value() << ")";
+ }
+ out.dec();
+ out << nl << "end";
+
+ out << nl << "methods(Static)";
+ out.inc();
+ if(!p->isLocal())
+ {
+ out << nl << "function ice_write(os, v)";
+ out.inc();
+ out << nl << "if isempty(v)";
+ out.inc();
+ string firstEnum = fixIdent(enumerators.front()->name());
+ out << nl << "os.writeEnum(int32(" << abs << "." << firstEnum << "), " << p->maxValue() << ");";
+ out.dec();
+ out << nl << "else";
+ out.inc();
+ out << nl << "os.writeEnum(int32(v), " << p->maxValue() << ");";
+ out.dec();
+ out << nl << "end";
+ out.dec();
+ out << nl << "end";
+ out << nl << "function r = ice_read(is)";
+ out.inc();
+ out << nl << "v = is.readEnum(" << p->maxValue() << ");";
+ out << nl << "r = " << abs << ".ice_getValue(v);";
+ out.dec();
+ out << nl << "end";
+ }
+ out << nl << "function r = ice_getValue(v)";
+ out.inc();
+ out << nl << "switch v";
+ out.inc();
+ for(EnumeratorList::const_iterator q = enumerators.begin(); q != enumerators.end(); ++q)
+ {
+ out << nl << "case " << (*q)->value();
+ out.inc();
+ out << nl << "r = " << abs << "." << fixIdent((*q)->name()) << ";";
+ out.dec();
+ }
+ out << nl << "otherwise";
+ out.inc();
+ out << nl << "throw(Ice.MarshalException('', '', sprintf('enumerator value %d is out of range', v)));";
+ out.dec();
+ out.dec();
+ out << nl << "end";
+ out.dec();
+ out << nl << "end";
+
+ out.dec();
+ out << nl << "end";
+
+ out.dec();
+ out << nl << "end";
+ out << nl;
+ out.close();
+}
+
+void
+CodeVisitor::visitConst(const ConstPtr& p)
+{
+ const string name = fixIdent(p->name());
+ const string scoped = p->scoped();
+
+ IceUtilInternal::Output out;
+ openClass(scoped, out);
+
+ out << nl << "classdef " << name;
+
+ out.inc();
+ out << nl << "properties(Constant)";
+ out.inc();
+ out << nl << "value " << typeToString(p->type()) << " = "
+ << constantValue(p->type(), p->valueType(), p->value());
+ out.dec();
+ out << nl << "end";
+
+ out.dec();
+ out << nl << "end";
+ out << nl;
+ out.close();
+ out.close();
+}
+
+void
+CodeVisitor::openClass(const string& scoped, IceUtilInternal::Output& out)
+{
+ vector<string> v = splitScopedName(scoped);
+ assert(v.size() > 1);
+
+ string path;
+ if(!_dir.empty())
+ {
+ path = _dir + "/";
+ }
+
+ //
+ // Create a package directory corresponding to each Slice module.
+ //
+ for(vector<string>::size_type i = 0; i < v.size() - 1; i++)
+ {
+ path += "+" + lookupKwd(v[i]);
+ if(!IceUtilInternal::directoryExists(path))
+ {
+ if(IceUtilInternal::mkdir(path, 0777) != 0)
+ {
+ ostringstream os;
+ os << "cannot create directory `" << path << "': " << strerror(errno);
+ throw FileException(__FILE__, __LINE__, os.str());
+ }
+ FileTracker::instance()->addDirectory(path);
+ }
+ path += "/";
+ }
+
+ //
+ // There are two options:
+ //
+ // 1) Create a subdirectory named "@ClassName" containing a file "ClassName.m".
+ // 2) Create a file named "ClassName.m".
+ //
+ // The class directory is useful if you want to add additional supporting files for the class. We only
+ // generate a single file for a class so we use option 2.
+ //
+ const string cls = lookupKwd(v[v.size() - 1]);
+ path += "/" + cls + ".m";
+
+ out.open(path);
+ printHeader(out);
+ FileTracker::instance()->addFile(path);
+}
+
+string
+CodeVisitor::getOperationMode(Slice::Operation::Mode mode)
+{
+ switch(mode)
+ {
+ case Operation::Normal:
+ return "Normal";
+ case Operation::Nonmutating:
+ return "Nonmutating";
+ case Operation::Idempotent:
+ return "Idempotent";
+ default:
+ return "???";
+ }
+}
+
+void
+CodeVisitor::collectClassMembers(const ClassDefPtr& p, MemberInfoList& allMembers, bool inherited)
+{
+ ClassList bases = p->bases();
+ if(!bases.empty() && !bases.front()->isInterface())
+ {
+ collectClassMembers(bases.front(), allMembers, true);
+ }
+
+ DataMemberList members = p->dataMembers();
+
+ for(DataMemberList::iterator q = members.begin(); q != members.end(); ++q)
+ {
+ MemberInfo m;
+ m.fixedName = fixIdent((*q)->name());
+ m.inherited = inherited;
+ m.dataMember = *q;
+ allMembers.push_back(m);
+ }
+}
+
+void
+CodeVisitor::collectExceptionMembers(const ExceptionPtr& p, MemberInfoList& allMembers, bool inherited)
+{
+ ExceptionPtr base = p->base();
+ if(base)
+ {
+ collectExceptionMembers(base, allMembers, true);
+ }
+
+ DataMemberList members = p->dataMembers();
+
+ for(DataMemberList::iterator q = members.begin(); q != members.end(); ++q)
+ {
+ MemberInfo m;
+ m.fixedName = fixIdent((*q)->name());
+ m.inherited = inherited;
+ m.dataMember = *q;
+ allMembers.push_back(m);
+ }
+}
+
+CodeVisitor::ParamInfoList
+CodeVisitor::getInParams(const OperationPtr& op)
+{
+ const ParamDeclList l = op->inParameters();
+ ParamInfoList r;
+ for(ParamDeclList::const_iterator p = l.begin(); p != l.end(); ++p)
+ {
+ ParamInfo info;
+ info.fixedName = fixIdent((*p)->name());
+ info.type = (*p)->type();
+ info.optional = (*p)->optional();
+ info.tag = (*p)->tag();
+ info.param = *p;
+ r.push_back(info);
+ }
+ return r;
+}
+
+CodeVisitor::ParamInfoList
+CodeVisitor::getOutParams(const OperationPtr& op)
+{
+ const ParamDeclList l = op->outParameters();
+ ParamInfoList r;
+
+ if(op->returnType())
+ {
+ ParamInfo info;
+ info.fixedName = "result";
+ for(ParamDeclList::const_iterator p = l.begin(); p != l.end(); ++p)
+ {
+ if((*p)->name() == "result")
+ {
+ info.fixedName = "result_";
+ break;
+ }
+ }
+ info.type = op->returnType();
+ info.optional = op->returnIsOptional();
+ info.tag = op->returnTag();
+ r.push_back(info);
+ }
+
+ for(ParamDeclList::const_iterator p = l.begin(); p != l.end(); ++p)
+ {
+ ParamInfo info;
+ info.fixedName = fixIdent((*p)->name());
+ info.type = (*p)->type();
+ info.optional = (*p)->optional();
+ info.tag = (*p)->tag();
+ info.param = *p;
+ r.push_back(info);
+ }
+
+ return r;
+}
+
+string
+CodeVisitor::getOptionalFormat(const TypePtr& type)
+{
+ BuiltinPtr bp = BuiltinPtr::dynamicCast(type);
+ if(bp)
+ {
+ switch(bp->kind())
+ {
+ case Builtin::KindByte:
+ case Builtin::KindBool:
+ {
+ return "'OptionalFormatF1'";
+ }
+ case Builtin::KindShort:
+ {
+ return "'OptionalFormatF2'";
+ }
+ case Builtin::KindInt:
+ case Builtin::KindFloat:
+ {
+ return "'OptionalFormatF4'";
+ }
+ case Builtin::KindLong:
+ case Builtin::KindDouble:
+ {
+ return "'OptionalFormatF8'";
+ }
+ case Builtin::KindString:
+ {
+ return "'OptionalFormatVSize'";
+ }
+ case Builtin::KindObject:
+ {
+ return "'OptionalFormatClass'";
+ }
+ case Builtin::KindObjectProxy:
+ {
+ return "'OptionalFormatFSize'";
+ }
+ case Builtin::KindLocalObject:
+ {
+ assert(false);
+ break;
+ }
+ case Builtin::KindValue:
+ {
+ return "'OptionalFormatClass'";
+ }
+ }
+ }
+
+ if(EnumPtr::dynamicCast(type))
+ {
+ return "'OptionalFormatSize'";
+ }
+
+ SequencePtr seq = SequencePtr::dynamicCast(type);
+ if(seq)
+ {
+ return seq->type()->isVariableLength() ? "'OptionalFormatFSize'" : "'OptionalFormatVSize'";
+ }
+
+ DictionaryPtr d = DictionaryPtr::dynamicCast(type);
+ if(d)
+ {
+ return (d->keyType()->isVariableLength() || d->valueType()->isVariableLength()) ?
+ "'OptionalFormatFSize'" : "'OptionalFormatVSize'";
+ }
+
+ StructPtr st = StructPtr::dynamicCast(type);
+ if(st)
+ {
+ return st->isVariableLength() ? "'OptionalFormatFSize'" : "'OptionalFormatVSize'";
+ }
+
+ if(ProxyPtr::dynamicCast(type))
+ {
+ return "'OptionalFormatFSize'";
+ }
+
+ ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
+ assert(cl);
+ return "'OptionalFormatClass'";
+}
+
+string
+CodeVisitor::getFormatType(FormatType type)
+{
+ switch(type)
+ {
+ case DefaultFormat:
+ return "Ice.FormatType.DefaultFormat";
+ case CompactFormat:
+ return "Ice.FormatType.CompactFormat";
+ case SlicedFormat:
+ return "Ice.FormatType.SlicedFormat";
+ default:
+ assert(false);
+ }
+
+ return "???";
+}
+
+void
+CodeVisitor::marshal(IceUtilInternal::Output& out, const string& stream, const string& v, const TypePtr& type,
+ bool optional, int tag, int& idx)
+{
+ BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
+ if(builtin)
+ {
+ switch(builtin->kind())
+ {
+ case Builtin::KindByte:
+ {
+ if(optional)
+ {
+ out << nl << stream << ".writeByteOpt(" << tag << ", " << v << ");";
+ }
+ else
+ {
+ out << nl << stream << ".writeByte(" << v << ");";
+ }
+ break;
+ }
+ case Builtin::KindBool:
+ {
+ if(optional)
+ {
+ out << nl << stream << ".writeBoolOpt(" << tag << ", " << v << ");";
+ }
+ else
+ {
+ out << nl << stream << ".writeBool(" << v << ");";
+ }
+ break;
+ }
+ case Builtin::KindShort:
+ {
+ if(optional)
+ {
+ out << nl << stream << ".writeShortOpt(" << tag << ", " << v << ");";
+ }
+ else
+ {
+ out << nl << stream << ".writeShort(" << v << ");";
+ }
+ break;
+ }
+ case Builtin::KindInt:
+ {
+ if(optional)
+ {
+ out << nl << stream << ".writeIntOpt(" << tag << ", " << v << ");";
+ }
+ else
+ {
+ out << nl << stream << ".writeInt(" << v << ");";
+ }
+ break;
+ }
+ case Builtin::KindLong:
+ {
+ if(optional)
+ {
+ out << nl << stream << ".writeLongOpt(" << tag << ", " << v << ");";
+ }
+ else
+ {
+ out << nl << stream << ".writeLong(" << v << ");";
+ }
+ break;
+ }
+ case Builtin::KindFloat:
+ {
+ if(optional)
+ {
+ out << nl << stream << ".writeFloatOpt(" << tag << ", " << v << ");";
+ }
+ else
+ {
+ out << nl << stream << ".writeFloat(" << v << ");";
+ }
+ break;
+ }
+ case Builtin::KindDouble:
+ {
+ if(optional)
+ {
+ out << nl << stream << ".writeDoubleOpt(" << tag << ", " << v << ");";
+ }
+ else
+ {
+ out << nl << stream << ".writeDouble(" << v << ");";
+ }
+ break;
+ }
+ case Builtin::KindString:
+ {
+ if(optional)
+ {
+ out << nl << stream << ".writeStringOpt(" << tag << ", " << v << ");";
+ }
+ else
+ {
+ out << nl << stream << ".writeString(" << v << ");";
+ }
+ break;
+ }
+ case Builtin::KindObject:
+ case Builtin::KindValue:
+ {
+ if(optional)
+ {
+ out << nl << stream << ".writeValueOpt(" << tag << ", " << v << ");";
+ }
+ else
+ {
+ out << nl << stream << ".writeValue(" << v << ");";
+ }
+ break;
+ }
+ case Builtin::KindObjectProxy:
+ {
+ if(optional)
+ {
+ out << nl << stream << ".writeProxyOpt(" << tag << ", " << v << ");";
+ }
+ else
+ {
+ out << nl << stream << ".writeProxy(" << v << ");";
+ }
+ break;
+ }
+ case Builtin::KindLocalObject:
+ {
+ assert(false);
+ break;
+ }
+ }
+ return;
+ }
+
+ ProxyPtr prx = ProxyPtr::dynamicCast(type);
+ if(prx)
+ {
+ if(optional)
+ {
+ out << nl << stream << ".writeProxyOpt(" << tag << ", " << v << ");";
+ }
+ else
+ {
+ out << nl << stream << ".writeProxy(" << v << ");";
+ }
+ return;
+ }
+
+ ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
+ if(cl)
+ {
+ if(optional)
+ {
+ out << nl << stream << ".writeValueOpt(" << tag << ", " << v << ");";
+ }
+ else
+ {
+ out << nl << stream << ".writeValue(" << v << ");";
+ }
+ return;
+ }
+
+ StructPtr st = StructPtr::dynamicCast(type);
+ if(st)
+ {
+ const string typeS = getAbsolute(st);
+ if(optional)
+ {
+ if(optional)
+ {
+ out << nl << "if ~isempty(" << v << ") && " << stream << ".writeOptional(" << tag << ", "
+ << getOptionalFormat(type) << ")";
+ out.inc();
+ }
+
+ if(st->isVariableLength())
+ {
+ out << nl << "pos = " << stream << ".startSize();";
+ out << nl << typeS << ".ice_write(" << stream << ", " << v << ");";
+ out << nl << stream << ".endSize(pos);";
+ }
+ else
+ {
+ out << nl << stream << ".writeSize(" << st->minWireSize() << ");";
+ out << nl << typeS << ".ice_write(" << stream << ", " << v << ");";
+ }
+ if(optional)
+ {
+ out.dec();
+ out << nl << "end";
+ }
+ }
+ else
+ {
+ out << nl << typeS << ".ice_write(" << stream << ", " << v << ");";
+ }
+ return;
+ }
+
+ EnumPtr en = EnumPtr::dynamicCast(type);
+ if(en)
+ {
+ const string typeS = getAbsolute(en);
+ if(optional)
+ {
+ out << nl << "if " << stream << ".writeOptional(" << tag << ", " << getOptionalFormat(type) << ")";
+ out.inc();
+ out << nl << typeS << ".ice_write(" << stream << ", " << v << ");";
+ out.dec();
+ out << nl << "end";
+ }
+ else
+ {
+ out << nl << typeS << ".ice_write(" << stream << ", " << v << ");";
+ }
+ return;
+ }
+
+ DictionaryPtr dict = DictionaryPtr::dynamicCast(type);
+ if(dict)
+ {
+ if(optional)
+ {
+ out << nl << "if " << stream << ".writeOptional(" << tag << ", " << getOptionalFormat(dict) << "))";
+ out.inc();
+ out << nl << getAbsolute(dict) << ".write(" << stream << ", " << v << ");";
+ out.dec();
+ out << nl << "end";
+ }
+ else
+ {
+ out << nl << getAbsolute(dict) << ".write(" << stream << ", " << v << ");";
+ }
+ return;
+ }
+
+ SequencePtr seq = SequencePtr::dynamicCast(type);
+ if(seq)
+ {
+ const TypePtr content = seq->type();
+ const BuiltinPtr b = BuiltinPtr::dynamicCast(content);
+
+ if(b && b->kind() != Builtin::KindObject && b->kind() != Builtin::KindObjectProxy &&
+ b->kind() != Builtin::KindValue)
+ {
+ static const char* builtinTable[] =
+ {
+ "Byte",
+ "Bool",
+ "Short",
+ "Int",
+ "Long",
+ "Float",
+ "Double",
+ "String",
+ "???",
+ "???",
+ "???",
+ "???"
+ };
+ string bs = builtinTable[b->kind()];
+ out << nl << stream << ".write" << builtinTable[b->kind()] << "Seq";
+ if(optional)
+ {
+ out << "Opt(" << tag << ", ";
+ }
+ else
+ {
+ out << "(";
+ }
+ out << v << ");";
+ return;
+ }
+
+ if(optional)
+ {
+ out << nl << "if " << stream << ".writeOptional(" << tag << ", " << getOptionalFormat(seq) << "))";
+ out.inc();
+ out << nl << getAbsolute(seq) << ".write(" << stream << ", " << v << ");";
+ out.dec();
+ out << nl << "end";
+ }
+ else
+ {
+ out << nl << getAbsolute(seq) << ".write(" << stream << ", " << v << ");";
+ }
+ return;
+ }
+
+ assert(false);
+}
+
+
+void
+CodeVisitor::unmarshal(IceUtilInternal::Output& out, const string& stream, const string& v, const TypePtr& type,
+ bool optional, int tag, int& idx)
+{
+ BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
+ if(builtin)
+ {
+ switch(builtin->kind())
+ {
+ case Builtin::KindByte:
+ {
+ if(optional)
+ {
+ out << nl << v << " = " << stream << ".readByteOpt(" << tag << ");";
+ }
+ else
+ {
+ out << nl << v << " = " << stream << ".readByte();";
+ }
+ break;
+ }
+ case Builtin::KindBool:
+ {
+ if(optional)
+ {
+ out << nl << v << " = " << stream << ".readBoolOpt(" << tag << ");";
+ }
+ else
+ {
+ out << nl << v << " = " << stream << ".readBool();";
+ }
+ break;
+ }
+ case Builtin::KindShort:
+ {
+ if(optional)
+ {
+ out << nl << v << " = " << stream << ".readShortOpt(" << tag << ");";
+ }
+ else
+ {
+ out << nl << v << " = " << stream << ".readShort();";
+ }
+ break;
+ }
+ case Builtin::KindInt:
+ {
+ if(optional)
+ {
+ out << nl << v << " = " << stream << ".readIntOpt(" << tag << ");";
+ }
+ else
+ {
+ out << nl << v << " = " << stream << ".readInt();";
+ }
+ break;
+ }
+ case Builtin::KindLong:
+ {
+ if(optional)
+ {
+ out << nl << v << " = " << stream << ".readLongOpt(" << tag << ");";
+ }
+ else
+ {
+ out << nl << v << " = " << stream << ".readLong();";
+ }
+ break;
+ }
+ case Builtin::KindFloat:
+ {
+ if(optional)
+ {
+ out << nl << v << " = " << stream << ".readFloatOpt(" << tag << ");";
+ }
+ else
+ {
+ out << nl << v << " = " << stream << ".readFloat();";
+ }
+ break;
+ }
+ case Builtin::KindDouble:
+ {
+ if(optional)
+ {
+ out << nl << v << " = " << stream << ".readDoubleOpt(" << tag << ");";
+ }
+ else
+ {
+ out << nl << v << " = " << stream << ".readDouble();";
+ }
+ break;
+ }
+ case Builtin::KindString:
+ {
+ if(optional)
+ {
+ out << nl << v << " = " << stream << ".readStringOpt(" << tag << ");";
+ }
+ else
+ {
+ out << nl << v << " = " << stream << ".readString();";
+ }
+ break;
+ }
+ case Builtin::KindObject:
+ case Builtin::KindValue:
+ {
+#if 0 // TBD
+ if(optional)
+ {
+ out << nl << stream << ".readValue(" << tag << ", " << param << ");";
+ }
+ else if(holder && mode == OptionalNone)
+ {
+ out << nl << stream << ".readValue(" << param << ");";
+ }
+ else
+ {
+ if(patchParams.empty())
+ {
+ out << nl << stream << ".readValue(new Patcher());";
+ }
+ else
+ {
+ out << nl << stream << ".readValue(" << patchParams << ");";
+ }
+ }
+#endif
+ break;
+ }
+ case Builtin::KindObjectProxy:
+ {
+ if(optional)
+ {
+ out << nl << v << " = " << stream << ".readProxyOpt(" << tag << ");";
+ }
+ else
+ {
+ out << nl << v << " = " << stream << ".readProxy();";
+ }
+ break;
+ }
+ case Builtin::KindLocalObject:
+ {
+ assert(false);
+ break;
+ }
+ }
+ return;
+ }
+
+ ProxyPtr prx = ProxyPtr::dynamicCast(type);
+ if(prx)
+ {
+ const string typeS = getAbsolute(prx->_class(), "", "Prx");
+ if(optional)
+ {
+ out << nl << "if " << stream << ".readOptional(" << tag << ", " << getOptionalFormat(type) << ")";
+ out.inc();
+ out << nl << stream << ".skip(4);";
+ out << nl << v << " = " << typeS << ".ice_read(" << stream << ");";
+ out.dec();
+ out << nl << "end";
+ }
+ else
+ {
+ out << nl << v << " = " << typeS << ".ice_read(" << stream << ");";
+ }
+ return;
+ }
+
+ ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
+ if(cl)
+ {
+#if 0 // TBD
+ if(optional)
+ {
+ const string typeS = typeToString(type, TypeModeIn, package);
+ out << nl << "if(" << stream << ".readOptional(" << tag << ", " << getOptionalFormat(type) << "))";
+ out << sb;
+ out << nl << stream << ".readValue(new Ice.OptionalObject(" << v << ", " << typeS << ".class, "
+ << getStaticId(type, package) << "));";
+ out << eb;
+ if(mode == OptionalOutParam)
+ {
+ out << nl << "else";
+ out << sb;
+ out << nl << v << ".clear();";
+ out << eb;
+ }
+ }
+ else
+ {
+ if(holder && mode == OptionalNone)
+ {
+ out << nl << stream << ".readValue(" << param << ");";
+ }
+ else
+ {
+ if(patchParams.empty())
+ {
+ out << nl << stream << ".readValue(new Patcher());";
+ }
+ else
+ {
+ out << nl << stream << ".readValue(" << patchParams << ");";
+ }
+ }
+ }
+#endif
+ return;
+ }
+
+ StructPtr st = StructPtr::dynamicCast(type);
+ if(st)
+ {
+ const string typeS = getAbsolute(st);
+ if(optional)
+ {
+ out << nl << "if " << stream << ".readOptional(" << tag << ", " << getOptionalFormat(type) << ")";
+ out.inc();
+
+ if(st->isVariableLength())
+ {
+ out << nl << stream << ".skip(4);";
+ }
+ else
+ {
+ out << nl << stream << ".skipSize();";
+ }
+
+ out << nl << v << " = " << typeS << ".ice_read(" << stream << ");";
+
+ out.dec();
+ out << nl << "end";
+ }
+ else
+ {
+ out << nl << v << " = " << typeS << ".ice_read(" << stream << ");";
+ }
+ return;
+ }
+
+ EnumPtr en = EnumPtr::dynamicCast(type);
+ if(en)
+ {
+ const string typeS = getAbsolute(en);
+ if(optional)
+ {
+ out << nl << "if " << stream << ".readOptional(" << tag << ", " << getOptionalFormat(type) << ")";
+ out.inc();
+ out << nl << v << " = " << typeS << ".ice_read(" << stream << ");";
+ out.dec();
+ out << nl << "end";
+ }
+ else
+ {
+ out << nl << v << " = " << typeS << ".ice_read(" << stream << ");";
+ }
+ return;
+ }
+
+ DictionaryPtr dict = DictionaryPtr::dynamicCast(type);
+ if(dict)
+ {
+ if(optional)
+ {
+ out << nl << "if " << stream << ".readOptional(" << tag << ", " << getOptionalFormat(dict) << "))";
+ out.inc();
+ out << nl << v << " = " << getAbsolute(dict) << ".read(" << stream << ");";
+ out.dec();
+ out << nl << "end";
+ }
+ else
+ {
+ out << nl << v << " = " << getAbsolute(dict) << ".read(" << stream << ");";
+ }
+ return;
+ }
+
+ SequencePtr seq = SequencePtr::dynamicCast(type);
+ if(seq)
+ {
+ const TypePtr content = seq->type();
+ const BuiltinPtr b = BuiltinPtr::dynamicCast(content);
+
+ if(b && b->kind() != Builtin::KindObject && b->kind() != Builtin::KindObjectProxy &&
+ b->kind() != Builtin::KindValue)
+ {
+ static const char* builtinTable[] =
+ {
+ "Byte",
+ "Bool",
+ "Short",
+ "Int",
+ "Long",
+ "Float",
+ "Double",
+ "String",
+ "???",
+ "???",
+ "???",
+ "???"
+ };
+ string bs = builtinTable[b->kind()];
+ out << nl << v << " = " << stream << ".read" << builtinTable[b->kind()] << "Seq";
+ if(optional)
+ {
+ out << "Opt(" << tag << ");";
+ }
+ else
+ {
+ out << "();";
+ }
+ return;
+ }
+
+ if(optional)
+ {
+ out << nl << "if " << stream << ".readOptional(" << tag << ", " << getOptionalFormat(seq) << "))";
+ out.inc();
+ out << nl << v << " = " << getAbsolute(seq) << ".read(" << stream << ");";
+ out.dec();
+ out << nl << "end";
+ }
+ else
+ {
+ out << nl << v << " = " << getAbsolute(seq) << ".read(" << stream << ");";
+ }
+ return;
+ }
+
+ assert(false);
+}
+
+static void
+generate(const UnitPtr& un, const string& dir, bool all, bool checksum, const vector<string>& includePaths)
+{
+ CodeVisitor codeVisitor(dir);
+ un->visit(&codeVisitor, false);
+
+#if 0
+ if(checksum)
+ {
+ ChecksumMap checksums = createChecksums(un);
+ if(!checksums.empty())
+ {
+ out << sp;
+ if(ns)
+ {
+ out << "namespace"; // Global namespace.
+ out << sb;
+ out << "new Ice\\SliceChecksumInit(array(";
+ for(ChecksumMap::const_iterator p = checksums.begin(); p != checksums.end();)
+ {
+ out << nl << "\"" << p->first << "\" => \"";
+ ostringstream str;
+ str.flags(ios_base::hex);
+ str.fill('0');
+ for(vector<unsigned char>::const_iterator q = p->second.begin(); q != p->second.end(); ++q)
+ {
+ str << static_cast<int>(*q);
+ }
+ out << str.str() << "\"";
+ if(++p != checksums.end())
+ {
+ out << ",";
+ }
+ }
+ out << "));";
+ out << eb;
+ }
+ else
+ {
+ for(ChecksumMap::const_iterator p = checksums.begin(); p != checksums.end(); ++p)
+ {
+ out << nl << "$Ice_sliceChecksums[\"" << p->first << "\"] = \"";
+ ostringstream str;
+ str.flags(ios_base::hex);
+ str.fill('0');
+ for(vector<unsigned char>::const_iterator q = p->second.begin(); q != p->second.end(); ++q)
+ {
+ str << static_cast<int>(*q);
+ }
+ out << str.str() << "\";";
+ }
+ }
+ }
+ }
+
+ out << nl; // Trailing newline.
+#endif
+}
+
+namespace
+{
+
+IceUtil::Mutex* globalMutex = 0;
+bool interrupted = false;
+
+class Init
+{
+public:
+
+ Init()
+ {
+ globalMutex = new IceUtil::Mutex;
+ }
+
+ ~Init()
+ {
+ delete globalMutex;
+ globalMutex = 0;
+ }
+};
+
+Init init;
+
+}
+
+static void
+interruptedCallback(int /*signal*/)
+{
+ IceUtilInternal::MutexPtrLock<IceUtil::Mutex> sync(globalMutex);
+
+ interrupted = true;
+}
+
+static void
+usage(const string& n)
+{
+ consoleErr << "Usage: " << n << " [options] slice-files...\n";
+ consoleErr <<
+ "Options:\n"
+ "-h, --help Show this message.\n"
+ "-v, --version Display the Ice version.\n"
+ "-DNAME Define NAME as 1.\n"
+ "-DNAME=DEF Define NAME as DEF.\n"
+ "-UNAME Remove any definition for NAME.\n"
+ "-IDIR Put DIR in the include file search path.\n"
+ "-E Print preprocessor output on stdout.\n"
+ "--output-dir DIR Create files in the directory DIR.\n"
+ "-d, --debug Print debug messages.\n"
+ "--depend Generate Makefile dependencies.\n"
+ "--depend-xml Generate dependencies in XML format.\n"
+ "--depend-file FILE Write dependencies to FILE instead of standard output.\n"
+ "--validate Validate command line options.\n"
+ "--all Generate code for Slice definitions in included files.\n"
+ "--checksum Generate checksums for Slice definitions.\n"
+ ;
+}
+
+int
+compile(const vector<string>& argv)
+{
+ IceUtilInternal::Options opts;
+ opts.addOpt("h", "help");
+ opts.addOpt("v", "version");
+ opts.addOpt("", "validate");
+ opts.addOpt("D", "", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat);
+ opts.addOpt("U", "", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat);
+ opts.addOpt("I", "", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat);
+ opts.addOpt("E");
+ opts.addOpt("", "output-dir", IceUtilInternal::Options::NeedArg);
+ opts.addOpt("", "depend");
+ opts.addOpt("", "depend-xml");
+ opts.addOpt("", "depend-file", IceUtilInternal::Options::NeedArg, "");
+ opts.addOpt("d", "debug");
+ opts.addOpt("", "all");
+ opts.addOpt("", "checksum");
+
+ bool validate = find(argv.begin(), argv.end(), "--validate") != argv.end();
+
+ vector<string> args;
+ try
+ {
+ args = opts.parse(argv);
+ }
+ catch(const IceUtilInternal::BadOptException& e)
+ {
+ consoleErr << argv[0] << ": error: " << e.reason << endl;
+ if(!validate)
+ {
+ usage(argv[0]);
+ }
+ return EXIT_FAILURE;
+ }
+
+ if(opts.isSet("help"))
+ {
+ usage(argv[0]);
+ return EXIT_SUCCESS;
+ }
+
+ if(opts.isSet("version"))
+ {
+ consoleErr << ICE_STRING_VERSION << endl;
+ return EXIT_SUCCESS;
+ }
+
+ vector<string> cppArgs;
+ vector<string> optargs = opts.argVec("D");
+ for(vector<string>::const_iterator i = optargs.begin(); i != optargs.end(); ++i)
+ {
+ cppArgs.push_back("-D" + *i);
+ }
+
+ optargs = opts.argVec("U");
+ for(vector<string>::const_iterator i = optargs.begin(); i != optargs.end(); ++i)
+ {
+ cppArgs.push_back("-U" + *i);
+ }
+
+ vector<string> includePaths = opts.argVec("I");
+ for(vector<string>::const_iterator i = includePaths.begin(); i != includePaths.end(); ++i)
+ {
+ cppArgs.push_back("-I" + Preprocessor::normalizeIncludePath(*i));
+ }
+
+ bool preprocess = opts.isSet("E");
+
+ string output = opts.optArg("output-dir");
+
+ bool depend = opts.isSet("depend");
+
+ bool dependxml = opts.isSet("depend-xml");
+
+ string dependFile = opts.optArg("depend-file");
+
+ bool debug = opts.isSet("debug");
+
+ bool all = opts.isSet("all");
+
+ bool checksum = opts.isSet("checksum");
+
+ if(args.empty())
+ {
+ consoleErr << argv[0] << ": error: no input file" << endl;
+ if(!validate)
+ {
+ usage(argv[0]);
+ }
+ return EXIT_FAILURE;
+ }
+
+ if(depend && dependxml)
+ {
+ consoleErr << argv[0] << ": error: cannot specify both --depend and --depend-xml" << endl;
+ if(!validate)
+ {
+ usage(argv[0]);
+ }
+ return EXIT_FAILURE;
+ }
+
+ if(validate)
+ {
+ return EXIT_SUCCESS;
+ }
+
+ int status = EXIT_SUCCESS;
+
+ IceUtil::CtrlCHandler ctrlCHandler;
+ ctrlCHandler.setCallback(interruptedCallback);
+
+ ostringstream os;
+ if(dependxml)
+ {
+ os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<dependencies>" << endl;
+ }
+
+ for(vector<string>::const_iterator i = args.begin(); i != args.end(); ++i)
+ {
+ //
+ // Ignore duplicates.
+ //
+ vector<string>::iterator p = find(args.begin(), args.end(), *i);
+ if(p != i)
+ {
+ continue;
+ }
+
+ if(depend || dependxml)
+ {
+ PreprocessorPtr icecpp = Preprocessor::create(argv[0], *i, cppArgs);
+ FILE* cppHandle = icecpp->preprocess(false, "-D__SLICE2PHP__");
+
+ if(cppHandle == 0)
+ {
+ return EXIT_FAILURE;
+ }
+
+ UnitPtr u = Unit::createUnit(false, false, false, false);
+ int parseStatus = u->parse(*i, cppHandle, debug);
+ u->destroy();
+
+ if(parseStatus == EXIT_FAILURE)
+ {
+ return EXIT_FAILURE;
+ }
+
+ if(!icecpp->printMakefileDependencies(os, depend ? Preprocessor::PHP : Preprocessor::SliceXML,
+ includePaths, "-D__SLICE2PHP__"))
+ {
+ return EXIT_FAILURE;
+ }
+
+ if(!icecpp->close())
+ {
+ return EXIT_FAILURE;
+ }
+ }
+ else
+ {
+ PreprocessorPtr icecpp = Preprocessor::create(argv[0], *i, cppArgs);
+ FILE* cppHandle = icecpp->preprocess(false, "-D__SLICE2PHP__");
+
+ if(cppHandle == 0)
+ {
+ return EXIT_FAILURE;
+ }
+
+ if(preprocess)
+ {
+ char buf[4096];
+ while(fgets(buf, static_cast<int>(sizeof(buf)), cppHandle) != ICE_NULLPTR)
+ {
+ if(fputs(buf, stdout) == EOF)
+ {
+ return EXIT_FAILURE;
+ }
+ }
+ if(!icecpp->close())
+ {
+ return EXIT_FAILURE;
+ }
+ }
+ else
+ {
+ UnitPtr u = Unit::createUnit(false, all, false, false);
+ int parseStatus = u->parse(*i, cppHandle, debug);
+
+ if(!icecpp->close())
+ {
+ u->destroy();
+ return EXIT_FAILURE;
+ }
+
+ if(parseStatus == EXIT_FAILURE)
+ {
+ status = EXIT_FAILURE;
+ }
+ else
+ {
+ string base = icecpp->getBaseName();
+ string::size_type pos = base.find_last_of("/\\");
+ if(pos != string::npos)
+ {
+ base.erase(0, pos + 1);
+ }
+
+ try
+ {
+ generate(u, output, all, checksum, includePaths);
+ }
+ catch(const Slice::FileException& ex)
+ {
+ //
+ // If a file could not be created, then cleanup any created files.
+ //
+ FileTracker::instance()->cleanup();
+ u->destroy();
+ consoleErr << argv[0] << ": error: " << ex.reason() << endl;
+ return EXIT_FAILURE;
+ }
+ catch(const string& err)
+ {
+ FileTracker::instance()->cleanup();
+ consoleErr << argv[0] << ": error: " << err << endl;
+ status = EXIT_FAILURE;
+ }
+ }
+
+ u->destroy();
+ }
+ }
+
+ {
+ IceUtilInternal::MutexPtrLock<IceUtil::Mutex> sync(globalMutex);
+
+ if(interrupted)
+ {
+ FileTracker::instance()->cleanup();
+ return EXIT_FAILURE;
+ }
+ }
+ }
+
+ if(dependxml)
+ {
+ os << "</dependencies>\n";
+ }
+
+ if(depend || dependxml)
+ {
+ writeDependencies(os.str(), dependFile);
+ }
+
+ return status;
+}
+
+#ifdef _WIN32
+int wmain(int argc, wchar_t* argv[])
+#else
+int main(int argc, char* argv[])
+#endif
+{
+ vector<string> args = Slice::argvToArgs(argc, argv);
+ try
+ {
+ return compile(args);
+ }
+ catch(const std::exception& ex)
+ {
+ consoleErr << args[0] << ": error:" << ex.what() << endl;
+ return EXIT_FAILURE;
+ }
+ catch(const std::string& msg)
+ {
+ consoleErr << args[0] << ": error:" << msg << endl;
+ return EXIT_FAILURE;
+ }
+ catch(const char* msg)
+ {
+ consoleErr << args[0] << ": error:" << msg << endl;
+ return EXIT_FAILURE;
+ }
+ catch(...)
+ {
+ consoleErr << args[0] << ": error:" << "unknown exception" << endl;
+ return EXIT_FAILURE;
+ }
+}