diff options
Diffstat (limited to 'cpp/src/slice2swift/SwiftUtil.cpp')
-rw-r--r-- | cpp/src/slice2swift/SwiftUtil.cpp | 2815 |
1 files changed, 2815 insertions, 0 deletions
diff --git a/cpp/src/slice2swift/SwiftUtil.cpp b/cpp/src/slice2swift/SwiftUtil.cpp new file mode 100644 index 00000000000..80e9d6469c2 --- /dev/null +++ b/cpp/src/slice2swift/SwiftUtil.cpp @@ -0,0 +1,2815 @@ +// +// Copyright (c) ZeroC, Inc. All rights reserved. +// +// + +#include <IceUtil/OutputUtil.h> +#include <IceUtil/StringUtil.h> + +#include <Slice/Util.h> + +#include <SwiftUtil.h> + +using namespace std; +using namespace Slice; +using namespace IceUtilInternal; + +namespace +{ + +static string +lookupKwd(const string& name) +{ + // + // Keyword list. *Must* be kept in alphabetical order. + // + static const string keywordList[] = + { + "Any", "as", "associatedtype", "associativity", "break", + "case", "catch", "class", "continue", "convenience", "default", "defer", "deinit", + "didSet", "do", "dynamic", "else", "enum", "extension", "fallthrough", "false", + "fileprivate", "final", "for", "func", "get", "guard", "if", "import", "in", "indirect", + "infix", "init", "inout", "internal", "is", "lazy", "left", "let", "mutating", "nil", + "none", "nonmutating", "open", "operator", "optional", "override", "postfix", "precedence", + "prefix", "private", "protocol", "public", "repeat", "required", "rethrows", "return", + "right", "self", "set", "static", "struct", "subscript", "super", "switch", "throw", "throws", + "true", "try", "Type", "typealias", "unowned", "var", "weak", "where", "while", "willSet" + }; + bool found = binary_search(&keywordList[0], + &keywordList[sizeof(keywordList) / sizeof(*keywordList)], + name, + Slice::CICompare()); + if(found) + { + return "`" + name + "`"; + } + + return name; +} + +string +replace(string s, string patt, string val) +{ + string r = s; + string::size_type pos = r.find(patt); + while(pos != string::npos) + { + r.replace(pos, patt.size(), val); + pos += val.size(); + pos = r.find(patt, pos); + } + return r; +} + +string +opFormatTypeToString(const OperationPtr& op ) +{ + switch(op->format()) + { + case DefaultFormat: + { + return ".DefaultFormat"; + } + case CompactFormat: + { + return ".CompactFormat"; + } + case SlicedFormat: + { + return ".SlicedFormat"; + } + default: + { + assert(false); + } + } + return "???"; +} + +} + +// +// Split a scoped name into its components and return the components as a list of (unscoped) identifiers. +// +StringList +Slice::splitScopedName(const string& scoped) +{ + assert(scoped[0] == ':'); + StringList 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; +} + +// +// Check the given identifier against Swift's list of reserved words. If it matches +// a reserved word, then an escaped version is returned with a leading underscore. +// +string +Slice::fixIdent(const string& ident) +{ + if(ident[0] != ':') + { + return lookupKwd(ident); + } + StringList ids = splitScopedName(ident); + transform(ids.begin(), ids.end(), ids.begin(), ptr_fun(lookupKwd)); + ostringstream result; + for(StringList::const_iterator i = ids.begin(); i != ids.end(); ++i) + { + result << "::" + *i; + } + return result.str(); +} + +string +Slice::getSwiftModule(const ModulePtr& module, string& swiftPrefix) +{ + const string modulePrefix = "swift:module:"; + + string swiftModule; + + if(module->findMetaData(modulePrefix, swiftModule)) + { + swiftModule = swiftModule.substr(modulePrefix.size()); + + size_t pos = swiftModule.find(':'); + if(pos != string::npos) + { + swiftPrefix = swiftModule.substr(pos + 1); + swiftModule = swiftModule.substr(0, pos); + } + } + else + { + swiftModule = module->name(); + swiftPrefix = ""; + } + return fixIdent(swiftModule); +} + +string +Slice::getSwiftModule(const ModulePtr& module) +{ + string prefix; + return getSwiftModule(module, prefix); +} + +ModulePtr +Slice::getTopLevelModule(const ContainedPtr& cont) +{ + // + // Traverse to the top-level module. + // + ModulePtr m; + ContainedPtr p = cont; + while(true) + { + if(ModulePtr::dynamicCast(p)) + { + m = ModulePtr::dynamicCast(p); + } + + ContainerPtr c = p->container(); + p = ContainedPtr::dynamicCast(c); // This cast fails for Unit. + if(!p) + { + break; + } + } + return m; +} + +ModulePtr +Slice::getTopLevelModule(const TypePtr& type) +{ + assert(ProxyPtr::dynamicCast(type) || ContainedPtr::dynamicCast(type)); + + ProxyPtr proxy = ProxyPtr::dynamicCast(type); + return getTopLevelModule(proxy ? ContainedPtr::dynamicCast(proxy->_class()->definition()) : + ContainedPtr::dynamicCast(type)); +} + +void +SwiftGenerator::trimLines(StringList& l) +{ + // + // Remove empty trailing lines. + // + while(!l.empty() && l.back().empty()) + { + l.pop_back(); + } +} + +StringList +SwiftGenerator::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 +SwiftGenerator::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; +} + +DocElements +SwiftGenerator::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 +SwiftGenerator::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 +SwiftGenerator::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 +SwiftGenerator::writeDocSummary(IceUtilInternal::Output& out, const ContainedPtr& p) +{ + DocElements doc = parseComment(p); + + string n = fixIdent(p->name()); + + // + // No leading newline. + // + if(!doc.overview.empty()) + { + writeDocLines(out, doc.overview); + } + + if(!doc.misc.empty()) + { + out << "///" << nl; + writeDocLines(out, doc.misc); + } + + if(doc.deprecated) + { + out << nl << "///"; + out << nl << "/// ## Deprecated"; + if(!doc.deprecateReason.empty()) + { + writeDocLines(out, doc.deprecateReason); + } + } +} + +void +SwiftGenerator::writeOpDocSummary(IceUtilInternal::Output& out, + const OperationPtr& p, + bool async, + bool dispatch, + bool local) +{ + DocElements doc = parseComment(p); + if(!doc.overview.empty()) + { + writeDocLines(out, doc.overview); + } + + if(doc.deprecated) + { + out << nl << "///"; + out << nl << "/// ## Deprecated"; + if(!doc.deprecateReason.empty()) + { + writeDocLines(out, doc.deprecateReason); + } + } + + int typeCtx = TypeContextInParam; + if(local) + { + typeCtx |= TypeContextLocal; + } + + const ParamInfoList allInParams = getAllInParams(p, typeCtx); + for(ParamInfoList::const_iterator q = allInParams.begin(); q != allInParams.end(); ++q) + { + out << nl << "///"; + out << nl << "/// - parameter " << (!dispatch && allInParams.size() == 1 ? "_" : q->name) + << ": `" << q->typeStr << "`"; + 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(!local) + { + out << nl << "///"; + if(dispatch) + { + out << nl << "/// - parameter current: `Ice.Current` - The Current object for the dispatch."; + } + else + { + out << nl << "/// - parameter context: `Ice.Context` - Optional request context."; + } + } + + typeCtx = local ? TypeContextLocal : 0; + + if(async) + { + if(!dispatch) + { + out << nl << "///"; + out << nl << "/// - parameter sentOn: `Dispatch.DispatchQueue?` - Optional dispatch queue used to"; + out << nl << "/// dispatch sent callback, the default is to use `PromiseKit.conf.Q.return` queue."; + out << nl << "///"; + out << nl << "/// - parameter sentFlags: `Dispatch.DispatchWorkItemFlags?` - Optional dispatch flags used"; + out << nl << "/// to dispatch sent callback"; + out << nl << "///"; + out << nl << "/// - parameter sent: `((Swift.Bool) -> Swift.Void)` - Optional sent callback."; + } + + out << nl << "///"; + out << nl << "/// - returns: `PromiseKit.Promise<" << operationReturnType(p, typeCtx) + << ">` - The result of the operation"; + } + else + { + const ParamInfoList allOutParams = getAllOutParams(p, typeCtx); + if(allOutParams.size() == 1) + { + ParamInfo ret = allOutParams.front(); + out << nl << "///"; + out << nl << "/// - returns: `" << ret.typeStr << "`"; + if(p->returnType()) + { + if(!doc.returns.empty()) + { + out << " - "; + writeDocLines(out, doc.returns, false); + } + } + else + { + map<string, StringList>::const_iterator r = doc.params.find(ret.name); + if(r != doc.params.end() && !r->second.empty()) + { + out << " - "; + writeDocLines(out, r->second, false); + } + } + } + else if(allOutParams.size() > 1) + { + out << nl << "///"; + out << nl << "/// - returns: `" << operationReturnType(p, typeCtx) << "`:"; + if(p->returnType()) + { + ParamInfo ret = allOutParams.back(); + out << nl << "///"; + out << nl << "/// - " << ret.name << ": `" << ret.typeStr << "`"; + if(!doc.returns.empty()) + { + out << " - "; + writeDocLines(out, doc.returns, false); + } + } + + for(ParamInfoList::const_iterator q = allOutParams.begin(); q != allOutParams.end(); ++q) + { + if(q->param != 0) + { + out << nl << "///"; + out << nl << "/// - " << q->name << ": `" << q->typeStr << "`"; + 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() && !async) + { + out << nl << "///"; + out << nl << "/// - throws:"; + for(map<string, StringList>::const_iterator q = doc.exceptions.begin(); q != doc.exceptions.end(); ++q) + { + out << nl << "///"; + out << nl << "/// - " << q->first; + if(!q->second.empty()) + { + out << " - "; + writeDocLines(out, q->second, false, " "); + } + } + } + + if(!doc.misc.empty()) + { + out << nl; + writeDocLines(out, doc.misc, false); + } +} + +void +SwiftGenerator::writeProxyDocSummary(IceUtilInternal::Output& out, const ClassDefPtr& p, const string& swiftModule) +{ + DocElements doc = parseComment(p); + + const string name = getUnqualified(getAbsolute(p), swiftModule); + const string prx = name + "Prx"; + + if(doc.overview.empty()) + { + out << nl << "/// " << prx << " overview."; + } + else + { + writeDocLines(out, doc.overview); + } + + const OperationList ops = p->operations(); + if(!ops.empty()) + { + out << nl << "///"; + out << nl << "/// " << prx << " Methods:"; + for(OperationList::const_iterator q = ops.begin(); q != ops.end(); ++q) + { + OperationPtr op = *q; + DocElements opdoc = parseComment(op); + out << nl << "///"; + out << nl << "/// - " << fixIdent(op->name()) << ": "; + if(!opdoc.overview.empty()) + { + writeDocSentence(out, opdoc.overview); + } + + out << nl << "///"; + out << nl << "/// - " << op->name() << "Async: "; + if(!opdoc.overview.empty()) + { + writeDocSentence(out, opdoc.overview); + } + } + } + + if(!doc.misc.empty()) + { + writeDocLines(out, doc.misc, false); + } +} + +void +SwiftGenerator::writeServantDocSummary(IceUtilInternal::Output& out, const ClassDefPtr& p, const string& swiftModule) +{ + DocElements doc = parseComment(p); + + const string name = getUnqualified(getAbsolute(p), swiftModule); + + if(doc.overview.empty()) + { + out << nl << "/// " << name << " overview."; + } + else + { + writeDocLines(out, doc.overview); + } + + const OperationList ops = p->operations(); + if(!ops.empty()) + { + out << nl << "///"; + out << nl << "/// " << name << " Methods:"; + for(OperationList::const_iterator q = ops.begin(); q != ops.end(); ++q) + { + OperationPtr op = *q; + DocElements opdoc = parseComment(op); + out << nl << "///"; + out << nl << "/// - " << fixIdent(op->name()) << ": "; + if(!opdoc.overview.empty()) + { + writeDocSentence(out, opdoc.overview); + } + } + } + + if(!doc.misc.empty()) + { + writeDocLines(out, doc.misc, false); + } +} + +void +SwiftGenerator::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; + } + + if(doc.overview.empty()) + { + out << nl << "/// " << fixIdent(p->name()); + } + else + { + writeDocLines(out, doc.overview); + } + + if(!doc.misc.empty()) + { + writeDocLines(out, doc.misc); + } + + if(doc.deprecated) + { + out << nl << "/// ##Deprecated"; + if(!doc.deprecateReason.empty()) + { + writeDocLines(out, doc.deprecateReason); + } + } +} + +void +SwiftGenerator::validateMetaData(const UnitPtr& u) +{ + MetaDataVisitor visitor; + u->visit(&visitor, true); +} + +// +// 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. +// +namespace +{ + +string +getAbsoluteImpl(const ContainedPtr& cont, const string& prefix = "", const string& suffix = "") +{ + string swiftPrefix; + string swiftModule = getSwiftModule(getTopLevelModule(cont), swiftPrefix); + + string str = cont->scope() + prefix + cont->name() + suffix; + if(str.find("::") == 0) + { + str.erase(0, 2); + } + + size_t pos = str.find("::"); + // + // Replace the definition top-level module by the corresponding Swift module + // and append the Swift prefix for the Slice module, then any remaining nested + // modules become a Swift prefix + // + if(pos != string::npos) + { + str = str.substr(pos + 2); + } + return swiftModule + "." + swiftPrefix + replace(str, "::", ""); +} + +} + +string +SwiftGenerator::getValue(const string& swiftModule, const TypePtr& type) +{ + BuiltinPtr builtin = BuiltinPtr::dynamicCast(type); + if(builtin) + { + switch(builtin->kind()) + { + case Builtin::KindBool: + { + return "false"; + } + case Builtin::KindByte: + case Builtin::KindShort: + case Builtin::KindInt: + case Builtin::KindLong: + { + return "0"; + } + case Builtin::KindFloat: + case Builtin::KindDouble: + { + return "0.0"; + } + case Builtin::KindString: + { + return "\"\""; + } + default: + { + return "nil"; + } + } + } + + EnumPtr en = EnumPtr::dynamicCast(type); + if(en) + { + return "." + fixIdent((*en->enumerators().begin())->name()); + } + + StructPtr st = StructPtr::dynamicCast(type); + if(st) + { + return getUnqualified(getAbsolute(type), swiftModule) + "()"; + } + + SequencePtr seq = SequencePtr::dynamicCast(type); + if(seq) + { + return getUnqualified(getAbsolute(type), swiftModule) + "()"; + } + + DictionaryPtr dict = DictionaryPtr::dynamicCast(type); + if(dict) + { + return getUnqualified(getAbsolute(type), swiftModule) + "()"; + } + + return "nil"; +} + +void +SwiftGenerator::writeConstantValue(IceUtilInternal::Output& out, const TypePtr& type, + const SyntaxTreeBasePtr& valueType, const string& value, + const StringList&, const string& swiftModule, bool optional) +{ + ConstPtr constant = ConstPtr::dynamicCast(valueType); + if(constant) + { + out << getUnqualified(getAbsolute(constant), swiftModule); + } + else + { + if(valueType) + { + BuiltinPtr bp = BuiltinPtr::dynamicCast(type); + EnumPtr ep = EnumPtr::dynamicCast(type); + if(bp && bp->kind() == Builtin::KindString) + { + out << "\""; + out << toStringLiteral(value, "\n\r\t", "", EC6UCN, 0); + out << "\""; + } + else if(ep) + { + assert(valueType); + EnumeratorPtr enumerator = EnumeratorPtr::dynamicCast(valueType); + assert(enumerator); + out << getUnqualified(getAbsolute(ep), swiftModule) << "." << enumerator->name(); + } + else + { + out << value; + } + } + else if(optional) + { + out << "nil"; + } + else + { + out << getValue(swiftModule, type); + } + } +} + +string +SwiftGenerator::typeToString(const TypePtr& type, + const ContainedPtr& toplevel, + const StringList& metadata, + bool optional, + int typeCtx) +{ + static const char* builtinTable[] = + { + "Swift.UInt8", + "Swift.Bool", + "Swift.Int16", + "Swift.Int32", + "Swift.Int64", + "Swift.Float", + "Swift.Double", + "Swift.String", + "Ice.Disp", // Object + "Ice.ObjectPrx", // ObjectPrx + "Swift.AnyObject", // LocalObject + "Ice.Value" // Value + }; + + if(!type) + { + return ""; + } + + bool local = (typeCtx & TypeContextLocal) != 0; + if(local) + { + for(StringList::const_iterator i = metadata.begin(); i != metadata.end(); ++i) + { + const string swiftType = "swift:type:"; + const string meta = *i; + if(meta.find(swiftType) == 0) + { + return meta.substr(swiftType.size()); + } + } + } + + string t = ""; + // + // The current module were the type is being used + // + string currentModule = getSwiftModule(getTopLevelModule(toplevel)); + BuiltinPtr builtin = BuiltinPtr::dynamicCast(type); + bool nonnull = find(metadata.begin(), metadata.end(), "swift:nonnull") != metadata.end(); + bool inparam = typeCtx & TypeContextInParam; + + if(builtin) + { + if(builtin->kind() == Builtin::KindObject && !(typeCtx & TypeContextLocal)) + { + t = getUnqualified(builtinTable[Builtin::KindValue], currentModule); + } + else + { + t = getUnqualified(builtinTable[builtin->kind()], currentModule); + } + } + + ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type); + ProxyPtr prx = ProxyPtr::dynamicCast(type); + ContainedPtr cont = ContainedPtr::dynamicCast(type); + + if(cl) + { + if(cl->isInterface() && !cl->isLocal()) + { + t = fixIdent(getUnqualified(builtinTable[Builtin::KindValue], currentModule)); + } + else + { + // + // Annotate nonnull closure as @escaping, Swift optional closure parameters are always + // @escaping see https://www.jessesquires.com/blog/why-optional-swift-closures-are-escaping/ + // + if(cl->isLocal() && cl->definition() && cl->definition()->isDelegate() && inparam && nonnull) + { + t = "@escaping "; + } + t += fixIdent(getUnqualified(getAbsoluteImpl(cl), currentModule)); + } + } + else if(prx) + { + ClassDefPtr def = prx->_class()->definition(); + if(def->isInterface() || def->allOperations().size() > 0) + { + t = getUnqualified(getAbsoluteImpl(prx->_class(), "", "Prx"), currentModule); + } + else + { + t = getUnqualified("Ice.ObjectPrx", currentModule); + } + } + else if(cont) + { + t = fixIdent(getUnqualified(getAbsoluteImpl(cont), currentModule)); + } + + if(!nonnull && (optional || isNullableType(type))) + { + t += "?"; + } + return t; +} + +string +SwiftGenerator::getAbsolute(const TypePtr& type) +{ + static const char* builtinTable[] = + { + "Swift.UInt8", + "Swift.Bool", + "Swift.Int16", + "Swift.Int32", + "Swift.Int64", + "Swift.Float", + "Swift.Double", + "Swift.String", + "Ice.Disp", // Object + "Ice.ObjectPrx", // ObjectPrx + "Swift.AnyObject", // LocalObject + "Ice.Value" // Value + }; + + BuiltinPtr builtin = BuiltinPtr::dynamicCast(type); + if(builtin) + { + return builtinTable[builtin->kind()]; + } + + ProxyPtr proxy = ProxyPtr::dynamicCast(type); + if(proxy) + { + return getAbsoluteImpl(proxy->_class(), "", "Prx"); + } + + ContainedPtr cont = ContainedPtr::dynamicCast(type); + if(cont) + { + return getAbsoluteImpl(cont); + } + + assert(false); + return "???"; +} + +string +SwiftGenerator::getAbsolute(const ClassDeclPtr& cl) +{ + return getAbsoluteImpl(cl); +} + +string +SwiftGenerator::getAbsolute(const ClassDefPtr& cl) +{ + return getAbsoluteImpl(cl); +} + +string +SwiftGenerator::getAbsolute(const ProxyPtr& prx) +{ + return getAbsoluteImpl(prx->_class(), "", "Prx"); +} + +string +SwiftGenerator::getAbsolute(const StructPtr& st) +{ + return getAbsoluteImpl(st); +} + +string +SwiftGenerator::getAbsolute(const ExceptionPtr& ex) +{ + return getAbsoluteImpl(ex); +} + +string +SwiftGenerator::getAbsolute(const EnumPtr& en) +{ + return getAbsoluteImpl(en); +} + +string +SwiftGenerator::getAbsolute(const ConstPtr& en) +{ + return getAbsoluteImpl(en); +} + +string +SwiftGenerator::getAbsolute(const SequencePtr& en) +{ + return getAbsoluteImpl(en); +} + +string +SwiftGenerator::getAbsolute(const DictionaryPtr& en) +{ + return getAbsoluteImpl(en); +} + +string +SwiftGenerator::getUnqualified(const string& type, const string& localModule) +{ + const string prefix = localModule + "."; + return type.find(prefix) == 0 ? type.substr(prefix.size()) : type; +} + +string +SwiftGenerator::modeToString(Operation::Mode opMode) +{ + string mode; + switch(opMode) + { + case Operation::Normal: + { + mode = ".Normal"; + break; + } + case Operation::Nonmutating: + { + mode = ".Nonmutating"; + break; + } + case Operation::Idempotent: + { + mode = ".Idempotent"; + break; + } + default: + { + assert(false); + break; + } + } + return mode; +} + +string +SwiftGenerator::getOptionalFormat(const TypePtr& type) +{ + BuiltinPtr bp = BuiltinPtr::dynamicCast(type); + if(bp) + { + switch(bp->kind()) + { + case Builtin::KindByte: + case Builtin::KindBool: + { + return ".F1"; + } + case Builtin::KindShort: + { + return ".F2"; + } + case Builtin::KindInt: + case Builtin::KindFloat: + { + return ".F4"; + } + case Builtin::KindLong: + case Builtin::KindDouble: + { + return ".F8"; + } + case Builtin::KindString: + { + return ".VSize"; + } + case Builtin::KindObject: + { + return ".Class"; + } + case Builtin::KindObjectProxy: + { + return ".FSize"; + } + case Builtin::KindLocalObject: + { + assert(false); + break; + } + case Builtin::KindValue: + { + return ".Class"; + } + } + } + + if(EnumPtr::dynamicCast(type)) + { + return ".Size"; + } + + SequencePtr seq = SequencePtr::dynamicCast(type); + if(seq) + { + return seq->type()->isVariableLength() ? ".FSize" : ".VSize"; + } + + DictionaryPtr d = DictionaryPtr::dynamicCast(type); + if(d) + { + return (d->keyType()->isVariableLength() || d->valueType()->isVariableLength()) ? + ".FSize" : ".VSize"; + } + + StructPtr st = StructPtr::dynamicCast(type); + if(st) + { + return st->isVariableLength() ? ".FSize" : ".VSize"; + } + + if(ProxyPtr::dynamicCast(type)) + { + return ".FSize"; + } + + ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type); + assert(cl); + return ".Class"; +} + +bool +SwiftGenerator::isNullableType(const TypePtr& type) +{ + BuiltinPtr builtin = BuiltinPtr::dynamicCast(type); + if(builtin) + { + switch(builtin->kind()) + { + case Builtin::KindObject: + case Builtin::KindObjectProxy: + case Builtin::KindLocalObject: + case Builtin::KindValue: + { + return true; + } + default: + { + return false; + } + } + } + + return ClassDeclPtr::dynamicCast(type) || ProxyPtr::dynamicCast(type); +} + +bool +SwiftGenerator::isProxyType(const TypePtr& p) +{ + const BuiltinPtr builtin = BuiltinPtr::dynamicCast(p); + return (builtin && builtin->kind() == Builtin::KindObjectProxy) || ProxyPtr::dynamicCast(p); +} + +bool +SwiftGenerator::isClassType(const TypePtr& p) +{ + const BuiltinPtr builtin = BuiltinPtr::dynamicCast(p); + return (builtin && (builtin->kind() == Builtin::KindObject || + builtin->kind() == Builtin::KindValue)) || + ClassDeclPtr::dynamicCast(p); +} + +bool +SwiftGenerator::containsClassMembers(const StructPtr& s) +{ + DataMemberList dm = s->dataMembers(); + for(DataMemberList::const_iterator i = dm.begin(); i != dm.end(); ++i) + { + if(isClassType((*i)->type())) + { + return true; + } + + StructPtr st = StructPtr::dynamicCast((*i)->type()); + if(st && containsClassMembers(st)) + { + return true; + } + + SequencePtr seq = SequencePtr::dynamicCast((*i)->type()); + if(seq) + { + st = StructPtr::dynamicCast(seq->type()); + if(isClassType(seq->type()) || (st && containsClassMembers(st))) + { + return true; + } + } + + DictionaryPtr dict = DictionaryPtr::dynamicCast((*i)->type()); + if(dict) + { + st = StructPtr::dynamicCast(dict->valueType()); + if(isClassType(dict->valueType()) || (st && containsClassMembers(st))) + { + return true; + } + } + } + return false; +} + +void +SwiftGenerator::writeDefaultInitializer(IceUtilInternal::Output& out, + bool required, + bool rootClass) +{ + out << sp; + out << nl << "public "; + if(required) + { + out << "required "; + } + if(rootClass) + { + out << "init() {}"; + } + else + { + assert(required); + out << "init()"; + out << sb; + out << nl << "super.init()"; + out << eb; + } +} + +void +SwiftGenerator::writeMemberwiseInitializer(IceUtilInternal::Output& out, + const DataMemberList& members, + const ContainedPtr& p) +{ + writeMemberwiseInitializer(out, members, DataMemberList(), members, p, false, true); +} + +void +SwiftGenerator::writeMemberwiseInitializer(IceUtilInternal::Output& out, + const DataMemberList& members, + const DataMemberList& baseMembers, + const DataMemberList& allMembers, + const ContainedPtr& p, + bool local, + bool rootClass, + const StringPairList& extraParams) +{ + if(!members.empty()) + { + out << sp; + out << nl; + int typeCtx = TypeContextInParam; + if(local) + { + typeCtx |= TypeContextLocal; + } + out << "public init" << spar; + for(DataMemberList::const_iterator i = allMembers.begin(); i != allMembers.end(); ++i) + { + DataMemberPtr m = *i; + out << (fixIdent(m->name()) + ": " + + typeToString(m->type(), p, m->getMetaData(), m->optional(), TypeContextInParam)); + } + for(StringPairList::const_iterator q = extraParams.begin(); q != extraParams.end(); ++q) + { + out << (q->first + ": " + q->second); + } + out << epar; + out << sb; + for(DataMemberList::const_iterator i = members.begin(); i != members.end(); ++i) + { + DataMemberPtr m = *i; + out << nl << "self." << fixIdent(m->name()) << " = " << fixIdent(m->name()); + } + + if(!rootClass) + { + out << nl << "super.init"; + out << spar; + for(DataMemberList::const_iterator i = baseMembers.begin(); i != baseMembers.end(); ++i) + { + const string name = fixIdent((*i)->name()); + out << (name + ": " + name); + } + for(StringPairList::const_iterator q = extraParams.begin(); q != extraParams.end(); ++q) + { + out << (q->first + ": " + q->first); + } + out << epar; + } + out << eb; + } +} + +void +SwiftGenerator::writeMembers(IceUtilInternal::Output& out, + const DataMemberList& members, + const ContainedPtr& p, + int typeCtx) +{ + string swiftModule = getSwiftModule(getTopLevelModule(p)); + bool protocol = (typeCtx & TypeContextProtocol); + string access = protocol ? "" : "public "; + for(DataMemberList::const_iterator q = members.begin(); q != members.end(); ++q) + { + DataMemberPtr member = *q; + TypePtr type = member->type(); + string defaultValue = member->defaultValue(); + writeMemberDoc(out, member); + out << nl << access << "var " << fixIdent(member->name()) << ": " + << typeToString(type, p, member->getMetaData(), member->optional(), typeCtx); + if(protocol) + { + out << " { get set }"; + } + else + { + out << " = "; + writeConstantValue(out, type, member->defaultValueType(), defaultValue, p->getMetaData(), swiftModule, + member->optional()); + } + } +} + +bool +SwiftGenerator::usesMarshalHelper(const TypePtr& type) +{ + SequencePtr seq = SequencePtr::dynamicCast(type); + if(seq) + { + BuiltinPtr builtin = BuiltinPtr::dynamicCast(seq->type()); + if(builtin) + { + return builtin->kind() > Builtin::KindString; + } + return true; + } + return DictionaryPtr::dynamicCast(type); +} + +void +SwiftGenerator::writeMarshalUnmarshalCode(Output &out, + const TypePtr& type, + const ContainedPtr& p, + const string& param, + bool marshal, + int tag) +{ + string swiftModule = getSwiftModule(getTopLevelModule(p)); + string stream = StructPtr::dynamicCast(p) ? "self" : marshal ? "ostr" : "istr"; + + string args; + if(tag >= 0) + { + args += "tag: " + int64ToString(tag); + if(marshal) + { + args += ", "; + } + } + + if(marshal) + { + if(tag >= 0 || usesMarshalHelper(type)) + { + args += "value: "; + } + args += param; + } + + BuiltinPtr builtin = BuiltinPtr::dynamicCast(type); + if(builtin) + { + switch(builtin->kind()) + { + case Builtin::KindByte: + case Builtin::KindBool: + case Builtin::KindShort: + case Builtin::KindInt: + case Builtin::KindLong: + case Builtin::KindFloat: + case Builtin::KindDouble: + case Builtin::KindString: + { + if(marshal) + { + out << nl << stream << ".write(" << args << ")"; + } + else + { + out << nl << param << " = try " << stream << ".read(" << args << ")"; + } + break; + } + case Builtin::KindObjectProxy: + { + if(marshal) + { + out << nl << stream << ".write(" << args << ")"; + } + else + { + if(tag >= 0) + { + args += ", type: "; + } + args += getUnqualified(getAbsolute(type), swiftModule) + ".self"; + + out << nl << param << " = try " << stream << ".read(" << args << ")"; + } + break; + } + case Builtin::KindObject: + case Builtin::KindValue: + { + if(marshal) + { + out << nl << stream << ".write(" << args << ")"; + } + else + { + out << nl << "try " << stream << ".read(" << args << ") { " << param << " = $0 }"; + } + break; + } + case Builtin::KindLocalObject: + { + assert(false); + break; + } + default: + { + break; + } + } + } + + if(ClassDeclPtr::dynamicCast(type)) + { + ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type); + if(marshal) + { + out << nl << stream << ".write(" << args << ")"; + } + else + { + if(cl->isInterface()) + { + out << nl << "try " << stream << ".read(" << args << ") { " << param << " = $0 }"; + } + else + { + if(tag >= 0) + { + args += ", value: "; + } + args += getUnqualified(getAbsolute(type), swiftModule) + ".self"; + out << nl << "try " << stream << ".read(" << args << ") { " << param << " = $0 " << "}"; + } + } + return; + } + + EnumPtr en = EnumPtr::dynamicCast(type); + if(en) + { + if(marshal) + { + out << nl << stream << ".write(" << args << ")"; + } + else + { + out << nl << param << " = try " << stream << ".read(" << args << ")"; + } + return; + } + + ProxyPtr prx = ProxyPtr::dynamicCast(type); + if(prx) + { + if(marshal) + { + out << nl << stream << ".write(" << args << ")"; + } + else + { + if(tag >= 0) + { + args += ", type: "; + } + + ClassDefPtr def = prx->_class()->definition(); + if(def->isInterface() || def->allOperations().size() > 0) + { + args += getUnqualified(getAbsolute(type), swiftModule) + ".self"; + } + else + { + args += getUnqualified("Ice.ObjectPrx", swiftModule) + ".self"; + } + out << nl << param << " = try " << stream << ".read(" << args << ")"; + } + return; + } + + if(StructPtr::dynamicCast(type)) + { + if(marshal) + { + out << nl << stream << ".write(" << args << ")"; + } + else + { + out << nl << param << " = try " << stream << ".read(" << args << ")"; + } + return; + } + + SequencePtr seq = SequencePtr::dynamicCast(type); + if(seq) + { + BuiltinPtr seqBuiltin = BuiltinPtr::dynamicCast(seq->type()); + if(seqBuiltin && seqBuiltin->kind() <= Builtin::KindString) + { + if(marshal) + { + out << nl << stream << ".write(" << args << ")"; + } + else + { + out << nl << param << " = try " << stream << ".read(" << args << ")"; + } + } + else + { + string helper = getUnqualified(getAbsoluteImpl(ContainedPtr::dynamicCast(type)), swiftModule) + "Helper"; + if(marshal) + { + out << nl << helper <<".write(to: " << stream << ", " << args << ")"; + } + else + { + out << nl << param << " = try " << helper << ".read(from: " << stream; + if(!args.empty()) + { + out << ", " << args; + } + out << ")"; + } + } + return; + } + + if(DictionaryPtr::dynamicCast(type)) + { + string helper = getUnqualified(getAbsoluteImpl(ContainedPtr::dynamicCast(type)), swiftModule) + "Helper"; + if(marshal) + { + out << nl << helper <<".write(to: " << stream << ", " << args << ")"; + } + else + { + out << nl << param << " = try " << helper << ".read(from: " << stream; + if(!args.empty()) + { + out << ", " << args; + } + out << ")"; + } + return; + } +} + +bool +SwiftGenerator::MetaDataVisitor::visitModuleStart(const ModulePtr& p) +{ + if(UnitPtr::dynamicCast(p->container())) + { + const UnitPtr ut = p->unit(); + const DefinitionContextPtr dc = ut->findDefinitionContext(p->file()); + assert(dc); + + // top-level module + ModulePtr m = ModulePtr::dynamicCast(p); + const string modulePrefix = "swift:module:"; + + string swiftModule; + string swiftPrefix; + + if(m->findMetaData(modulePrefix, swiftModule)) + { + swiftModule = swiftModule.substr(modulePrefix.size()); + + size_t pos = swiftModule.find(':'); + if(pos != string::npos) + { + swiftPrefix = swiftModule.substr(pos + 1); + swiftModule = swiftModule.substr(0, pos); + } + } + else + { + swiftModule = m->name(); + } + + const string filename = m->definitionContext()->filename(); + ModuleMap::const_iterator current = _modules.find(filename); + + if(current == _modules.end()) + { + _modules[filename] = swiftModule; + } + else if(current->second != swiftModule) + { + ostringstream os; + os << "invalid module mapping:\n Slice module `" << m->scoped() << "' should be map to Swift module `" + << current->second << "'" << endl; + dc->error(p->file(), p->line(), os.str()); + } + + ModulePrefix::iterator prefixes = _prefixes.find(swiftModule); + if(prefixes == _prefixes.end()) + { + ModuleMap mappings; + mappings[p->name()] = swiftPrefix; + _prefixes[swiftModule] = mappings; + } + else + { + current = prefixes->second.find(p->name()); + if(current == prefixes->second.end()) + { + prefixes->second[p->name()] = swiftPrefix; + } + else if(current->second != swiftPrefix) + { + ostringstream os; + os << "invalid module prefix:\n Slice module `" << m->scoped() << "' is already using"; + if(current->second.empty()) + { + os << " no prefix " << endl; + } + else + { + os << " a different Swift module prefix `" << current->second << "'" << endl; + } + dc->error(p->file(), p->line(), os.str()); + } + } + } + return true; +} + +string +SwiftGenerator::paramLabel(const string& param, const ParamDeclList& params) +{ + string s = param; + for(ParamDeclList::const_iterator q = params.begin(); q != params.end(); ++q) + { + if((*q)->name() == param) + { + s = "_" + s; + break; + } + } + return s; +} + +bool +SwiftGenerator::operationReturnIsTuple(const OperationPtr& op) +{ + ParamDeclList outParams = op->outParameters(); + return (op->returnType() && outParams.size() > 0) || outParams.size() > 1; +} + +string +SwiftGenerator::operationReturnType(const OperationPtr& op, int typeCtx) +{ + ostringstream os; + bool returnIsTuple = operationReturnIsTuple(op); + if(returnIsTuple) + { + os << "("; + } + + ParamDeclList outParams = op->outParameters(); + TypePtr returnType = op->returnType(); + if(returnType) + { + if(returnIsTuple) + { + os << paramLabel("returnValue", outParams) << ": "; + } + os << typeToString(returnType, op, op->getMetaData(), op->returnIsOptional(), typeCtx); + } + + for(ParamDeclList::const_iterator q = outParams.begin(); q != outParams.end(); ++q) + { + if(returnType || q != outParams.begin()) + { + os << ", "; + } + + if(returnIsTuple) + { + os << (*q)->name() << ": "; + } + + os << typeToString((*q)->type(), *q, (*q)->getMetaData(), (*q)->optional(), typeCtx); + } + + if(returnIsTuple) + { + os << ")"; + } + + return os.str(); +} + +std::string +SwiftGenerator::operationReturnDeclaration(const OperationPtr& op) +{ + ostringstream os; + ParamDeclList outParams = op->outParameters(); + TypePtr returnType = op->returnType(); + bool returnIsTuple = operationReturnIsTuple(op); + + if(returnIsTuple) + { + os << "("; + } + + if(returnType) + { + os << ("iceP_" + paramLabel("returnValue", outParams)); + } + + for(ParamDeclList::const_iterator q = outParams.begin(); q != outParams.end(); ++q) + { + if(returnType || q != outParams.begin()) + { + os << ", "; + } + + os << ("iceP_" + (*q)->name()); + } + + if(returnIsTuple) + { + os << ")"; + } + + return os.str(); +} + +string +SwiftGenerator::operationInParamsDeclaration(const OperationPtr& op) +{ + ostringstream os; + + ParamDeclList inParams = op->inParameters(); + const bool isTuple = inParams.size() > 1; + + if(!inParams.empty()) + { + if(isTuple) + { + os << "("; + } + for(ParamDeclList::const_iterator q = inParams.begin(); q != inParams.end(); ++q) + { + if(q != inParams.begin()) + { + os << ", "; + } + + os << ("iceP_" + (*q)->name()); + } + if(isTuple) + { + os << ")"; + } + + os << ": "; + + if(isTuple) + { + os << "("; + } + for(ParamDeclList::const_iterator q = inParams.begin(); q != inParams.end(); ++q) + { + if(q != inParams.begin()) + { + os << ", "; + } + + os << typeToString((*q)->type(), *q, (*q)->getMetaData(), (*q)->optional()); + } + if(isTuple) + { + os << ")"; + } + } + + return os.str(); +} + +bool +SwiftGenerator::operationIsAmd(const OperationPtr& op) +{ + const ClassDefPtr cl = ClassDefPtr::dynamicCast(op->container()); + return cl->hasMetaData("amd") || op->hasMetaData("amd"); +} + +ParamInfoList +SwiftGenerator::getAllInParams(const OperationPtr& op, int typeCtx) +{ + const ParamDeclList l = op->inParameters(); + ParamInfoList r; + for(ParamDeclList::const_iterator p = l.begin(); p != l.end(); ++p) + { + ParamInfo info; + info.name = (*p)->name(); + info.type = (*p)->type(); + info.typeStr = typeToString(info.type, op, (*p)->getMetaData(), (*p)->optional(), typeCtx); + info.optional = (*p)->optional(); + info.tag = (*p)->tag(); + info.param = *p; + r.push_back(info); + } + return r; +} + +void +SwiftGenerator::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); +} + +ParamInfoList +SwiftGenerator::getAllOutParams(const OperationPtr& op, int typeCtx) +{ + ParamDeclList params = op->outParameters(); + ParamInfoList l; + + for(ParamDeclList::const_iterator p = params.begin(); p != params.end(); ++p) + { + ParamInfo info; + info.name = (*p)->name(); + info.type = (*p)->type(); + info.typeStr = typeToString(info.type, op, (*p)->getMetaData(), (*p)->optional(), typeCtx); + info.optional = (*p)->optional(); + info.tag = (*p)->tag(); + info.param = *p; + l.push_back(info); + } + + if(op->returnType()) + { + ParamInfo info; + info.name = paramLabel("returnValue", params); + info.type = op->returnType(); + info.typeStr = typeToString(info.type, op, op->getMetaData(), op->returnIsOptional(), typeCtx); + info.optional = op->returnIsOptional(); + info.tag = op->returnTag(); + l.push_back(info); + } + + return l; +} + +void +SwiftGenerator::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); +} + +void +SwiftGenerator::writeMarshalInParams(::IceUtilInternal::Output& out, const OperationPtr& op) +{ + ParamInfoList requiredInParams, optionalInParams; + getInParams(op, requiredInParams, optionalInParams); + + out << "{ ostr in"; + out.inc(); + // + // Marshal parameters + // 1. required + // 2. optional + // + + for(ParamInfoList::const_iterator q = requiredInParams.begin(); q != requiredInParams.end(); ++q) + { + writeMarshalUnmarshalCode(out, q->type, op, "iceP_" + q->name, true); + } + + for(ParamInfoList::const_iterator q = optionalInParams.begin(); q != optionalInParams.end(); ++q) + { + writeMarshalUnmarshalCode(out, q->type, op, "iceP_" + q->name, true, q->tag); + } + + if(op->sendsClasses(false)) + { + out << nl << "ostr.writePendingValues()"; + } + out.dec(); + out << nl << "}"; +} + +void +SwiftGenerator::writeMarshalOutParams(::IceUtilInternal::Output& out, const OperationPtr& op) +{ + ParamInfoList requiredOutParams, optionalOutParams; + getOutParams(op, requiredOutParams, optionalOutParams); + + out << "{ ostr in"; + out.inc(); + // + // Marshal parameters + // 1. required + // 2. optional (including optional return) + // + + for(ParamInfoList::const_iterator q = requiredOutParams.begin(); q != requiredOutParams.end(); ++q) + { + writeMarshalUnmarshalCode(out, q->type, op, "iceP_" + q->name, true); + } + + for(ParamInfoList::const_iterator q = optionalOutParams.begin(); q != optionalOutParams.end(); ++q) + { + writeMarshalUnmarshalCode(out, q->type, op, "iceP_" + q->name, true, q->tag); + } + + if(op->returnsClasses(false)) + { + out << nl << "ostr.writePendingValues()"; + } + + out.dec(); + out << nl << "}"; +} + +void +SwiftGenerator::writeUnmarshalOutParams(::IceUtilInternal::Output& out, const OperationPtr& op) +{ + TypePtr returnType = op->returnType(); + + ParamInfoList requiredOutParams, optionalOutParams; + getOutParams(op, requiredOutParams, optionalOutParams); + const ParamInfoList allOutParams = getAllOutParams(op); + // + // Unmarshal parameters + // 1. required + // 2. return + // 3. optional (including optional return) + // + out << "{ istr in"; + out.inc(); + for(ParamInfoList::const_iterator q = requiredOutParams.begin(); q != requiredOutParams.end(); ++q) + { + string param; + if(isClassType(q->type)) + { + out << nl << "var iceP_" << q->name << ": " << q->typeStr; + param = "iceP_" + q->name; + } + else + { + param = "let iceP_" + q->name + ": " + q->typeStr; + } + writeMarshalUnmarshalCode(out, q->type, op, param, false); + } + + for(ParamInfoList::const_iterator q = optionalOutParams.begin(); q != optionalOutParams.end(); ++q) + { + string param; + if(isClassType(q->type)) + { + out << nl << "var iceP_" << q->name << ": " << q->typeStr; + param = "iceP_" + q->name; + } + else + { + param = "let iceP_" + q->name + ": " + q->typeStr; + } + writeMarshalUnmarshalCode(out, q->type, op, param, false, q->tag); + } + + if(op->returnsClasses(false)) + { + out << nl << "try istr.readPendingValues()"; + } + + out << nl << "return "; + if(allOutParams.size() > 1) + { + out << spar; + } + + if(returnType) + { + out << ("iceP_" + paramLabel("returnValue", op->outParameters())); + } + + for(ParamInfoList::const_iterator q = allOutParams.begin(); q != allOutParams.end(); ++q) + { + if(q->param) + { + out << ("iceP_" + q->name); + } + } + + if(allOutParams.size() > 1) + { + out << epar; + } + + out.dec(); + out << nl << "}"; +} + +void +SwiftGenerator::writeUnmarshalInParams(::IceUtilInternal::Output& out, const OperationPtr& op) +{ + ParamInfoList requiredInParams, optionalInParams; + getInParams(op, requiredInParams, optionalInParams); + const ParamInfoList allInParams = getAllInParams(op); + // + // Unmarshal parameters + // 1. required + // 3. optional + // + out << "{ istr in"; + out.inc(); + for(ParamInfoList::const_iterator q = requiredInParams.begin(); q != requiredInParams.end(); ++q) + { + if(q->param) + { + string param; + if(isClassType(q->type)) + { + out << nl << "var iceP_" << q->name << ": " << q->typeStr; + param = "iceP_" + q->name; + } + else + { + param = "let iceP_" + q->name + ": " + q->typeStr; + } + writeMarshalUnmarshalCode(out, q->type, op, param, false); + } + } + + for(ParamInfoList::const_iterator q = optionalInParams.begin(); q != optionalInParams.end(); ++q) + { + string param; + if(isClassType(q->type)) + { + out << nl << "var iceP_" << q->name << ": " << q->typeStr; + param = "iceP_" + q->name; + } + else + { + param = "let iceP_" + q->name + ": " + q->typeStr; + } + writeMarshalUnmarshalCode(out, q->type, op, param, false, q->tag); + } + + if(op->sendsClasses(false)) + { + out << nl << "try istr.readPendingValues()"; + } + + out << nl << "return "; + if(allInParams.size() > 1) + { + out << spar; + } + + for(ParamInfoList::const_iterator q = allInParams.begin(); q != allInParams.end(); ++q) + { + out << ("iceP_" + q->name); + } + + if(allInParams.size() > 1) + { + out << epar; + } + + out.dec(); + out << nl << "}"; +} + +void +SwiftGenerator::writeUnmarshalUserException(::IceUtilInternal::Output& out, const OperationPtr& op) +{ + const string swiftModule = getSwiftModule(getTopLevelModule(ContainedPtr::dynamicCast(op))); + ExceptionList throws = op->throws(); + throws.sort(); + throws.unique(); + + out << "{ ex in"; + out.inc(); + out << nl << "do "; + out << sb; + out << nl << "throw ex"; + out << eb; + for(ExceptionList::const_iterator q = throws.begin(); q != throws.end(); ++q) + { + out << " catch let error as " << getUnqualified(getAbsolute(*q), swiftModule) << sb; + out << nl << "throw error"; + out << eb; + } + out << " catch is " << getUnqualified("Ice.UserException", swiftModule) << " {}"; + out.dec(); + out << nl << "}"; +} + +void +SwiftGenerator::writeSwiftAttributes(::IceUtilInternal::Output& out, const StringList& metadata) +{ + static const string prefix = "swift:attribute:"; + for(StringList::const_iterator q = metadata.begin(); q != metadata.end(); ++q) + { + if(q->find(prefix) == 0 && q->size() > prefix.size()) + { + out << nl << q->substr(prefix.size()); + } + } +} + +void +SwiftGenerator::writeProxyOperation(::IceUtilInternal::Output& out, const OperationPtr& op) +{ + const string opName = fixIdent(op->name()); + + const ParamInfoList allInParams = getAllInParams(op); + const ParamInfoList allOutParams = getAllOutParams(op); + const ExceptionList allExceptions = op->throws(); + + const string swiftModule = getSwiftModule(getTopLevelModule(ContainedPtr::dynamicCast(op))); + + out << sp; + writeOpDocSummary(out, op, false, false); + out << nl << "func " << opName; + out << spar; + for(ParamInfoList::const_iterator q = allInParams.begin(); q != allInParams.end(); ++q) + { + if(allInParams.size() == 1) + { + out << ("_ iceP_" + q->name + ": " + q->typeStr + (q->optional ? " = nil" : "")); + } + else + { + out << (q->name + " iceP_" + q->name + ": " + q->typeStr + (q->optional ? " = nil" : "")); + } + } + out << ("context: " + getUnqualified("Ice.Context", swiftModule) + "? = nil"); + + out << epar; + out << " throws"; + + if(allOutParams.size() > 0) + { + out << " -> " << operationReturnType(op); + } + + out << sb; + + // + // Invoke + // + out << sp; + out << nl; + if(allOutParams.size() > 0) + { + out << "return "; + } + out << "try _impl._invoke("; + + out.useCurrentPosAsIndent(); + out << "operation: \"" << op->name() << "\","; + out << nl << "mode: " << modeToString(op->sendMode()) << ","; + + if(op->format() != DefaultFormat) + { + out << nl << "format: " << opFormatTypeToString(op); + out << ","; + } + + if(allInParams.size() > 0) + { + out << nl << "write: "; + writeMarshalInParams(out, op); + out << ","; + } + + if(allOutParams.size() > 0) + { + out << nl << "read: "; + writeUnmarshalOutParams(out, op); + out << ","; + } + + if(allExceptions.size() > 0) + { + out << nl << "userException:"; + writeUnmarshalUserException(out, op); + out << ","; + } + + out << nl << "context: context)"; + out.restoreIndent(); + + out << eb; +} + +void +SwiftGenerator::writeProxyAsyncOperation(::IceUtilInternal::Output& out, const OperationPtr& op) +{ + const string opName = fixIdent(op->name() + "Async"); + + const ParamInfoList allInParams = getAllInParams(op); + const ParamInfoList allOutParams = getAllOutParams(op); + const ExceptionList allExceptions = op->throws(); + + const string swiftModule = getSwiftModule(getTopLevelModule(ContainedPtr::dynamicCast(op))); + + out << sp; + writeOpDocSummary(out, op, true, false); + out << nl << "func " << opName; + out << spar; + for(ParamInfoList::const_iterator q = allInParams.begin(); q != allInParams.end(); ++q) + { + if(allInParams.size() == 1) + { + out << ("_ iceP_" + q->name + ": " + q->typeStr + (q->optional ? " = nil" : "")); + } + else + { + out << (q->name + " iceP_" + q->name + ": " + q->typeStr + (q->optional ? " = nil" : "")); + } + } + out << "context: " + getUnqualified("Ice.Context", swiftModule) + "? = nil"; + out << "sentOn: Dispatch.DispatchQueue? = PromiseKit.conf.Q.return"; + out << "sentFlags: Dispatch.DispatchWorkItemFlags? = nil"; + out << "sent: ((Swift.Bool) -> Swift.Void)? = nil"; + + out << epar; + out << " -> PromiseKit.Promise<"; + if(allOutParams.empty()) + { + out << "Swift.Void"; + } + else + { + out << operationReturnType(op); + } + out << ">"; + + out << sb; + + // + // Invoke + // + out << sp; + out << nl << "return _impl._invokeAsync("; + + out.useCurrentPosAsIndent(); + out << "operation: \"" << op->name() << "\","; + out << nl << "mode: " << modeToString(op->sendMode()) << ","; + + if(op->format() != DefaultFormat) + { + out << nl << "format: " << opFormatTypeToString(op); + out << ","; + } + + if(allInParams.size() > 0) + { + out << nl << "write: "; + writeMarshalInParams(out, op); + out << ","; + } + + if(allOutParams.size() > 0) + { + out << nl << "read: "; + writeUnmarshalOutParams(out, op); + out << ","; + } + + if(allExceptions.size() > 0) + { + out << nl << "userException:"; + writeUnmarshalUserException(out, op); + out << ","; + } + + out << nl << "context: context,"; + out << nl << "sentOn: sentOn,"; + out << nl << "sentFlags: sentFlags,"; + out << nl << "sent: sent)"; + out.restoreIndent(); + + out << eb; +} + +void +SwiftGenerator::writeDispatchOperation(::IceUtilInternal::Output& out, const OperationPtr& op) +{ + const string opName = op->name(); + + const ParamInfoList allInParams = getAllInParams(op); + const ParamInfoList allOutParams = getAllOutParams(op); + const ExceptionList allExceptions = op->throws(); + + const string swiftModule = getSwiftModule(getTopLevelModule(ContainedPtr::dynamicCast(op))); + + out << sp; + out << nl << "func _iceD_" << opName; + out << spar; + out << ("incoming inS: " + getUnqualified("Ice.Incoming", swiftModule)); + out << ("current: " + getUnqualified("Ice.Current", swiftModule)); + out << epar; + + out << " throws"; + + out << sb; + if(allInParams.empty()) + { + out << nl << "try inS.readEmptyParams()"; + } + else + { + out << nl << "let " << operationInParamsDeclaration(op) << " = try inS.read "; + writeUnmarshalInParams(out, op); + } + + if(op->format() != DefaultFormat) + { + out << nl << "inS.setFormat(" << opFormatTypeToString(op) << ");"; + } + + out << sp; + out << nl; + if(!allOutParams.empty()) + { + out << "let " << operationReturnDeclaration(op) << " = "; + } + out << "try self." << fixIdent(opName); + + out << spar; + for(ParamInfoList::const_iterator q = allInParams.begin(); q != allInParams.end(); ++q) + { + out << (q->name + ": iceP_" + q->name); + } + out << "current: current"; + out << epar; + + out << sp; + if(allOutParams.empty()) + { + out << nl << "inS.writeEmptyParams()"; + } + else + { + out << nl << "inS.write "; + writeMarshalOutParams(out, op); + } + + out << eb; +} + +void +SwiftGenerator::writeDispatchAsyncOperation(::IceUtilInternal::Output& out, const OperationPtr& op) +{ + const ParamInfoList allInParams = getAllInParams(op); + const ParamInfoList allOutParams = getAllOutParams(op); + + const string swiftModule = getSwiftModule(getTopLevelModule(ContainedPtr::dynamicCast(op))); + + out << sp; + out << nl << "func _iceD_" << op->name(); + out << spar; + out << ("incoming inS: " + getUnqualified("Ice.Incoming", swiftModule)); + out << ("current: " + getUnqualified("Ice.Current", swiftModule)); + out << epar; + + out << " throws"; + + out << sb; + if(allInParams.empty()) + { + out << nl << "try inS.readEmptyParams()"; + } + else + { + out << nl << "let " << operationInParamsDeclaration(op) << " = try inS.read "; + writeUnmarshalInParams(out, op); + } + + if(op->format() != DefaultFormat) + { + out << nl << "inS.setFormat(" << opFormatTypeToString(op) << ");"; + } + + out << sp; + out << nl; + out << "firstly"; + out << sb; + out << nl << fixIdent(op->name() + (operationIsAmd(op) ? "Async" : "")); + + out << spar; + for(ParamInfoList::const_iterator q = allInParams.begin(); q != allInParams.end(); ++q) + { + out << (q->name + ": iceP_" + q->name); + } + out << "current: current"; + out << epar; + out << eb; + + out << ".done(on: nil)"; + out << sb; + if(allOutParams.empty()) + { + out << nl << "inS.writeEmptyParams()"; + } + else + { + out << " " << operationReturnDeclaration(op) << " in"; + out << nl << "inS.write "; + writeMarshalOutParams(out, op); + } + out << eb; + + out << ".catch(on: nil)"; + out << sb; + out << " err in"; + out << nl << "inS.exception(err)"; + out << eb; + + out << eb; +} + +bool +SwiftGenerator::MetaDataVisitor::visitClassDefStart(const ClassDefPtr& p) +{ + validate(p); + return true; +} + +bool +SwiftGenerator::MetaDataVisitor::visitExceptionStart(const ExceptionPtr& p) +{ + validate(p); + return true; +} + +bool +SwiftGenerator::MetaDataVisitor::visitStructStart(const StructPtr& p) +{ + validate(p); + return true; +} + +void +SwiftGenerator::MetaDataVisitor::visitSequence(const SequencePtr& p) +{ + validate(p); +} + +void +SwiftGenerator::MetaDataVisitor::visitDictionary(const DictionaryPtr& p) +{ + validate(p); +} + +void +SwiftGenerator::MetaDataVisitor::visitEnum(const EnumPtr& p) +{ + validate(p); +} + +void +SwiftGenerator::MetaDataVisitor::visitConst(const ConstPtr& p) +{ + validate(p); +} + +void +SwiftGenerator::MetaDataVisitor::validate(const ContainedPtr&) +{ +} |