diff options
author | Jose <jose@zeroc.com> | 2018-02-06 12:36:14 +0100 |
---|---|---|
committer | Jose <jose@zeroc.com> | 2018-02-06 12:36:14 +0100 |
commit | e08688fc5bcad9e037181319fe10cfcc59f06d20 (patch) | |
tree | 143bb4c0aa48f62e189b2431fcf6bed89e967246 /cpp/src/slice2matlab/Main.cpp | |
parent | Remove bogus 5.0.0 package imports (diff) | |
parent | Fix whitespace (diff) | |
download | ice-e08688fc5bcad9e037181319fe10cfcc59f06d20.tar.bz2 ice-e08688fc5bcad9e037181319fe10cfcc59f06d20.tar.xz ice-e08688fc5bcad9e037181319fe10cfcc59f06d20.zip |
Merge remote-tracking branch 'origin/matlab' into 3.7
Diffstat (limited to 'cpp/src/slice2matlab/Main.cpp')
-rw-r--r-- | cpp/src/slice2matlab/Main.cpp | 5032 |
1 files changed, 5032 insertions, 0 deletions
diff --git a/cpp/src/slice2matlab/Main.cpp b/cpp/src/slice2matlab/Main.cpp new file mode 100644 index 00000000000..1a556601c61 --- /dev/null +++ b/cpp/src/slice2matlab/Main.cpp @@ -0,0 +1,5032 @@ +// ********************************************************************** +// +// 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/Preprocessor.h> +#include <Slice/FileTracker.h> +#include <Slice/Parser.h> +#include <Slice/Util.h> +#include <cstring> +#include <climits> +#include <iterator> + +#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 +{ + +// +// Split an absolute name into its components and return the components as a list of identifiers. +// +vector<string> +splitAbsoluteName(const string& abs) +{ + vector<string> ids; + string::size_type start = 0; + string::size_type pos; + while((pos = abs.find(".", start)) != string::npos) + { + assert(pos > start); + ids.push_back(abs.substr(start, pos - start)); + start = pos + 1; + } + if(start != abs.size()) + { + ids.push_back(abs.substr(start)); + } + + return ids; +} + +// +// 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 +lookupKwd(const string& name) +{ + // + // Keyword list. *Must* be kept in alphabetical order. + // + static const string keywordList[] = + { + "break", "case", "catch", "classdef", "continue", "else", "elseif", "end", "enumeration", "events", "for", + "function", "global", "if", "methods", "otherwise", "parfor", "persistent", "properties", "return", "spmd", + "switch", "try", "while" + }; + bool found = binary_search(&keywordList[0], + &keywordList[sizeof(keywordList) / sizeof(*keywordList)], + name); + return found ? name + "_" : name; +} + +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 +fixEnumerator(const string& name) +{ + assert(name[0] != ':'); + + // + // Method list. These represent the built-in methods for enumerators, inherited from uint8 or int32. + // MATLAB does not allow an enumeration class to declare an enumerator having one of these names. + // + // *Must* be kept in alphabetical order. + // + static const string methodList[] = + { + "abs", "accumarray", "all", "and", "any", "bitand", "bitcmp", "bitget", "bitor", "bitset", "bitshift", + "bitxor", "bsxfun", "cat", "ceil", "cell", "cellstr", "char", "complex", "conj", "conv2", "ctranspose", + "cummax", "cummin", "cumprod", "cumsum", "diag", "diff", "double", "end", "eq", "fft", "fftn", "find", + "fix", "floor", "full", "function_handle", "ge", "gt", "horzcat", "ifft", "ifftn", "imag", "int16", "int32", + "int64", "int8", "intersect", "isempty", "isequal", "isequaln", "isequalwithequalnans", "isfinite", "isfloat", + "isinf", "isinteger", "islogical", "ismember", "isnan", "isnumeric", "isreal", "isscalar", "issorted", + "issparse", "isvector", "ldivide", "le", "length", "linsolve", "logical", "lt", "max", "min", "minus", + "mldivide", "mod", "mpower", "mrdivide", "mtimes", "ndims", "ne", "nnz", "nonzeros", "not", "numel", "nzmax", + "or", "permute", "plot", "plus", "power", "prod", "rdivide", "real", "rem", "reshape", "round", "setdiff", + "setxor", "sign", "single", "size", "sort", "sortrowsc", "strcmp", "strcmpi", "strncmp", "strncmpi", + "subsasgn", "subsindex", "subsref", "sum", "times", "transpose", "tril", "triu", "uint16", "uint32", "uint64", + "uminus", "union", "uplus", "vertcat", "xor" + }; + + bool found = binary_search(&methodList[0], + &methodList[sizeof(methodList) / sizeof(*methodList)], + name); + return found ? name + "_" : lookupKwd(name); +} + +string +fixOp(const string& name) +{ + assert(name[0] != ':'); + + // + // An operation name must be escaped if it matches any of the identifiers in this list, in addition to the + // MATLAB language keywords. The identifiers below represent the names of methods inherited from ObjectPrx + // and handle. + // + // *Must* be kept in alphabetical order. + // + static const string idList[] = + { + "addlistener", "checkedCast", "delete", "eq", "findobj", "findprop", "ge", "gt", "isvalid", "le", "lt", "ne", + "notify", "uncheckedCast" + }; + bool found = binary_search(&idList[0], + &idList[sizeof(idList) / sizeof(*idList)], + name); + return found ? name + "_" : fixIdent(name); +} + +string +fixExceptionMember(const string& ident) +{ + // + // User exceptions are subclasses of MATLAB's MException class. Subclasses cannot redefine a member that + // conflicts with MException's properties. Unfortunately MException also has some undocumented non-public + // properties that will cause run-time errors. + // + if(ident == "identifier" || + ident == "message" || + ident == "stack" || + ident == "cause" || + ident == "type") // Undocumented + { + return ident + "_"; + } + + return fixIdent(ident); +} + +string +fixStructMember(const string& ident) +{ + // + // We define eq() and ne() methods for structures. + // + if(ident == "eq" || ident == "ne") + { + return ident + "_"; + } + + return fixIdent(ident); +} + +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; +} + +void +writeCopyright(IceUtilInternal::Output& out, const string& file) +{ + string f = file; + string::size_type pos = f.find_last_of("/"); + if(pos != string::npos) + { + f = f.substr(pos + 1); + } + + out << nl << "% Copyright (c) 2003-2017 ZeroC, Inc. All rights reserved."; + out << nl << "% Generated from " << f << " by slice2matlab version " << ICE_STRING_VERSION; + out << nl; +} + +void +openClass(const string& abs, const string& dir, IceUtilInternal::Output& out) +{ + vector<string> v = splitAbsoluteName(abs); + assert(v.size() > 1); + + string path; + if(!dir.empty()) + { + path = dir + "/"; + } + + // + // Create a package directory corresponding to each component. + // + 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); + FileTracker::instance()->addFile(path); +} + +// +// 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()) +{ + string str = fixIdent(cont->scope() + pfx + cont->name() + suffix); + if(str.find("::") == 0) + { + str.erase(0, 2); + } + + return replace(str, "::", "."); +} + +string +typeToString(const TypePtr& type) +{ + static const char* builtinTable[] = + { + "uint8", + "logical", + "int16", + "int32", + "int64", + "single", + "double", + "char", + "Ice.Object", // Object + "Ice.ObjectPrx", // ObjectPrx + "any", // LocalObject + "Ice.Value" // 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) + { + if(!StructPtr::dynamicCast(dict->keyType())) + { + return "containers.Map"; + } + } + + 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) +{ + if(optional || SequencePtr::dynamicCast(type) || ProxyPtr::dynamicCast(type) || ClassDeclPtr::dynamicCast(type)) + { + return false; + } + + BuiltinPtr b = BuiltinPtr::dynamicCast(type); + if(b && (b->kind() == Builtin::KindObject || b->kind() == Builtin::KindObjectProxy || + b->kind() == Builtin::KindValue)) + { + return false; + } + + return true; +} + +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 "Ice.Unset"; + } + 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) + { + const TypePtr key = dict->keyType(); + const TypePtr value = dict->valueType(); + if(StructPtr::dynamicCast(key)) + { + // + // We use a struct array when the key is a structure type because we can't use containers.Map. + // + return "struct('key', {}, 'value', {})"; + } + else + { + ostringstream ostr; + ostr << "containers.Map('KeyType', '" << dictionaryTypeToString(key, true) << "', 'ValueType', '" + << dictionaryTypeToString(value, false) << "')"; + return ostr.str(); + } + } + + EnumPtr en = EnumPtr::dynamicCast(m->type()); + if(en) + { + const EnumeratorList enumerators = en->enumerators(); + return getAbsolute(*enumerators.begin()); + } + + StructPtr st = StructPtr::dynamicCast(m->type()); + if(st) + { + return getAbsolute(st) + "()"; + } + + return "[]"; + } +} + +bool +isClass(const TypePtr& type) +{ + BuiltinPtr b = BuiltinPtr::dynamicCast(type); + ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type); + return (b && (b->kind() == Builtin::KindObject || b->kind() == Builtin::KindValue)) || cl; +} + +bool +isProxy(const TypePtr& type) +{ + BuiltinPtr b = BuiltinPtr::dynamicCast(type); + ProxyPtr p = ProxyPtr::dynamicCast(type); + return (b && b->kind() == Builtin::KindObjectProxy) || p; +} + +bool +needsConversion(const TypePtr& type) +{ + SequencePtr seq = SequencePtr::dynamicCast(type); + if(seq) + { + return isClass(seq->type()) || needsConversion(seq->type()); + } + + StructPtr st = StructPtr::dynamicCast(type); + if(st) + { + const DataMemberList members = st->dataMembers(); + for(DataMemberList::const_iterator q = members.begin(); q != members.end(); ++q) + { + if(needsConversion((*q)->type()) || isClass((*q)->type())) + { + return true; + } + } + return false; + } + + DictionaryPtr d = DictionaryPtr::dynamicCast(type); + if(d) + { + return needsConversion(d->valueType()) || isClass(d->valueType()); + } + + return false; +} + +void +convertValueType(IceUtilInternal::Output& out, const string& dest, const string& src, const TypePtr& type, + bool optional) +{ + assert(needsConversion(type)); + + if(optional) + { + out << nl << "if " << src << " ~= Ice.Unset"; + out.inc(); + } + + SequencePtr seq = SequencePtr::dynamicCast(type); + if(seq) + { + out << nl << dest << " = " << getAbsolute(seq) << ".convert(" << src << ");"; + } + + DictionaryPtr d = DictionaryPtr::dynamicCast(type); + if(d) + { + out << nl << dest << " = " << getAbsolute(d) << ".convert(" << src << ");"; + } + + StructPtr st = StructPtr::dynamicCast(type); + if(st) + { + out << nl << dest << " = " << src << ".ice_convert();"; + } + + if(optional) + { + out.dec(); + out << nl << "end"; + } +} + +void +trimLines(StringList& l) +{ + // + // Remove empty trailing lines. + // + while(!l.empty() && l.back().empty()) + { + l.pop_back(); + } +} + +StringList +splitComment(const string& c) +{ + string comment = c; + + // + // Strip HTML markup and javadoc links -- MATLAB doesn't display them. + // + string::size_type pos = 0; + do + { + pos = comment.find('<', pos); + if(pos != string::npos) + { + string::size_type endpos = comment.find('>', pos); + if(endpos == string::npos) + { + break; + } + comment.erase(pos, endpos - pos + 1); + } + } + while(pos != string::npos); + + const string link = "{@link"; + pos = 0; + do + { + pos = comment.find(link, pos); + if(pos != string::npos) + { + comment.erase(pos, link.size() + 1); // Erase trailing white space too. + string::size_type endpos = comment.find('}', pos); + if(endpos != string::npos) + { + string ident = comment.substr(pos, endpos - pos); + comment.erase(pos, endpos - pos + 1); + + // + // Check for links of the form {@link Type#member}. + // + string::size_type hash = ident.find('#'); + string rest; + if(hash != string::npos) + { + rest = ident.substr(hash + 1); + ident = ident.substr(0, hash); + if(!ident.empty()) + { + ident = fixIdent(ident); + if(!rest.empty()) + { + ident += "." + fixIdent(rest); + } + } + else if(!rest.empty()) + { + ident = fixIdent(rest); + } + } + else + { + ident = fixIdent(ident); + } + + comment.insert(pos, ident); + } + } + } + while(pos != string::npos); + + StringList result; + + pos = 0; + string::size_type nextPos; + while((nextPos = comment.find_first_of('\n', pos)) != string::npos) + { + result.push_back(IceUtilInternal::trim(string(comment, pos, nextPos - pos))); + pos = nextPos + 1; + } + string lastLine = IceUtilInternal::trim(string(comment, pos)); + if(!lastLine.empty()) + { + result.push_back(lastLine); + } + + trimLines(result); + + return result; +} + +bool +parseCommentLine(const string& l, const string& tag, bool namedTag, string& name, string& doc) +{ + doc.clear(); + + if(l.find(tag) == 0) + { + const string ws = " \t"; + + if(namedTag) + { + string::size_type n = l.find_first_not_of(ws, tag.size()); + if(n == string::npos) + { + return false; // Malformed line, ignore it. + } + string::size_type end = l.find_first_of(ws, n); + if(end == string::npos) + { + return false; // Malformed line, ignore it. + } + name = l.substr(n, end - n); + n = l.find_first_not_of(ws, end); + if(n != string::npos) + { + doc = l.substr(n); + } + } + else + { + name.clear(); + + string::size_type n = l.find_first_not_of(ws, tag.size()); + if(n == string::npos) + { + return false; // Malformed line, ignore it. + } + doc = l.substr(n); + } + + return true; + } + + return false; +} + +struct DocElements +{ + StringList overview; + bool deprecated; + StringList deprecateReason; + StringList misc; + StringList seeAlso; + StringList returns; + map<string, StringList> params; + map<string, StringList> exceptions; +}; + +DocElements +parseComment(const ContainedPtr& p) +{ + DocElements doc; + + doc.deprecated = false; + + // + // First check metadata for a deprecated tag. + // + string deprecateMetadata; + if(p->findMetaData("deprecate", deprecateMetadata)) + { + doc.deprecated = true; + if(deprecateMetadata.find("deprecate:") == 0 && deprecateMetadata.size() > 10) + { + doc.deprecateReason.push_back(IceUtilInternal::trim(deprecateMetadata.substr(10))); + } + } + + // + // Split up the comment into lines. + // + StringList lines = splitComment(p->comment()); + + StringList::const_iterator i; + for(i = lines.begin(); i != lines.end(); ++i) + { + const string l = *i; + if(l[0] == '@') + { + break; + } + doc.overview.push_back(l); + } + + enum State { StateMisc, StateParam, StateThrows, StateReturn, StateDeprecated }; + State state = StateMisc; + string name; + const string ws = " \t"; + const string paramTag = "@param"; + const string throwsTag = "@throws"; + const string exceptionTag = "@exception"; + const string returnTag = "@return"; + const string deprecatedTag = "@deprecated"; + const string seeTag = "@see"; + for(; i != lines.end(); ++i) + { + const string l = IceUtilInternal::trim(*i); + string line; + if(parseCommentLine(l, paramTag, true, name, line)) + { + if(!line.empty()) + { + state = StateParam; + StringList sl; + sl.push_back(line); // The first line of the description. + doc.params[name] = sl; + } + } + else if(parseCommentLine(l, throwsTag, true, name, line)) + { + if(!line.empty()) + { + state = StateThrows; + StringList sl; + sl.push_back(line); // The first line of the description. + doc.exceptions[name] = sl; + } + } + else if(parseCommentLine(l, exceptionTag, true, name, line)) + { + if(!line.empty()) + { + state = StateThrows; + StringList sl; + sl.push_back(line); // The first line of the description. + doc.exceptions[name] = sl; + } + } + else if(parseCommentLine(l, seeTag, false, name, line)) + { + if(!line.empty()) + { + doc.seeAlso.push_back(line); + } + } + else if(parseCommentLine(l, returnTag, false, name, line)) + { + if(!line.empty()) + { + state = StateReturn; + doc.returns.push_back(line); // The first line of the description. + } + } + else if(parseCommentLine(l, deprecatedTag, false, name, line)) + { + doc.deprecated = true; + if(!line.empty()) + { + state = StateDeprecated; + doc.deprecateReason.push_back(line); // The first line of the description. + } + } + else if(!l.empty()) + { + if(l[0] == '@') + { + // + // Treat all other tags as miscellaneous comments. + // + state = StateMisc; + } + + switch(state) + { + case StateMisc: + { + doc.misc.push_back(l); + break; + } + case StateParam: + { + assert(!name.empty()); + StringList sl; + if(doc.params.find(name) != doc.params.end()) + { + sl = doc.params[name]; + } + sl.push_back(l); + doc.params[name] = sl; + break; + } + case StateThrows: + { + assert(!name.empty()); + StringList sl; + if(doc.exceptions.find(name) != doc.exceptions.end()) + { + sl = doc.exceptions[name]; + } + sl.push_back(l); + doc.exceptions[name] = sl; + break; + } + case StateReturn: + { + doc.returns.push_back(l); + break; + } + case StateDeprecated: + { + doc.deprecateReason.push_back(l); + break; + } + } + } + } + + trimLines(doc.overview); + trimLines(doc.deprecateReason); + trimLines(doc.misc); + trimLines(doc.returns); + + return doc; +} + +void +writeDocLines(IceUtilInternal::Output& out, const StringList& lines, bool commentFirst, const string& space = " ") +{ + StringList l = lines; + if(!commentFirst) + { + out << l.front(); + l.pop_front(); + } + for(StringList::const_iterator i = l.begin(); i != l.end(); ++i) + { + out << nl << "%"; + if(!i->empty()) + { + out << space << *i; + } + } +} + +void +writeDocSentence(IceUtilInternal::Output& out, const StringList& lines) +{ + // + // Write the first sentence. + // + for(StringList::const_iterator i = lines.begin(); i != lines.end(); ++i) + { + const string ws = " \t"; + + if(i->empty()) + { + break; + } + if(i != lines.begin() && i->find_first_not_of(ws) == 0) + { + out << " "; + } + string::size_type pos = i->find('.'); + if(pos == string::npos) + { + out << *i; + } + else if(pos == i->size() - 1) + { + out << *i; + break; + } + else + { + // + // Assume a period followed by whitespace indicates the end of the sentence. + // + while(pos != string::npos) + { + if(ws.find((*i)[pos + 1]) != string::npos) + { + break; + } + pos = i->find('.', pos + 1); + } + if(pos != string::npos) + { + out << i->substr(0, pos + 1); + break; + } + else + { + out << *i; + } + } + } +} + +void +writeSeeAlso(IceUtilInternal::Output& out, const StringList& seeAlso, const ContainerPtr& container) +{ + assert(!seeAlso.empty()); + // + // All references must be on one line. + // + out << nl << "% See also "; + for(StringList::const_iterator p = seeAlso.begin(); p != seeAlso.end(); ++p) + { + if(p != seeAlso.begin()) + { + out << ", "; + } + + string sym = *p; + string rest; + string::size_type pos = sym.find('#'); + if(pos != string::npos) + { + rest = sym.substr(pos + 1); + sym = sym.substr(0, pos); + } + + if(!sym.empty() || !rest.empty()) + { + if(!sym.empty()) + { + ContainedList c = container->lookupContained(sym, false); + if(c.empty()) + { + out << sym; + } + else + { + out << getAbsolute(c.front()); + } + + if(!rest.empty()) + { + out << "."; + } + } + + if(!rest.empty()) + { + out << rest; + } + } + } +} + +void +writeDocSummary(IceUtilInternal::Output& out, const ContainedPtr& p) +{ + DocElements doc = parseComment(p); + + string n = fixIdent(p->name()); + + // + // No leading newline. + // + out << "% " << n << " Summary of " << n; + + if(!doc.overview.empty()) + { + out << nl << "%"; + writeDocLines(out, doc.overview, true); + } + + if(p->containedType() == Contained::ContainedTypeEnum) + { + out << nl << "%"; + out << nl << "% " << n << " Properties:"; + EnumPtr en = EnumPtr::dynamicCast(p); + const EnumeratorList el = en->enumerators(); + for(EnumeratorList::const_iterator q = el.begin(); q != el.end(); ++q) + { + StringList sl = splitComment((*q)->comment()); + out << nl << "% " << fixEnumerator((*q)->name()); + if(!sl.empty()) + { + out << " - "; + writeDocSentence(out, sl); + } + } + } + else if(p->containedType() == Contained::ContainedTypeStruct) + { + out << nl << "%"; + out << nl << "% " << n << " Properties:"; + StructPtr st = StructPtr::dynamicCast(p); + const DataMemberList dml = st->dataMembers(); + for(DataMemberList::const_iterator q = dml.begin(); q != dml.end(); ++q) + { + StringList sl = splitComment((*q)->comment()); + out << nl << "% " << fixIdent((*q)->name()); + if(!sl.empty()) + { + out << " - "; + writeDocSentence(out, sl); + } + } + } + else if(p->containedType() == Contained::ContainedTypeException) + { + ExceptionPtr ex = ExceptionPtr::dynamicCast(p); + const DataMemberList dml = ex->dataMembers(); + if(!dml.empty()) + { + out << nl << "%"; + out << nl << "% " << n << " Properties:"; + for(DataMemberList::const_iterator q = dml.begin(); q != dml.end(); ++q) + { + StringList sl = splitComment((*q)->comment()); + out << nl << "% " << fixExceptionMember((*q)->name()); + if(!sl.empty()) + { + out << " - "; + writeDocSentence(out, sl); + } + } + } + } + else if(p->containedType() == Contained::ContainedTypeClass) + { + ClassDefPtr cl = ClassDefPtr::dynamicCast(p); + const DataMemberList dml = cl->dataMembers(); + if(!dml.empty()) + { + out << nl << "%"; + out << nl << "% " << n << " Properties:"; + for(DataMemberList::const_iterator q = dml.begin(); q != dml.end(); ++q) + { + StringList sl = splitComment((*q)->comment()); + out << nl << "% " << fixIdent((*q)->name()); + if(!sl.empty()) + { + out << " - "; + writeDocSentence(out, sl); + } + } + } + } + + if(!doc.misc.empty()) + { + out << nl << "%"; + writeDocLines(out, doc.misc, true); + } + + if(!doc.seeAlso.empty()) + { + out << nl << "%"; + writeSeeAlso(out, doc.seeAlso, p->container()); + } + + if(!doc.deprecateReason.empty()) + { + out << nl << "%"; + out << nl << "% Deprecated: "; + writeDocLines(out, doc.deprecateReason, false); + } + else if(doc.deprecated) + { + out << nl << "%"; + out << nl << "% Deprecated"; + } + + out << nl; +} + +void +writeOpDocSummary(IceUtilInternal::Output& out, const OperationPtr& p, bool async) +{ + DocElements doc = parseComment(p); + + out << nl << "% " << (async ? p->name() + "Async" : fixOp(p->name())); + + if(!doc.overview.empty()) + { + out << " "; + writeDocLines(out, doc.overview, false); + } + + out << nl << "%"; + out << nl << "% Parameters:"; + const ParamDeclList inParams = p->inParameters(); + string ctxName = "context"; + string resultName = "result"; + for(ParamDeclList::const_iterator q = inParams.begin(); q != inParams.end(); ++q) + { + if((*q)->name() == "context") + { + ctxName = "context_"; + } + if((*q)->name() == "result") + { + resultName = "result_"; + } + + out << nl << "% " << fixIdent((*q)->name()) << " (" << typeToString((*q)->type()) << ")"; + map<string, StringList>::const_iterator r = doc.params.find((*q)->name()); + if(r != doc.params.end() && !r->second.empty()) + { + out << " - "; + writeDocLines(out, r->second, false, " "); + } + } + out << nl << "% " << ctxName << " (containers.Map) - Optional request context."; + + if(async) + { + out << nl << "%"; + out << nl << "% Returns (Ice.Future) - A future that will be completed with the results of the invocation."; + } + else + { + const ParamDeclList outParams = p->outParameters(); + if(p->returnType() || !outParams.empty()) + { + for(ParamDeclList::const_iterator q = outParams.begin(); q != outParams.end(); ++q) + { + if((*q)->name() == "result") + { + resultName = "result_"; + } + } + + out << nl << "%"; + if(p->returnType() && outParams.empty()) + { + out << nl << "% Returns (" << typeToString(p->returnType()) << ")"; + if(!doc.returns.empty()) + { + out << " - "; + writeDocLines(out, doc.returns, false); + } + } + else if(!p->returnType() && outParams.size() == 1) + { + out << nl << "% Returns (" << typeToString(outParams.front()->type()) << ")"; + map<string, StringList>::const_iterator q = doc.params.find(outParams.front()->name()); + if(q != doc.params.end() && !q->second.empty()) + { + out << " - "; + writeDocLines(out, q->second, false); + } + } + else + { + out << nl << "% Returns:"; + if(p->returnType()) + { + out << nl << "% " << resultName << " (" << typeToString(p->returnType()) << ")"; + if(!doc.returns.empty()) + { + out << " - "; + writeDocLines(out, doc.returns, false, " "); + } + } + for(ParamDeclList::const_iterator q = outParams.begin(); q != outParams.end(); ++q) + { + out << nl << "% " << fixIdent((*q)->name()) << " (" << typeToString((*q)->type()) << ")"; + map<string, StringList>::const_iterator r = doc.params.find((*q)->name()); + if(r != doc.params.end() && !r->second.empty()) + { + out << " - "; + writeDocLines(out, r->second, false, " "); + } + } + } + } + } + + if(!doc.exceptions.empty()) + { + out << nl << "%"; + out << nl << "% Exceptions:"; + for(map<string, StringList>::const_iterator q = doc.exceptions.begin(); q != doc.exceptions.end(); ++q) + { + // + // Try to find the exception based on the name given in the doc comment. + // + out << nl << "% "; + ExceptionPtr ex = p->container()->lookupException(q->first, false); + if(ex) + { + out << getAbsolute(ex); + } + else + { + out << q->first; + } + if(!q->second.empty()) + { + out << " - "; + writeDocLines(out, q->second, false, " "); + } + } + } + + if(!doc.misc.empty()) + { + out << nl << "%"; + writeDocLines(out, doc.misc, true); + } + + if(!doc.seeAlso.empty()) + { + out << nl << "%"; + writeSeeAlso(out, doc.seeAlso, p->container()); + } + + if(!doc.deprecateReason.empty()) + { + out << nl << "%"; + out << nl << "% Deprecated: "; + writeDocLines(out, doc.deprecateReason, false); + } + else if(doc.deprecated) + { + out << nl << "%"; + out << nl << "% Deprecated"; + } + + out << nl; +} + +void +writeProxyDocSummary(IceUtilInternal::Output& out, const ClassDefPtr& p) +{ + DocElements doc = parseComment(p); + + string n = p->name() + "Prx"; + + // + // No leading newline. + // + out << "% " << n << " Summary of " << n; + + if(!doc.overview.empty()) + { + out << nl << "%"; + writeDocLines(out, doc.overview, true); + } + + out << nl << "%"; + out << nl << "% " << n << " Methods:"; + const OperationList ops = p->operations(); + if(!ops.empty()) + { + for(OperationList::const_iterator q = ops.begin(); q != ops.end(); ++q) + { + OperationPtr op = *q; + DocElements opdoc = parseComment(op); + out << nl << "% " << fixOp(op->name()); + if(!opdoc.overview.empty()) + { + out << " - "; + writeDocSentence(out, opdoc.overview); + } + out << nl << "% " << op->name() << "Async"; + if(!opdoc.overview.empty()) + { + out << " - "; + writeDocSentence(out, opdoc.overview); + } + } + } + out << nl << "% checkedCast - Contacts the remote server to verify that the object implements this type."; + out << nl << "% uncheckedCast - Downcasts the given proxy to this type without contacting the remote server."; + + if(!doc.misc.empty()) + { + out << nl << "%"; + writeDocLines(out, doc.misc, true); + } + + if(!doc.seeAlso.empty()) + { + out << nl << "%"; + writeSeeAlso(out, doc.seeAlso, p->container()); + } + + if(!doc.deprecateReason.empty()) + { + out << nl << "%"; + out << nl << "% Deprecated: "; + writeDocLines(out, doc.deprecateReason, false); + } + else if(doc.deprecated) + { + out << nl << "%"; + out << nl << "% Deprecated"; + } + + out << nl; +} + +void +writeMemberDoc(IceUtilInternal::Output& out, const DataMemberPtr& p) +{ + DocElements doc = parseComment(p); + + // + // Skip if there are no doc comments. + // + if(doc.overview.empty() && doc.misc.empty() && doc.seeAlso.empty() && doc.deprecateReason.empty() && + !doc.deprecated) + { + return; + } + + string n; + + ContainedPtr cont = ContainedPtr::dynamicCast(p->container()); + if(cont->containedType() == Contained::ContainedTypeException) + { + n = fixExceptionMember(p->name()); + } + else + { + n = fixIdent(p->name()); + } + + out << nl << "% " << n; + + if(!doc.overview.empty()) + { + out << " - "; + writeDocLines(out, doc.overview, false); + } + + if(!doc.misc.empty()) + { + out << nl << "%"; + writeDocLines(out, doc.misc, true); + } + + if(!doc.seeAlso.empty()) + { + out << nl << "%"; + writeSeeAlso(out, doc.seeAlso, p->container()); + } + + if(!doc.deprecateReason.empty()) + { + out << nl << "%"; + out << nl << "% Deprecated: "; + writeDocLines(out, doc.deprecateReason, false); + } + else if(doc.deprecated) + { + out << nl << "%"; + out << nl << "% Deprecated"; + } +} + +} + +// +// 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: + + 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; + int pos; // Only used for out params + ParamDeclPtr param; // 0 == return value + }; + typedef list<ParamInfo> ParamInfoList; + + ParamInfoList getAllInParams(const OperationPtr&); + void getInParams(const OperationPtr&, ParamInfoList&, ParamInfoList&); + ParamInfoList getAllOutParams(const OperationPtr&); + void getOutParams(const OperationPtr&, ParamInfoList&, ParamInfoList&); + + string getOptionalFormat(const TypePtr&); + string getFormatType(FormatType); + + void marshal(IceUtilInternal::Output&, const string&, const string&, const TypePtr&, bool, int); + void unmarshal(IceUtilInternal::Output&, const string&, const string&, const TypePtr&, bool, int); + + void unmarshalStruct(IceUtilInternal::Output&, const StructPtr&, const string&); + void convertStruct(IceUtilInternal::Output&, const StructPtr&, const string&); + + const string _dir; +}; + +// +// CodeVisitor implementation. +// +CodeVisitor::CodeVisitor(const string& dir) : + _dir(dir) +{ +} + +bool +CodeVisitor::visitClassDefStart(const ClassDefPtr& p) +{ + if(p->hasMetaData("matlab:internal")) + { + return false; + } + + const string name = fixIdent(p->name()); + const string scoped = p->scoped(); + const string abs = getAbsolute(p); + const ClassList bases = p->bases(); + const OperationList allOps = p->allOperations(); + const string self = name == "obj" ? "this" : "obj"; + + if(!p->isInterface()) + { + ClassDefPtr base; + if(!bases.empty() && !bases.front()->isInterface()) + { + base = bases.front(); + } + + IceUtilInternal::Output out; + openClass(abs, _dir, out); + + writeDocSummary(out, p); + writeCopyright(out, p->file()); + + out << nl << "classdef "; + if(p->isLocal() && !allOps.empty()) + { + out << "(Abstract) "; + } + out << name; + if(base) + { + out << " < " << getAbsolute(base); + } + else if(!p->isLocal()) + { + out << " < Ice.Value"; + } + else + { + out << " < matlab.mixin.Copyable"; + } + + out.inc(); + + const DataMemberList members = p->dataMembers(); + if(!members.empty()) + { + if(p->hasMetaData("protected")) + { + // + // All members are protected. + // + out << nl << "properties(Access=protected)"; + out.inc(); + for(DataMemberList::const_iterator q = members.begin(); q != members.end(); ++q) + { + writeMemberDoc(out, *q); + out << nl << fixIdent((*q)->name()); + if(declarePropertyType((*q)->type(), (*q)->optional())) + { + out << " " << typeToString((*q)->type()); + } + } + out.dec(); + out << nl << "end"; + } + else + { + DataMemberList prot, pub; + for(DataMemberList::const_iterator q = members.begin(); q != members.end(); ++q) + { + if((*q)->hasMetaData("protected")) + { + prot.push_back(*q); + } + else + { + pub.push_back(*q); + } + } + if(!pub.empty()) + { + out << nl << "properties"; + out.inc(); + for(DataMemberList::const_iterator q = pub.begin(); q != pub.end(); ++q) + { + writeMemberDoc(out, *q); + out << nl << fixIdent((*q)->name()); + if(declarePropertyType((*q)->type(), (*q)->optional())) + { + out << " " << typeToString((*q)->type()); + } + } + out.dec(); + out << nl << "end"; + } + if(!prot.empty()) + { + out << nl << "properties(Access=protected)"; + out.inc(); + for(DataMemberList::const_iterator q = prot.begin(); q != prot.end(); ++q) + { + writeMemberDoc(out, *q); + out << nl << fixIdent((*q)->name()); + if(declarePropertyType((*q)->type(), (*q)->optional())) + { + out << " " << typeToString((*q)->type()); + } + } + out.dec(); + out << nl << "end"; + } + } + } + + const bool basePreserved = p->inheritsMetaData("preserve-slice"); + const bool preserved = p->hasMetaData("preserve-slice"); + + MemberInfoList allMembers; + collectClassMembers(p, allMembers, false); + + if(!allMembers.empty() || !p->isLocal() || (preserved && !basePreserved)) + { + out << nl << "methods"; + out.inc(); + + // + // Constructor + // + if(!allMembers.empty()) + { + vector<string> allNames; + for(MemberInfoList::const_iterator q = allMembers.begin(); q != allMembers.end(); ++q) + { + allNames.push_back(q->fixedName); + } + 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) + { + out << nl << self << " = " << self << "@" << getAbsolute(base) << 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()) + { + out << nl << "function id = ice_id(obj)"; + out.inc(); + out << nl << "id = obj.ice_staticId();"; + out.dec(); + out << nl << "end"; + + if(preserved && !basePreserved) + { + out << nl << "function r = ice_getSlicedData(obj)"; + out.inc(); + out << nl << "r = obj.iceSlicedData_;"; + out.dec(); + out << nl << "end"; + } + } + + out.dec(); + out << nl << "end"; + } + + if(!p->isLocal()) + { + DataMemberList convertMembers; + for(DataMemberList::const_iterator d = members.begin(); d != members.end(); ++d) + { + if(needsConversion((*d)->type())) + { + convertMembers.push_back(*d); + } + } + + if((preserved && !basePreserved) || !convertMembers.empty()) + { + out << nl << "methods(Hidden=true)"; + out.inc(); + + if(preserved && !basePreserved) + { + out << nl << "function iceWrite(obj, os)"; + out.inc(); + out << nl << "os.startValue(obj.iceSlicedData_);"; + out << nl << "obj.iceWriteImpl(os);"; + out << nl << "os.endValue();"; + out.dec(); + out << nl << "end"; + out << nl << "function iceRead(obj, is)"; + out.inc(); + out << nl << "is.startValue();"; + out << nl << "obj.iceReadImpl(is);"; + out << nl << "obj.iceSlicedData_ = is.endValue(true);"; + out.dec(); + out << nl << "end"; + } + + if(!convertMembers.empty()) + { + out << nl << "function r = iceDelayPostUnmarshal(obj)"; + out.inc(); + out << nl << "r = true;"; + out.dec(); + out << nl << "end"; + out << nl << "function icePostUnmarshal(obj)"; + out.inc(); + for(DataMemberList::const_iterator d = convertMembers.begin(); d != convertMembers.end(); ++d) + { + string m = "obj." + fixIdent((*d)->name()); + convertValueType(out, m, m, (*d)->type(), (*d)->optional()); + } + if(base) + { + out << nl << "icePostUnmarshal@" << getAbsolute(base) << "(obj);"; + } + out.dec(); + out << nl << "end"; + } + + out.dec(); + out << nl << "end"; + } + + out << nl << "methods(Access=protected)"; + out.inc(); + + const DataMemberList optionalMembers = p->orderedOptionalDataMembers(); + + out << nl << "function iceWriteImpl(obj, os)"; + out.inc(); + out << nl << "os.startSlice('" << scoped << "', " << p->compactId() << (!base ? ", true" : ", false") + << ");"; + for(DataMemberList::const_iterator d = members.begin(); d != members.end(); ++d) + { + if(!(*d)->optional()) + { + marshal(out, "os", "obj." + fixIdent((*d)->name()), (*d)->type(), false, 0); + } + } + for(DataMemberList::const_iterator d = optionalMembers.begin(); d != optionalMembers.end(); ++d) + { + marshal(out, "os", "obj." + fixIdent((*d)->name()), (*d)->type(), true, (*d)->tag()); + } + out << nl << "os.endSlice();"; + if(base) + { + out << nl << "iceWriteImpl@" << getAbsolute(base) << "(obj, os);"; + } + out.dec(); + out << nl << "end"; + out << nl << "function iceReadImpl(obj, is)"; + out.inc(); + out << nl << "is.startSlice();"; + for(DataMemberList::const_iterator d = members.begin(); d != members.end(); ++d) + { + if(!(*d)->optional()) + { + if(isClass((*d)->type())) + { + unmarshal(out, "is", "@obj.iceSetMember_" + fixIdent((*d)->name()), (*d)->type(), false, 0); + } + else + { + unmarshal(out, "is", "obj." + fixIdent((*d)->name()), (*d)->type(), false, 0); + } + } + } + for(DataMemberList::const_iterator d = optionalMembers.begin(); d != optionalMembers.end(); ++d) + { + if(isClass((*d)->type())) + { + unmarshal(out, "is", "@obj.iceSetMember_" + fixIdent((*d)->name()), (*d)->type(), true, + (*d)->tag()); + } + else + { + unmarshal(out, "is", "obj." + fixIdent((*d)->name()), (*d)->type(), true, (*d)->tag()); + } + } + out << nl << "is.endSlice();"; + if(base) + { + out << nl << "iceReadImpl@" << getAbsolute(base) << "(obj, is);"; + } + out.dec(); + out << nl << "end"; + + DataMemberList classMembers = p->classDataMembers(); + if(!classMembers.empty()) + { + // + // For each class data member, we generate an "iceSetMember_<name>" method that is called when the + // instance is eventually unmarshaled. + // + for(DataMemberList::const_iterator d = classMembers.begin(); d != classMembers.end(); ++d) + { + string m = fixIdent((*d)->name()); + out << nl << "function iceSetMember_" << m << "(obj, v)"; + out.inc(); + out << nl << "obj." << m << " = v;"; + 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.dec(); + out << nl << "end"; + + if(preserved && !basePreserved) + { + out << nl << "properties(Access=protected)"; + out.inc(); + out << nl << "iceSlicedData_"; + out.dec(); + out << nl << "end"; + } + } + else + { + const OperationList ops = p->operations(); + if(!ops.empty()) + { + out << nl << "methods(Abstract)"; + out.inc(); + for(OperationList::const_iterator q = ops.begin(); q != ops.end(); ++q) + { + OperationPtr op = *q; + const ParamInfoList outParams = getAllOutParams(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 << fixOp(op->name()) << spar << "obj_"; + const ParamInfoList inParams = getAllInParams(op); + 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(); + + if(p->compactId() >= 0) + { + ostringstream ostr; + ostr << "IceCompactId.TypeId_" << p->compactId(); + + openClass(ostr.str(), _dir, out); + + out << nl << "classdef TypeId_" << p->compactId(); + out.inc(); + + out << nl << "properties(Constant)"; + out.inc(); + out << nl << "typeId = '" << scoped << "'"; + out.dec(); + out << nl << "end"; + + out.dec(); + out << nl << "end"; + out << nl; + + out.close(); + } + } + + if(!p->isLocal() && (p->isInterface() || (!p->isInterface() && !allOps.empty()))) + { + // + // Generate proxy class. + // + + const string prxName = p->name() + "Prx"; + const string prxAbs = getAbsolute(p, "", "Prx"); + + ClassList prxBases = bases; + // + // For proxy purposes, we can ignore a base class if it has no operations. + // + if(!prxBases.empty() && !prxBases.front()->isInterface() && prxBases.front()->allOperations().empty()) + { + prxBases.pop_front(); + } + + IceUtilInternal::Output out; + openClass(prxAbs, _dir, out); + + writeProxyDocSummary(out, p); + writeCopyright(out, p->file()); + + out << nl << "classdef " << prxName << " < "; + if(!prxBases.empty()) + { + for(ClassList::const_iterator q = prxBases.begin(); q != prxBases.end(); ++q) + { + if(q != prxBases.begin()) + { + out << " & "; + } + out << getAbsolute(*q, "", "Prx"); + } + } + else + { + out << "Ice.ObjectPrx"; + } + + out.inc(); + + out << nl << "methods"; + out.inc(); + + // + // Operations. + // + bool hasExceptions = false; + const OperationList ops = p->operations(); + for(OperationList::const_iterator q = ops.begin(); q != ops.end(); ++q) + { + OperationPtr op = *q; + ParamInfoList requiredInParams, optionalInParams; + getInParams(op, requiredInParams, optionalInParams); + ParamInfoList requiredOutParams, optionalOutParams; + getOutParams(op, requiredOutParams, optionalOutParams); + const ParamInfoList allInParams = getAllInParams(op); + const ParamInfoList allOutParams = getAllOutParams(op); + const bool twowayOnly = op->returnsData(); + const ExceptionList exceptions = op->throws(); + + if(!exceptions.empty()) + { + hasExceptions = true; + } + + // + // Ensure no parameter is named "obj". + // + string self = "obj"; + for(ParamInfoList::const_iterator r = allOutParams.begin(); r != allOutParams.end(); ++r) + { + if(r->fixedName == "obj") + { + self = "obj_"; + } + } + for(ParamInfoList::const_iterator r = allInParams.begin(); r != allInParams.end(); ++r) + { + if(r->fixedName == "obj") + { + self = "obj_"; + } + } + + // + // Synchronous method. + // + out << nl << "function "; + if(allOutParams.size() > 1) + { + out << "["; + for(ParamInfoList::const_iterator r = allOutParams.begin(); r != allOutParams.end(); ++r) + { + if(r != allOutParams.begin()) + { + out << ", "; + } + out << r->fixedName; + } + out << "] = "; + } + else if(allOutParams.size() == 1) + { + out << allOutParams.begin()->fixedName << " = "; + } + out << fixOp(op->name()) << spar; + + out << self; + for(ParamInfoList::const_iterator r = allInParams.begin(); r != allInParams.end(); ++r) + { + out << r->fixedName; + } + out << "varargin"; // For the optional context + out << epar; + out.inc(); + + writeOpDocSummary(out, op, false); + + if(!allInParams.empty()) + { + if(op->format() == DefaultFormat) + { + out << nl << "os_ = " << self << ".iceStartWriteParams([]);"; + } + else + { + out << nl << "os_ = " << self << ".iceStartWriteParams(" << getFormatType(op->format()) << ");"; + } + for(ParamInfoList::const_iterator r = requiredInParams.begin(); r != requiredInParams.end(); ++r) + { + marshal(out, "os_", r->fixedName, r->type, false, 0); + } + for(ParamInfoList::const_iterator r = optionalInParams.begin(); r != optionalInParams.end(); ++r) + { + marshal(out, "os_", r->fixedName, r->type, r->optional, r->tag); + } + if(op->sendsClasses(false)) + { + out << nl << "os_.writePendingValues();"; + } + out << nl << self << ".iceEndWriteParams(os_);"; + } + + out << nl; + if(!allOutParams.empty()) + { + out << "is_ = "; + } + out << self << ".iceInvoke('" << op->name() << "', " + << getOperationMode(op->sendMode()) << ", " << (twowayOnly ? "true" : "false") + << ", " << (allInParams.empty() ? "[]" : "os_") << ", " << (!allOutParams.empty() ? "true" : "false"); + if(exceptions.empty()) + { + out << ", {}"; + } + else + { + out << ", " << prxAbs << "." << op->name() << "_ex_"; + } + out << ", varargin{:});"; + + if(twowayOnly && !allOutParams.empty()) + { + out << nl << "is_.startEncapsulation();"; + // + // To unmarshal results: + // + // * unmarshal all required out parameters + // * unmarshal the required return value (if any) + // * unmarshal all optional out parameters (this includes an optional return value) + // + ParamInfoList classParams; + ParamInfoList convertParams; + for(ParamInfoList::const_iterator r = requiredOutParams.begin(); r != requiredOutParams.end(); ++r) + { + if(r->param) + { + string name; + if(isClass(r->type)) + { + out << nl << r->fixedName << "_h_ = IceInternal.ValueHolder();"; + name = "@(v) " + r->fixedName + "_h_.set(v)"; + classParams.push_back(*r); + } + else + { + name = r->fixedName; + } + unmarshal(out, "is_", name, r->type, false, -1); + + if(needsConversion(r->type)) + { + convertParams.push_back(*r); + } + } + } + // + // Now do the required return value if necessary. + // + if(!requiredOutParams.empty() && !requiredOutParams.begin()->param) + { + ParamInfoList::const_iterator r = requiredOutParams.begin(); + string name; + if(isClass(r->type)) + { + out << nl << r->fixedName << "_h_ = IceInternal.ValueHolder();"; + name = "@(v) " + r->fixedName + "_h_.set(v)"; + classParams.push_back(*r); + } + else + { + name = r->fixedName; + } + unmarshal(out, "is_", name, r->type, false, -1); + + if(needsConversion(r->type)) + { + convertParams.push_back(*r); + } + } + // + // Now unmarshal all optional out parameters. They are already sorted by tag. + // + for(ParamInfoList::const_iterator r = optionalOutParams.begin(); r != optionalOutParams.end(); ++r) + { + string name; + if(isClass(r->type)) + { + out << nl << r->fixedName << "_h_ = IceInternal.ValueHolder();"; + name = "@(v) " + r->fixedName + "_h_.set(v)"; + classParams.push_back(*r); + } + else + { + name = r->fixedName; + } + unmarshal(out, "is_", name, r->type, r->optional, r->tag); + + if(needsConversion(r->type)) + { + convertParams.push_back(*r); + } + } + if(op->returnsClasses(false)) + { + out << nl << "is_.readPendingValues();"; + } + out << nl << "is_.endEncapsulation();"; + // + // After calling readPendingValues(), all callback functions have been invoked. + // Now we need to collect the values. + // + for(ParamInfoList::const_iterator r = classParams.begin(); r != classParams.end(); ++r) + { + out << nl << r->fixedName << " = " << r->fixedName << "_h_.value;"; + } + + for(ParamInfoList::const_iterator r = convertParams.begin(); r != convertParams.end(); ++r) + { + convertValueType(out, r->fixedName, r->fixedName, r->type, r->optional); + } + } + + out.dec(); + out << nl << "end"; + + // + // Asynchronous method. + // + out << nl << "function r_ = " << op->name() << "Async" << spar; + out << self; + for(ParamInfoList::const_iterator r = allInParams.begin(); r != allInParams.end(); ++r) + { + out << r->fixedName; + } + out << "varargin"; // For the optional context + out << epar; + out.inc(); + + writeOpDocSummary(out, op, true); + + if(!allInParams.empty()) + { + if(op->format() == DefaultFormat) + { + out << nl << "os_ = " << self << ".iceStartWriteParams([]);"; + } + else + { + out << nl << "os_ = " << self << ".iceStartWriteParams(" << getFormatType(op->format()) << ");"; + } + for(ParamInfoList::const_iterator r = requiredInParams.begin(); r != requiredInParams.end(); ++r) + { + marshal(out, "os_", r->fixedName, r->type, false, 0); + } + for(ParamInfoList::const_iterator r = optionalInParams.begin(); r != optionalInParams.end(); ++r) + { + marshal(out, "os_", r->fixedName, r->type, r->optional, r->tag); + } + if(op->sendsClasses(false)) + { + out << nl << "os_.writePendingValues();"; + } + out << nl << self << ".iceEndWriteParams(os_);"; + } + + if(twowayOnly && !allOutParams.empty()) + { + out << nl << "function varargout = unmarshal(is_)"; + out.inc(); + out << nl << "is_.startEncapsulation();"; + // + // To unmarshal results: + // + // * unmarshal all required out parameters + // * unmarshal the required return value (if any) + // * unmarshal all optional out parameters (this includes an optional return value) + // + for(ParamInfoList::const_iterator r = requiredOutParams.begin(); r != requiredOutParams.end(); ++r) + { + if(r->param) + { + string name; + if(isClass(r->type)) + { + out << nl << r->fixedName << " = IceInternal.ValueHolder();"; + name = "@(v) " + r->fixedName + ".set(v)"; + } + else + { + name = r->fixedName; + } + unmarshal(out, "is_", name, r->type, r->optional, r->tag); + } + } + // + // Now do the required return value if necessary. + // + if(!requiredOutParams.empty() && !requiredOutParams.begin()->param) + { + ParamInfoList::const_iterator r = requiredOutParams.begin(); + string name; + if(isClass(r->type)) + { + out << nl << r->fixedName << " = IceInternal.ValueHolder();"; + name = "@(v) " + r->fixedName + ".set(v)"; + } + else + { + name = r->fixedName; + } + unmarshal(out, "is_", name, r->type, false, -1); + } + // + // Now unmarshal all optional out parameters. They are already sorted by tag. + // + for(ParamInfoList::const_iterator r = optionalOutParams.begin(); r != optionalOutParams.end(); ++r) + { + string name; + if(isClass(r->type)) + { + out << nl << r->fixedName << " = IceInternal.ValueHolder();"; + name = "@(v) " + r->fixedName + ".set(v)"; + } + else + { + name = r->fixedName; + } + unmarshal(out, "is_", name, r->type, r->optional, r->tag); + } + if(op->returnsClasses(false)) + { + out << nl << "is_.readPendingValues();"; + } + out << nl << "is_.endEncapsulation();"; + for(ParamInfoList::const_iterator r = requiredOutParams.begin(); r != requiredOutParams.end(); ++r) + { + if(isClass(r->type)) + { + out << nl << "varargout{" << r->pos << "} = " << r->fixedName << ".value;"; + } + else if(needsConversion(r->type)) + { + ostringstream dest; + dest << "varargout{" << r->pos << "}"; + convertValueType(out, dest.str(), r->fixedName, r->type, r->optional); + } + else + { + out << nl << "varargout{" << r->pos << "} = " << r->fixedName << ';'; + } + } + for(ParamInfoList::const_iterator r = optionalOutParams.begin(); r != optionalOutParams.end(); ++r) + { + if(isClass(r->type)) + { + out << nl << "varargout{" << r->pos << "} = " << r->fixedName << ".value;"; + } + else if(needsConversion(r->type)) + { + ostringstream dest; + dest << "varargout{" << r->pos << "}"; + convertValueType(out, dest.str(), r->fixedName, r->type, r->optional); + } + else + { + out << nl << "varargout{" << r->pos << "} = " << r->fixedName << ';'; + } + } + out.dec(); + out << nl << "end"; + } + + out << nl << "r_ = " << self << ".iceInvokeAsync('" << op->name() << "', " + << getOperationMode(op->sendMode()) << ", " << (twowayOnly ? "true" : "false") << ", " + << (allInParams.empty() ? "[]" : "os_") << ", " << allOutParams.size() << ", " + << (twowayOnly && !allOutParams.empty() ? "@unmarshal" : "[]"); + if(exceptions.empty()) + { + out << ", {}"; + } + else + { + out << ", " << prxAbs << "." << op->name() << "_ex_"; + } + 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 = is.readProxy('" << prxAbs << "');"; + out.dec(); + out << nl << "end"; + out << nl << "function r = checkedCast(p, varargin)"; + out.inc(); + out << nl << "% checkedCast Contacts the remote server to verify that the object implements this type."; + out << nl << "% Raises a local exception if a communication error occurs. You can optionally supply a"; + out << nl << "% facet name and a context map."; + out << nl << "%"; + out << nl << "% Parameters:"; + out << nl << "% p - The proxy to be cast."; + out << nl << "% facet - The optional name of the desired facet."; + out << nl << "% context - The optional context map to send with the invocation."; + out << nl << "%"; + out << nl << "% Returns (" << prxAbs << ") - A proxy for this type, or an empty array if the object" + << " does not support this type."; + out << nl << "r = Ice.ObjectPrx.iceCheckedCast(p, " << prxAbs << ".ice_staticId(), '" << prxAbs + << "', varargin{:});"; + out.dec(); + out << nl << "end"; + out << nl << "function r = uncheckedCast(p, varargin)"; + out.inc(); + out << nl << "% uncheckedCast Downcasts the given proxy to this type without contacting the remote server."; + out << nl << "% You can optionally specify a facet name."; + out << nl << "%"; + out << nl << "% Parameters:"; + out << nl << "% p - The proxy to be cast."; + out << nl << "% facet - The optional name of the desired facet."; + out << nl << "%"; + out << nl << "% Returns (" << prxAbs << ") - A proxy for this type."; + out << nl << "r = Ice.ObjectPrx.iceUncheckedCast(p, '" << prxAbs << "', varargin{:});"; + out.dec(); + out << nl << "end"; + out.dec(); + out << nl << "end"; + + // + // Constructor. + // + out << nl << "methods(Hidden=true)"; + out.inc(); + out << nl << "function obj = " << prxName << "(communicator, encoding, impl, bytes)"; + out.inc(); + if(!bases.empty()) + { + for(ClassList::const_iterator q = bases.begin(); q != bases.end(); ++q) + { + out << nl << "obj = obj@" << getAbsolute(*q, "", "Prx") << "(communicator, encoding, impl, bytes);"; + } + } + else + { + out << nl << "obj = obj@Ice.ObjectPrx(communicator, encoding, impl, bytes);"; + } + out.dec(); + out << nl << "end"; + out.dec(); + out << nl << "end"; + + if(hasExceptions) + { + // + // Generate a constant property for each operation that throws user exceptions. The property is + // a cell array containing the class names of the exceptions. + // + out << nl << "properties(Constant,Access=private)"; + out.inc(); + for(OperationList::const_iterator q = ops.begin(); q != ops.end(); ++q) + { + OperationPtr op = *q; + 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 + + if(!exceptions.empty()) + { + out << nl << op->name() << "_ex_ = { "; + for(ExceptionList::const_iterator e = exceptions.begin(); e != exceptions.end(); ++e) + { + if(e != exceptions.begin()) + { + out << ", "; + } + out << "'" + getAbsolute(*e) + "'"; + } + out << " }"; + } + } + out.dec(); + out << nl << "end"; + } + + out.dec(); + out << nl << "end"; + out << nl; + + out.close(); + } + + if(p->isLocal()) + { + // + // Generate local abstract class. + // + + IceUtilInternal::Output out; + openClass(abs, _dir, out); + + writeDocSummary(out, p); + writeCopyright(out, p->file()); + + out << nl << "classdef (Abstract) " << name; + if(bases.empty()) + { + out << " < handle"; + } + else + { + 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 = getAllOutParams(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 << fixOp(op->name()) << spar; + string self = "obj"; + const ParamInfoList inParams = getAllInParams(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(); + const string abs = getAbsolute(p); + const bool basePreserved = p->inheritsMetaData("preserve-slice"); + const bool preserved = p->hasMetaData("preserve-slice"); + + IceUtilInternal::Output out; + openClass(abs, _dir, out); + + writeDocSummary(out, p); + writeCopyright(out, p->file()); + + ExceptionPtr base = p->base(); + + out << nl << "classdef " << name; + if(base) + { + out << " < " << getAbsolute(base); + } + else if(p->isLocal()) + { + out << " < Ice.LocalException"; + } + else + { + out << " < Ice.UserException"; + } + out.inc(); + + const DataMemberList members = p->dataMembers(); + if(!members.empty()) + { + out << nl << "properties"; + out.inc(); + for(DataMemberList::const_iterator q = members.begin(); q != members.end(); ++q) + { + writeMemberDoc(out, *q); + out << nl << fixExceptionMember((*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; + MemberInfoList convertMembers; + for(MemberInfoList::const_iterator q = allMembers.begin(); q != allMembers.end(); ++q) + { + allNames.push_back(q->fixedName); + + if(!q->inherited && needsConversion(q->dataMember->type())) + { + convertMembers.push_back(*q); + } + } + 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 = abs; + const string exmsg = abs; + // + // 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"; + + if(!p->isLocal() && preserved && !basePreserved) + { + out << nl << "function r = ice_getSlicedData(obj)"; + out.inc(); + out << nl << "r = obj.iceSlicedData_;"; + out.dec(); + out << nl << "end"; + } + + out.dec(); + out << nl << "end"; + + if(!p->isLocal()) + { + const DataMemberList classMembers = p->classDataMembers(); + if(!classMembers.empty() || !convertMembers.empty() || (preserved && !basePreserved)) + { + out << nl << "methods(Hidden=true)"; + out.inc(); + + if(preserved && !basePreserved) + { + // + // Override read_ for the first exception in the hierarchy that has the "preserve-slice" metadata. + // + out << nl << "function obj = iceRead(obj, is)"; + out.inc(); + out << nl << "is.startException();"; + out << nl << "obj = obj.iceReadImpl(is);"; + out << nl << "obj.iceSlicedData_ = is.endException(true);"; + out.dec(); + out << nl << "end"; + } + + if(!classMembers.empty() || !convertMembers.empty()) + { + out << nl << "function obj = icePostUnmarshal(obj)"; + out.inc(); + for(DataMemberList::const_iterator q = classMembers.begin(); q != classMembers.end(); ++q) + { + string m = fixExceptionMember((*q)->name()); + out << nl << "obj." << m << " = obj." << m << ".value;"; + } + for(MemberInfoList::const_iterator q = convertMembers.begin(); q != convertMembers.end(); ++q) + { + string m = "obj." + q->fixedName; + convertValueType(out, m, m, q->dataMember->type(), q->dataMember->optional()); + } + if(base && base->usesClasses(true)) + { + out << nl << "obj = icePostUnmarshal@" << getAbsolute(base) << "(obj);"; + } + out.dec(); + out << nl << "end"; + } + + out.dec(); + out << nl << "end"; + } + + out << nl << "methods(Access=protected)"; + out.inc(); + + out << nl << "function obj = iceReadImpl(obj, is)"; + out.inc(); + out << nl << "is.startSlice();"; + for(DataMemberList::const_iterator q = members.begin(); q != members.end(); ++q) + { + string m = fixExceptionMember((*q)->name()); + if(!(*q)->optional()) + { + if(isClass((*q)->type())) + { + out << nl << "obj." << m << " = IceInternal.ValueHolder();"; + unmarshal(out, "is", "@(v) obj." + m + ".set(v)", (*q)->type(), false, 0); + } + else + { + unmarshal(out, "is", "obj." + m, (*q)->type(), false, 0); + } + } + } + const DataMemberList optionalMembers = p->orderedOptionalDataMembers(); + for(DataMemberList::const_iterator q = optionalMembers.begin(); q != optionalMembers.end(); ++q) + { + string m = fixExceptionMember((*q)->name()); + if(isClass((*q)->type())) + { + out << nl << "obj." << m << " = IceInternal.ValueHolder();"; + unmarshal(out, "is", "@(v) obj." + m + ".set(v)", (*q)->type(), true, (*q)->tag()); + } + else + { + unmarshal(out, "is", "obj." + m, (*q)->type(), true, (*q)->tag()); + } + } + out << nl << "is.endSlice();"; + if(base) + { + out << nl << "obj = iceReadImpl@" << getAbsolute(base) << "(obj, is);"; + } + out.dec(); + out << nl << "end"; + + out.dec(); + out << nl << "end"; + + if(preserved && !basePreserved) + { + out << nl << "properties(Access=protected)"; + out.inc(); + out << nl << "iceSlicedData_"; + 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(abs, _dir, out); + + writeDocSummary(out, p); + writeCopyright(out, p->file()); + + const DataMemberList members = p->dataMembers(); + const DataMemberList classMembers = p->classDataMembers(); + + out << nl << "classdef " << name; + + out.inc(); + out << nl << "properties"; + out.inc(); + vector<string> memberNames; + DataMemberList convertMembers; + for(DataMemberList::const_iterator q = members.begin(); q != members.end(); ++q) + { + const string m = fixStructMember((*q)->name()); + memberNames.push_back(m); + writeMemberDoc(out, *q); + out << nl << m; + if(declarePropertyType((*q)->type(), false)) + { + out << " " << typeToString((*q)->type()); + } + + if(needsConversion((*q)->type())) + { + convertMembers.push_back(*q); + } + } + 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 << "." << fixStructMember((*q)->name()) << " = " << defaultValue(*q) << ';'; + } + out.dec(); + out << nl << "end"; + out.dec(); + out << nl << "end"; + out << nl << "function r = eq(obj, other)"; + out.inc(); + out << nl << "r = isequal(obj, other);"; + out.dec(); + out << nl << "end"; + out << nl << "function r = ne(obj, other)"; + out.inc(); + out << nl << "r = ~isequal(obj, other);"; + out.dec(); + out << nl << "end"; + + if(!convertMembers.empty() || !classMembers.empty()) + { + out << nl << "function obj = ice_convert(obj)"; + out.inc(); + convertStruct(out, p, "obj"); + 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 << "();"; + unmarshalStruct(out, p, "r"); + out.dec(); + out << nl << "end"; + + out << nl << "function r = ice_readOpt(is, tag)"; + out.inc(); + out << nl << "if is.readOptional(tag, " << getOptionalFormat(p) << ")"; + out.inc(); + if(p->isVariableLength()) + { + out << nl << "is.skip(4);"; + } + else + { + out << nl << "is.skipSize();"; + } + out << nl << "r = " << abs << ".ice_read(is);"; + out.dec(); + out << nl << "else"; + out.inc(); + out << nl << "r = Ice.Unset;"; + out.dec(); + out << nl << "end"; + 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) + { + marshal(out, "os", "v." + fixStructMember((*q)->name()), (*q)->type(), false, 0); + } + out.dec(); + out << nl << "end"; + + out << nl << "function ice_writeOpt(os, tag, v)"; + out.inc(); + out << nl << "if v ~= Ice.Unset && os.writeOptional(tag, " << getOptionalFormat(p) << ")"; + out.inc(); + if(p->isVariableLength()) + { + out << nl << "pos = os.startSize();"; + out << nl << abs << ".ice_write(os, v);"; + out << nl << "os.endSize(pos);"; + } + else + { + out << nl << "os.writeSize(" << p->minWireSize() << ");"; + out << nl << abs << ".ice_write(os, 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(); + + return false; +} + +void +CodeVisitor::visitSequence(const SequencePtr& p) +{ + if(p->isLocal()) + { + return; + } + + const TypePtr content = p->type(); + + const BuiltinPtr b = BuiltinPtr::dynamicCast(content); + if(b) + { + switch(b->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); + } + } + } + + EnumPtr enumContent = EnumPtr::dynamicCast(content); + SequencePtr seqContent = SequencePtr::dynamicCast(content); + StructPtr structContent = StructPtr::dynamicCast(content); + DictionaryPtr dictContent = DictionaryPtr::dynamicCast(content); + + const string name = fixIdent(p->name()); + const string scoped = p->scoped(); + const string abs = getAbsolute(p); + const bool cls = isClass(content); + const bool proxy = isProxy(content); + const bool convert = needsConversion(content); + + IceUtilInternal::Output out; + openClass(abs, _dir, out); + + writeCopyright(out, p->file()); + + 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(); + // + // Aside from the primitive types, only enum and struct sequences are mapped to arrays. The rest are mapped + // to cell arrays. We can't use the same subscript syntax for both. + // + if(enumContent || structContent) + { + marshal(out, "os", "seq(i)", content, false, 0); + } + else + { + marshal(out, "os", "seq{i}", content, false, 0); + } + out.dec(); + out << nl << "end"; + out.dec(); + out << nl << "end"; + + out << nl << "function writeOpt(os, tag, seq)"; + out.inc(); + out << nl << "if seq ~= Ice.Unset && os.writeOptional(tag, " << getOptionalFormat(p) << ")"; + out.inc(); + if(p->type()->isVariableLength()) + { + out << nl << "pos = os.startSize();"; + out << nl << abs << ".write(os, seq);"; + out << nl << "os.endSize(pos);"; + } + else + { + // + // The element is a fixed-size type. If the element type is bool or byte, we do NOT write an extra size. + // + const size_t sz = p->type()->minWireSize(); + if(sz > 1) + { + out << nl << "len = length(seq);"; + out << nl << "if len > 254"; + out.inc(); + out << nl << "os.writeSize(len * " << sz << " + 5);"; + out.dec(); + out << nl << "else"; + out.inc(); + out << nl << "os.writeSize(len * " << sz << " + 1);"; + out .dec(); + out << nl << "end"; + } + out << nl << abs << ".write(os, seq);"; + } + out.dec(); + out << nl << "end"; + out.dec(); + out << nl << "end"; + + out << nl << "function r = read(is)"; + out.inc(); + out << nl << "sz = is.readSize();"; + if(cls) + { + // + // For a sequence<class>, read() returns an instance of IceInternal.CellArrayHandle that we later replace + // with the cell array. See convert(). + // + out << nl << "if sz == 0"; + out.inc(); + out << nl << "r = {};"; + out.dec(); + out << nl << "else"; + out.inc(); + out << nl << "r = IceInternal.CellArrayHandle();"; + out << nl << "r.array = cell(1, sz);"; + out << nl << "for i = 1:sz"; + out.inc(); + // + // Ice.CellArrayHandle defines a set() method that we call from the lambda. + // + unmarshal(out, "is", "@(v) r.set(i, v)", content, false, 0); + out.dec(); + out << nl << "end"; + out.dec(); + out << nl << "end"; + } + else if((b && b->kind() == Builtin::KindString) || dictContent || seqContent || proxy) + { + // + // These types require a cell array. + // + out << nl << "if sz == 0"; + out.inc(); + out << nl << "r = {};"; + out.dec(); + out << nl << "else"; + out.inc(); + out << nl << "r = cell(1, sz);"; + out << nl << "for i = 1:sz"; + out.inc(); + unmarshal(out, "is", "r{i}", content, false, 0); + out.dec(); + out << nl << "end"; + out.dec(); + out << nl << "end"; + } + else if(enumContent) + { + const EnumeratorList enumerators = enumContent->enumerators(); + out << nl << "r = " << getAbsolute(enumContent) << ".empty();"; + out << nl << "if sz > 0"; + out.inc(); + out << nl << "r(1, sz) = " << getAbsolute(*enumerators.begin()) << ";"; + out << nl << "for i = 1:sz"; + out.inc(); + unmarshal(out, "is", "r(i)", content, false, 0); + out.dec(); + out << nl << "end"; + out.dec(); + out << nl << "end"; + } + else if(structContent) + { + // + // The most efficient way to build a sequence of structs is to pre-allocate the array using the + // syntax "arr(1, sz) = Type()". Additionally, we also have to inline the unmarshaling code for + // the struct members. + // + out << nl << "r = " << getAbsolute(structContent) << ".empty();"; + out << nl << "if sz > 0"; + out.inc(); + out << nl << "r(1, sz) = " << getAbsolute(structContent) << "();"; + out << nl << "for i = 1:sz"; + out.inc(); + unmarshalStruct(out, structContent, "r(i)"); + out.dec(); + out << nl << "end"; + out.dec(); + out << nl << "end"; + } + else + { + assert(false); + } + out.dec(); + out << nl << "end"; + + out << nl << "function r = readOpt(is, tag)"; + out.inc(); + out << nl << "if is.readOptional(tag, " << getOptionalFormat(p) << ")"; + out.inc(); + if(p->type()->isVariableLength()) + { + out << nl << "is.skip(4);"; + } + else if(p->type()->minWireSize() > 1) + { + out << nl << "is.skipSize();"; + } + out << nl << "r = " << abs << ".read(is);"; + out.dec(); + out << nl << "else"; + out.inc(); + out << nl << "r = Ice.Unset;"; + out.dec(); + out << nl << "end"; + out.dec(); + out << nl << "end"; + + if(cls || convert) + { + out << nl << "function r = convert(seq)"; + out.inc(); + if(cls) + { + out << nl << "if isempty(seq)"; + out.inc(); + out << nl << "r = seq;"; + out.dec(); + out << nl << "else"; + out.inc(); + out << nl << "r = seq.array;"; + out.dec(); + out << nl << "end"; + } + else + { + assert(structContent || seqContent || dictContent); + if(structContent) + { + // + // Inline the conversion. + // + out << nl << "r = seq;"; + out << nl << "for i = 1:length(seq)"; + out.inc(); + convertStruct(out, structContent, "r(i)"); + out.dec(); + out << nl << "end"; + } + else + { + out << nl << "sz = length(seq);"; + out << nl << "if sz > 0"; + out.inc(); + out << nl << "r = cell(1, sz);"; + out << nl << "for i = 1:sz"; + out.inc(); + convertValueType(out, "r{i}", "seq{i}", content, false); + out << nl << "end"; + out.dec(); + out.dec(); + out << nl << "else"; + out.inc(); + out << nl << "r = seq;"; + 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 bool cls = isClass(value); + const bool convert = needsConversion(value); + + 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(abs, _dir, out); + + writeCopyright(out, p->file()); + + 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.dec(); + out << nl << "end"; + out.dec(); + out << nl << "end"; + out << nl << "methods(Static)"; + out.inc(); + + 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(); + marshal(out, "os", "d(i).key", key, false, 0); + marshal(out, "os", "d(i).value", value, false, 0); + 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(); + out << nl << "k = keys{i};"; + out << nl << "v = values{i};"; + marshal(out, "os", "k", key, false, 0); + marshal(out, "os", "v", value, false, 0); + out.dec(); + out << nl << "end"; + } + out.dec(); + out << nl << "end"; + out.dec(); + out << nl << "end"; + + out << nl << "function writeOpt(os, tag, d)"; + out.inc(); + out << nl << "if d ~= Ice.Unset && os.writeOptional(tag, " << getOptionalFormat(p) << ")"; + out.inc(); + if(key->isVariableLength() || value->isVariableLength()) + { + out << nl << "pos = os.startSize();"; + out << nl << abs << ".write(os, d);"; + out << nl << "os.endSize(pos);"; + } + else + { + const size_t sz = key->minWireSize() + value->minWireSize(); + if(cls) + { + out << nl << "len = length(d.array);"; + } + else + { + out << nl << "len = length(d);"; + } + out << nl << "if len > 254"; + out.inc(); + out << nl << "os.writeSize(len * " << sz << " + 5);"; + out.dec(); + out << nl << "else"; + out.inc(); + out << nl << "os.writeSize(len * " << sz << " + 1);"; + out .dec(); + out << nl << "end"; + out << nl << abs << ".write(os, d);"; + } + out.dec(); + out << nl << "end"; + out.dec(); + out << nl << "end"; + + out << nl << "function r = read(is)"; + out.inc(); + out << nl << "sz = is.readSize();"; + if(st) + { + // + // We use a struct array when the key is a structure type because we can't use containers.Map. + // + out << nl << "r = struct('key', {}, 'value', {});"; + } + else + { + out << nl << "r = containers.Map('KeyType', '" << dictionaryTypeToString(key, true) << "', 'ValueType', '" + << dictionaryTypeToString(value, false) << "');"; + } + out << nl << "for i = 1:sz"; + out.inc(); + + unmarshal(out, "is", "k", key, false, 0); + + if(cls) + { + out << nl << "v = IceInternal.ValueHolder();"; + unmarshal(out, "is", "@(v_) v.set(v_)", value, false, 0); + } + else + { + unmarshal(out, "is", "v", value, false, 0); + } + + 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 << nl << "function r = readOpt(is, tag)"; + out.inc(); + out << nl << "if is.readOptional(tag, " << getOptionalFormat(p) << ")"; + out.inc(); + if(key->isVariableLength() || value->isVariableLength()) + { + out << nl << "is.skip(4);"; + } + else + { + out << nl << "is.skipSize();"; + } + out << nl << "r = " << abs << ".read(is);"; + out.dec(); + out << nl << "else"; + out.inc(); + out << nl << "r = Ice.Unset;"; + out.dec(); + out << nl << "end"; + out.dec(); + out << nl << "end"; + + if(cls || convert) + { + out << nl << "function r = convert(d, obj)"; + out.inc(); + if(st) + { + out << nl << "for i = 1:length(d)"; + out.inc(); + if(cls) + { + // + // Each entry has a temporary ValueHolder that we need to replace with the actual value. + // + out << nl << "d(i).value = d(i).value.value;"; + } + else + { + convertValueType(out, "d(i).value", "d(i).value", value, false); + } + out.dec(); + out << nl << "end"; + } + else + { + out << nl << "keys = d.keys();"; + out << nl << "values = d.values();"; + out << nl << "for i = 1:d.Count"; + out.inc(); + out << nl << "k = keys{i};"; + out << nl << "v = values{i};"; + if(cls) + { + // + // Each entry has a temporary ValueHolder that we need to replace with the actual value. + // + out << nl << "d(k) = v.value;"; + } + else + { + convertValueType(out, "d(k)", "v", value, false); + } + out.dec(); + out << nl << "end"; + } + out << nl << "r = d;"; + 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); + const EnumeratorList enumerators = p->enumerators(); + + IceUtilInternal::Output out; + openClass(abs, _dir, out); + + writeDocSummary(out, p); + writeCopyright(out, p->file()); + + out << nl << "classdef " << name; + if(p->maxValue() <= 255) + { + out << " < uint8"; + } + else + { + out << " < int32"; + } + + out.inc(); + out << nl << "enumeration"; + out.inc(); + for(EnumeratorList::const_iterator q = enumerators.begin(); q != enumerators.end(); ++q) + { + StringList sl = splitComment((*q)->comment()); + if(!sl.empty()) + { + writeDocLines(out, sl, true); + } + out << nl << fixEnumerator((*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 = fixEnumerator(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 ice_writeOpt(os, tag, v)"; + out.inc(); + out << nl << "if v ~= Ice.Unset && os.writeOptional(tag, " << getOptionalFormat(p) << ")"; + out.inc(); + out << nl << abs << ".ice_write(os, v);"; + 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_readOpt(is, tag)"; + out.inc(); + out << nl << "if is.readOptional(tag, " << getOptionalFormat(p) << ")"; + out.inc(); + out << nl << "r = " << abs << ".ice_read(is);"; + out.dec(); + out << nl << "else"; + out.inc(); + out << nl << "r = Ice.Unset;"; + out.dec(); + out << nl << "end"; + 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 << "." << fixEnumerator((*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(); + const string abs = getAbsolute(p); + + IceUtilInternal::Output out; + openClass(abs, _dir, out); + + writeDocSummary(out, p); + writeCopyright(out, p->file()); + + 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(); +} + +string +CodeVisitor::getOperationMode(Slice::Operation::Mode mode) +{ + switch(mode) + { + case Operation::Normal: + return "0"; + case Operation::Nonmutating: + return "1"; + case Operation::Idempotent: + return "2"; + 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 = fixExceptionMember((*q)->name()); + m.inherited = inherited; + m.dataMember = *q; + allMembers.push_back(m); + } +} + +CodeVisitor::ParamInfoList +CodeVisitor::getAllInParams(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; +} + +void +CodeVisitor::getInParams(const OperationPtr& op, ParamInfoList& required, ParamInfoList& optional) +{ + const ParamInfoList params = getAllInParams(op); + for(ParamInfoList::const_iterator p = params.begin(); p != params.end(); ++p) + { + if(p->optional) + { + optional.push_back(*p); + } + else + { + required.push_back(*p); + } + } + + // + // Sort optional parameters by tag. + // + class SortFn + { + public: + static bool compare(const ParamInfo& lhs, const ParamInfo& rhs) + { + return lhs.tag < rhs.tag; + } + }; + optional.sort(SortFn::compare); +} + +CodeVisitor::ParamInfoList +CodeVisitor::getAllOutParams(const OperationPtr& op) +{ + ParamDeclList params = op->outParameters(); + ParamInfoList l; + int pos = 1; + + if(op->returnType()) + { + ParamInfo info; + info.fixedName = "result"; + info.pos = pos++; + + for(ParamDeclList::const_iterator p = params.begin(); p != params.end(); ++p) + { + if((*p)->name() == "result") + { + info.fixedName = "result_"; + break; + } + } + info.type = op->returnType(); + info.optional = op->returnIsOptional(); + info.tag = op->returnTag(); + l.push_back(info); + } + + for(ParamDeclList::const_iterator p = params.begin(); p != params.end(); ++p) + { + ParamInfo info; + info.fixedName = fixIdent((*p)->name()); + info.type = (*p)->type(); + info.optional = (*p)->optional(); + info.tag = (*p)->tag(); + info.pos = pos++; + info.param = *p; + l.push_back(info); + } + + return l; +} + +void +CodeVisitor::getOutParams(const OperationPtr& op, ParamInfoList& required, ParamInfoList& optional) +{ + const ParamInfoList params = getAllOutParams(op); + for(ParamInfoList::const_iterator p = params.begin(); p != params.end(); ++p) + { + if(p->optional) + { + optional.push_back(*p); + } + else + { + required.push_back(*p); + } + } + + // + // Sort optional parameters by tag. + // + class SortFn + { + public: + static bool compare(const ParamInfo& lhs, const ParamInfo& rhs) + { + return lhs.tag < rhs.tag; + } + }; + optional.sort(SortFn::compare); +} + +string +CodeVisitor::getOptionalFormat(const TypePtr& type) +{ + BuiltinPtr bp = BuiltinPtr::dynamicCast(type); + if(bp) + { + switch(bp->kind()) + { + case Builtin::KindByte: + case Builtin::KindBool: + { + return "Ice.OptionalFormat.F1"; + } + case Builtin::KindShort: + { + return "Ice.OptionalFormat.F2"; + } + case Builtin::KindInt: + case Builtin::KindFloat: + { + return "Ice.OptionalFormat.F4"; + } + case Builtin::KindLong: + case Builtin::KindDouble: + { + return "Ice.OptionalFormat.F8"; + } + case Builtin::KindString: + { + return "Ice.OptionalFormat.VSize"; + } + case Builtin::KindObject: + { + return "Ice.OptionalFormat.Class"; + } + case Builtin::KindObjectProxy: + { + return "Ice.OptionalFormat.FSize"; + } + case Builtin::KindLocalObject: + { + assert(false); + break; + } + case Builtin::KindValue: + { + return "Ice.OptionalFormat.Class"; + } + } + } + + if(EnumPtr::dynamicCast(type)) + { + return "Ice.OptionalFormat.Size"; + } + + SequencePtr seq = SequencePtr::dynamicCast(type); + if(seq) + { + return seq->type()->isVariableLength() ? "Ice.OptionalFormat.FSize" : "Ice.OptionalFormat.VSize"; + } + + DictionaryPtr d = DictionaryPtr::dynamicCast(type); + if(d) + { + return (d->keyType()->isVariableLength() || d->valueType()->isVariableLength()) ? + "Ice.OptionalFormat.FSize" : "Ice.OptionalFormat.VSize"; + } + + StructPtr st = StructPtr::dynamicCast(type); + if(st) + { + return st->isVariableLength() ? "Ice.OptionalFormat.FSize" : "Ice.OptionalFormat.VSize"; + } + + if(ProxyPtr::dynamicCast(type)) + { + return "Ice.OptionalFormat.FSize"; + } + + ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type); + assert(cl); + return "Ice.OptionalFormat.Class"; +} + +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) +{ + 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) + { + out << nl << typeS << ".ice_writeOpt(" << stream << ", " << tag << ", " << v << ");"; + } + 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 << typeS << ".ice_writeOpt(" << stream << ", " << tag << ", " << v << ");"; + } + else + { + out << nl << typeS << ".ice_write(" << stream << ", " << v << ");"; + } + return; + } + + DictionaryPtr dict = DictionaryPtr::dynamicCast(type); + if(dict) + { + if(optional) + { + out << nl << getAbsolute(dict) << ".writeOpt(" << stream << ", " << tag << ", " << v << ");"; + } + 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 << getAbsolute(seq) << ".writeOpt(" << stream << ", " << tag << ", " << v << ");"; + } + 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) +{ + 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(optional) + { + out << nl << stream << ".readValueOpt(" << tag << ", " << v << ", 'Ice.Value');"; + } + else + { + out << nl << stream << ".readValue(" << v << ", 'Ice.Value');"; + } + 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) + { + if(prx->_class()->isInterface() || !prx->_class()->definition()->allOperations().empty()) + { + 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 << ");"; + } + } + else + { + if(optional) + { + out << nl << v << " = " << stream << ".readProxyOpt(" << tag << ");"; + } + else + { + out << nl << v << " = " << stream << ".readProxy();"; + } + } + return; + } + + ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type); + if(cl) + { + const string cls = cl->isInterface() ? "Ice.Value" : getAbsolute(cl); + if(optional) + { + out << nl << stream << ".readValueOpt(" << tag << ", " << v << ", '" << cls << "');"; + } + else + { + out << nl << stream << ".readValue(" << v << ", '" << cls << "');"; + } + return; + } + + StructPtr st = StructPtr::dynamicCast(type); + if(st) + { + const string typeS = getAbsolute(st); + if(optional) + { + out << nl << v << " = " << typeS << ".ice_readOpt(" << stream << ", " << tag << ");"; + } + 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 << v << " = " << typeS << ".ice_readOpt(" << stream << ", " << tag << ");"; + } + else + { + out << nl << v << " = " << typeS << ".ice_read(" << stream << ");"; + } + return; + } + + DictionaryPtr dict = DictionaryPtr::dynamicCast(type); + if(dict) + { + if(optional) + { + out << nl << v << " = " << getAbsolute(dict) << ".readOpt(" << stream << ", " << tag << ");"; + } + 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 << v << " = " << getAbsolute(seq) << ".readOpt(" << stream << ", " << tag << ");"; + } + else + { + out << nl << v << " = " << getAbsolute(seq) << ".read(" << stream << ");"; + } + return; + } + + assert(false); +} + +void +CodeVisitor::unmarshalStruct(IceUtilInternal::Output& out, const StructPtr& p, const string& v) +{ + const DataMemberList members = p->dataMembers(); + + for(DataMemberList::const_iterator q = members.begin(); q != members.end(); ++q) + { + string m = fixStructMember((*q)->name()); + if(isClass((*q)->type())) + { + out << nl << v << "." << m << " = IceInternal.ValueHolder();"; + unmarshal(out, "is", "@(v_) " + v + "." + m + ".set(v_)", (*q)->type(), false, 0); + } + else + { + unmarshal(out, "is", v + "." + m, (*q)->type(), false, 0); + } + } +} + +void +CodeVisitor::convertStruct(IceUtilInternal::Output& out, const StructPtr& p, const string& v) +{ + const DataMemberList members = p->dataMembers(); + + for(DataMemberList::const_iterator q = members.begin(); q != members.end(); ++q) + { + string m = fixStructMember((*q)->name()); + if(needsConversion((*q)->type())) + { + convertValueType(out, v + "." + m, v + "." + m, (*q)->type(), false); + } + else if(isClass((*q)->type())) + { + out << nl << v << "." << m << " = " << v << "." << m << ".value;"; + } + } +} + +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" + "--list-generated Emit list of generated files in XML format.\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("", "list-generated"); + opts.addOpt("d", "debug"); + opts.addOpt("", "all"); + + 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 listGenerated = opts.isSet("list-generated"); + + 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__SLICE2MATLAB__"); + + 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__SLICE2MATLAB__")) + { + return EXIT_FAILURE; + } + + if(!icecpp->close()) + { + return EXIT_FAILURE; + } + } + else + { + FileTracker::instance()->setSource(*i); + + PreprocessorPtr icecpp = Preprocessor::create(argv[0], *i, cppArgs); + FILE* cppHandle = icecpp->preprocess(true, "-D__SLICE2MATLAB__"); + + 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 + { + CodeVisitor codeVisitor(output); + u->visit(&codeVisitor, all); + } + 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; + status = EXIT_FAILURE; + FileTracker::instance()->error(); + break; + } + } + + 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); + } + + if(listGenerated) + { + FileTracker::instance()->dumpxml(); + } + + 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; + } +} |