summaryrefslogtreecommitdiff
path: root/cpp/src/slice2swift/SwiftUtil.cpp
diff options
context:
space:
mode:
authorJoe George <joe@zeroc.com>2019-02-18 13:21:34 -0500
committerJoe George <joe@zeroc.com>2019-02-18 13:21:34 -0500
commit68fa96c625a683f7cae45d5f6c646b9b5c269b3a (patch)
tree59ba0f3e2e839d233f724289b4b178108109674b /cpp/src/slice2swift/SwiftUtil.cpp
parentFixed formatting bug (diff)
downloadice-68fa96c625a683f7cae45d5f6c646b9b5c269b3a.tar.bz2
ice-68fa96c625a683f7cae45d5f6c646b9b5c269b3a.tar.xz
ice-68fa96c625a683f7cae45d5f6c646b9b5c269b3a.zip
Initial commit of Swift mapping
Diffstat (limited to 'cpp/src/slice2swift/SwiftUtil.cpp')
-rw-r--r--cpp/src/slice2swift/SwiftUtil.cpp931
1 files changed, 931 insertions, 0 deletions
diff --git a/cpp/src/slice2swift/SwiftUtil.cpp b/cpp/src/slice2swift/SwiftUtil.cpp
new file mode 100644
index 00000000000..c7dd5c5f42c
--- /dev/null
+++ b/cpp/src/slice2swift/SwiftUtil.cpp
@@ -0,0 +1,931 @@
+
+// **********************************************************************
+//
+// Copyright (c) 2003-2018 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/OutputUtil.h>
+#include <IceUtil/StringUtil.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", "break", "case", "catch", "class", "continue", "default", "defer", "deinit",
+ "do", "else", "enum", "extension", "fallthrough", "false", "fileprivate", "for", "func", "guard", "if",
+ "import", "in", "init", "inout", "internal", "is", "let", "nil", "open", "operator", "private", "protocol",
+ "public", "repeat", "rethrows", "return", "self", "Self", "static", "struct", "subscript", "super", "switch",
+ "throw", "throws", "true", "try", "typealias", "var", "where", "while"
+ };
+ 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;
+}
+
+//
+// Split a scoped name into its components and return the components as a list of (unscoped) identifiers.
+//
+static StringList
+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;
+}
+
+static StringList
+fixIds(const StringList& ids)
+{
+ StringList newIds;
+ for(StringList::const_iterator i = ids.begin(); i != ids.end(); ++i)
+ {
+ newIds.push_back(lookupKwd(*i));
+ }
+ return newIds;
+}
+
+}
+
+SwiftGenerator::ModuleMap SwiftGenerator::_modules;
+
+void
+SwiftGenerator::validateMetaData(const UnitPtr& u)
+{
+ MetaDataVisitor visitor;
+ u->visit(&visitor, true);
+}
+
+bool
+SwiftGenerator::addModule(const ModulePtr& m, const string& module, const string& name)
+{
+ string scoped = m->scoped();
+ ModuleMap::const_iterator i = _modules.find(scoped);
+ if(i != _modules.end())
+ {
+ if(i->second.module != module || i->second.name != name)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ ModulePrefix mp;
+ mp.m = m;
+ mp.module = module;
+ mp.name = name;
+ _modules[scoped] = mp;
+ }
+ return true;
+}
+
+SwiftGenerator::ModulePrefix
+SwiftGenerator::modulePrefix(const ModulePtr& m)
+{
+ return _modules[m->scoped()];
+}
+
+string
+SwiftGenerator::moduleName(const ModulePtr& m)
+{
+ return _modules[m->scoped()].name;
+}
+
+ModulePtr
+SwiftGenerator::findModule(const ContainedPtr& cont)
+{
+ ModulePtr m = ModulePtr::dynamicCast(cont);
+ ContainerPtr container = cont->container();
+ while(container && !m)
+ {
+ ContainedPtr contained = ContainedPtr::dynamicCast(container);
+ container = contained->container();
+ m = ModulePtr::dynamicCast(contained);
+ }
+ assert(m);
+ return m;
+}
+
+string
+SwiftGenerator::getLocalScope(const string& scope, const string& separator)
+{
+ assert(!scope.empty());
+
+ //
+ // Remove trailing "::" if present.
+ //
+ string fixedScope;
+ if(scope[scope.size() - 1] == ':')
+ {
+ assert(scope[scope.size() - 2] == ':');
+ fixedScope = scope.substr(0, scope.size() - 2);
+ }
+ else
+ {
+ fixedScope = scope;
+ }
+ if(fixedScope.empty())
+ {
+ return "";
+ }
+ const StringList ids = fixIds(splitScopedName(fixedScope));
+
+ //
+ // Return local scope for "::A::B::C" as A.B.C
+ //
+ stringstream result;
+ for(StringList::const_iterator i = ids.begin(); i != ids.end(); ++i)
+ {
+ if(i != ids.begin())
+ {
+ result << separator;
+ }
+ result << *i;
+ }
+ return result.str();
+
+}
+
+string
+SwiftGenerator::typeToString(const TypePtr& type, const ContainedPtr& c)
+{
+ static const char* builtinTable[] =
+ {
+ "UInt8",
+ "Bool",
+ "Int16",
+ "Int32",
+ "Int64",
+ "Float",
+ "Double",
+ "String",
+ "Ice.Object", // Object
+ "Ice.ObjectPrx", // ObjectPrx
+ "AnyObject", // LocalObject
+ "Ice.Value" // Value
+ };
+
+ if(!type)
+ {
+ return "";
+ }
+
+ const bool hasNonOptionalMetadata = c && c->hasMetaData("swift:non-optional");
+ const ParamDeclPtr p = ParamDeclPtr::dynamicCast(c);
+ const bool isOptionalParam = p && p->optional();
+
+ string str;
+ bool optional = isOptionalParam || (!isValueType(type) && !hasNonOptionalMetadata);
+
+ BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
+ if(builtin)
+ {
+ str = builtinTable[builtin->kind()];
+ return optional ? str + "?" : str;
+ }
+
+ ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
+ if(cl)
+ {
+ str = getAbsolute(cl);
+
+ if(cl->isLocal())
+ {
+ const ClassDefPtr def = cl->definition();
+ if(p && def && def->isDelegate())
+ {
+
+ // Swift closures are @escaping by default
+ if(p->hasMetaData("swift:non-optional"))
+ {
+ return "@escaping " + str;
+ }
+ else
+ {
+ return str + "?";
+ }
+ }
+ }
+ return optional ? str + "?" : str;
+ }
+
+ ProxyPtr proxy = ProxyPtr::dynamicCast(type);
+ if(proxy)
+ {
+ str = getAbsolute(proxy->_class(), "", "Prx");
+ return optional ? str + "?" : str;
+ }
+
+ DictionaryPtr dict = DictionaryPtr::dynamicCast(type);
+ if(dict)
+ {
+ str = getAbsolute(dict);
+ return optional ? str + "?" : str;
+ }
+
+ ContainedPtr contained = ContainedPtr::dynamicCast(type);
+ if(contained)
+ {
+ str = getAbsolute(contained);
+ return optional ? str + "?" : str;
+ }
+
+ return "???";
+}
+
+std::string
+SwiftGenerator::typeToProxyImpl(const TypePtr& type)
+{
+ BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
+ if(builtin)
+ {
+ switch(builtin->kind())
+ {
+ case Builtin::KindObjectProxy:
+ {
+ return "_ObjectPrxI";
+ break;
+ }
+ default:
+ {
+ assert(false);
+ break;
+ }
+ }
+
+ }
+ ProxyPtr proxy = ProxyPtr::dynamicCast(type);
+ if(proxy)
+ {
+ return getAbsolute(proxy->_class(), "_", "PrxI");
+ }
+
+ return "???";
+}
+
+//
+// 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.
+//
+std::string
+SwiftGenerator::fixIdent(const std::string& ident)
+{
+ if(ident[0] != ':')
+ {
+ return lookupKwd(ident);
+ }
+ StringList ids = splitScopedName(ident);
+ transform(ids.begin(), ids.end(), ids.begin(), ptr_fun(lookupKwd));
+ stringstream result;
+ for(StringList::const_iterator i = ids.begin(); i != ids.end(); ++i)
+ {
+ result << "::" + *i;
+ }
+ return result.str();
+}
+
+std::string
+SwiftGenerator::fixName(const ContainedPtr& cont)
+{
+ return moduleName(findModule(cont)) + cont->name();
+}
+
+//
+// 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.
+//
+std::string
+SwiftGenerator::getAbsolute(const ContainedPtr& cont,
+ const string& pfx,
+ const string& suffix)
+{
+ string str = fixIdent(cont->scope() + pfx + cont->name() + suffix);
+ if(str.find("::") == 0)
+ {
+ str.erase(0, 2);
+ }
+
+ return replace(str, "::", ".");
+}
+
+std::string
+SwiftGenerator::modeToString(Operation::Mode opMode)
+{
+ string mode;
+ switch(opMode)
+ {
+ case Operation::Normal:
+ {
+ mode = "Ice.OperationMode.Normal";
+ break;
+ }
+ case Operation::Nonmutating:
+ {
+ mode = "Ice.OperationMode.Nonmutating";
+ break;
+ }
+ case Operation::Idempotent:
+ {
+ mode = "Ice.OperationMode.Idempotent";
+ break;
+ }
+ default:
+ {
+ assert(false);
+ break;
+ }
+ }
+ return mode;
+}
+
+bool
+SwiftGenerator::isObjcRepresentable(const TypePtr& type)
+{
+ return BuiltinPtr::dynamicCast(type);
+}
+
+bool
+SwiftGenerator::isObjcRepresentable(const DataMemberList& members)
+{
+ for(DataMemberList::const_iterator q = members.begin(); q != members.end(); ++q)
+ {
+ if(!isObjcRepresentable((*q)->type()))
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool
+SwiftGenerator::isValueType(const TypePtr& type)
+{
+ if(!type)
+ {
+ return true;
+ }
+ BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
+ if(builtin)
+ {
+ switch(builtin->kind())
+ {
+ case Builtin::KindObject:
+ case Builtin::KindObjectProxy:
+ case Builtin::KindLocalObject:
+ case Builtin::KindValue:
+ {
+ return false;
+ break;
+ }
+ default:
+ {
+ return true;
+ break;
+ }
+ }
+ }
+
+ ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
+ if(cl)
+ {
+ return false;
+ }
+
+ ProxyPtr proxy = ProxyPtr::dynamicCast(type);
+ if(proxy)
+ {
+ return false;
+ }
+
+ DictionaryPtr dict = DictionaryPtr::dynamicCast(type);
+ if(dict)
+ {
+ return true;
+ }
+
+ ContainedPtr contained = ContainedPtr::dynamicCast(type);
+ if(contained)
+ {
+ return true;
+ }
+
+ return true;
+}
+
+bool
+SwiftGenerator::isProxyType(const TypePtr& p)
+{
+ const BuiltinPtr builtin = BuiltinPtr::dynamicCast(p);
+ return (builtin && builtin->kind() == Builtin::KindObjectProxy) || ProxyPtr::dynamicCast(p);
+}
+
+void
+SwiftGenerator::writeTuple(IceUtilInternal::Output& out, const StringList& tuple)
+{
+ if(tuple.size() > 1)
+ {
+ out << "(";
+ }
+
+ for(StringList::const_iterator q = tuple.begin(); q != tuple.end(); ++q)
+ {
+ if(q != tuple.begin())
+ {
+ out << ", ";
+ }
+ out << (*q);
+ }
+ if(tuple.size() > 1)
+ {
+ out << ")";
+ }
+}
+
+void
+SwiftGenerator::writeDataMembers(IceUtilInternal::Output& out, const DataMemberList& members, bool writeGetter)
+{
+ for(DataMemberList::const_iterator q = members.begin(); q != members.end(); ++q)
+ {
+ const TypePtr type = (*q)->type();
+ out << nl;
+
+ // not a protocol
+ if(!writeGetter)
+ {
+ out << "public ";
+ }
+
+ out << "var " << (*q)->name() << ": " << typeToString(type, (*q));
+
+ // protocol
+ if(writeGetter)
+ {
+ out << " { get }";
+ }
+ }
+}
+
+void
+SwiftGenerator::writeInitializer(IceUtilInternal::Output& out,
+ const DataMemberList& members,
+ const DataMemberList& allMembers)
+{
+
+ DataMemberList baseMembers;
+
+ for(DataMemberList::const_iterator q = allMembers.begin(); q != allMembers.end(); ++q)
+ {
+ if(find(members.begin(), members.end(), *q) == members.end())
+ {
+ baseMembers.push_back(*q);
+ }
+ }
+
+ // initializer
+ out << nl << "public init";
+ writeInitializerMembers(out, allMembers.empty() ? members : allMembers);
+ out << sb;
+
+ for(DataMemberList::const_iterator q = members.begin(); q != members.end(); ++q)
+ {
+ const string n = (*q)->name();
+ out << nl << "self." << n << " = " << n;
+ }
+
+ // call base class init
+ if(!baseMembers.empty())
+ {
+ out << nl << "super.init";
+ writeInitializerMembers(out, baseMembers, false);
+ }
+
+ out << eb;
+}
+
+void
+SwiftGenerator::writeInitializerMembers(IceUtilInternal::Output& out, const DataMemberList& members, bool useType)
+{
+ out << "(";
+ for(DataMemberList::const_iterator q = members.begin(); q != members.end(); ++q)
+ {
+ if(q != members.begin())
+ {
+ out << ", ";
+ }
+ out << (*q)->name();
+
+ if(useType)
+ {
+ out << ": " << typeToString((*q)->type(), *q);
+ }
+ else
+ {
+ out << ": " << (*q)->name();
+ }
+ }
+ out << ")";
+}
+
+void
+SwiftGenerator::writeOperation(IceUtilInternal::Output& out, const OperationPtr& op, bool)
+{
+ const string opName = op->name();
+ StringList metaData = op->getMetaData();
+ ExceptionList throws = op->throws();
+ const ParamDeclList outParams = op->outParameters();
+ StringList returns;
+ throws.sort();
+ throws.unique();
+
+ out << nl << "func " << opName;
+ writeOperationsParameters(out, op->parameters());
+ //TODO: remove cpp:noexcept once swift:nothrow is everywhere
+ if(!op->hasMetaData("cpp:noexcept") && !op->hasMetaData("swift:nothrow"))
+ {
+ out << " throws";
+ }
+
+ string ret = typeToString(op->returnType(), op);
+ if(!ret.empty())
+ {
+ returns.push_back(ret);
+ }
+
+ for(ParamDeclList::const_iterator p = outParams.begin(); p != outParams.end(); ++p)
+ {
+ returns.push_back(typeToString((*p)->type()));
+ }
+
+ if(!returns.empty())
+ {
+ out << " -> ";
+ writeTuple(out, returns);
+ }
+}
+
+void
+SwiftGenerator::writeOperationsParameters(IceUtilInternal::Output& out, const ParamDeclList& parameters)
+{
+ out << "(";
+ for(ParamDeclList::const_iterator q = parameters.begin(); q != parameters.end() && !(*q)->isOutParam(); ++q)
+ {
+
+ if(q != parameters.begin())
+ {
+ out << ", ";
+ }
+
+ out << (*q)->name() << ": " << typeToString((*q)->type(), *q);
+ }
+ out << ")";
+}
+
+void
+SwiftGenerator::writeCastFuncs(IceUtilInternal::Output& out, const ClassDefPtr& p)
+{
+ const string prx = fixName(p) + "Prx";
+ const string prxImpl = "_" + prx + "I";
+ out << nl << "public func checkedCast(prx: ObjectPrx, type: " << prx << ".Protocol, ";
+ out << "facet: String? = nil, context: Context? = nil) throws -> " << prx << "?";
+ out << sb << nl;
+ out << "return try " << prxImpl << ".checkedCast(prx: prx, facet: facet, context: context) as " << prxImpl << "?";
+ out << eb << nl;
+
+ out << nl << "public func uncheckedCast(prx: ObjectPrx, type: " << prx << ".Protocol, ";
+ out << "facet: String? = nil, context: Context? = nil) -> " << prx << "?";
+ out << sb << nl;
+ out << "return " << prxImpl << ".uncheckedCast(prx: prx, facet: facet, context: context) as " << prxImpl << "?";
+ out << eb << nl;
+
+ out << nl << "public extension Ice.InputStream";
+ out << sb << nl;
+ out << "func read(proxy: " << prx << ".Protocol) throws -> " << prx << "?";
+ out << sb << nl;
+ out << "return try " << prxImpl << ".ice_read(from: self)";
+ out << eb << nl;
+
+ out << "func read(proxyArray: " << prx << ".Protocol) throws -> [" << prx << "?]";
+ out << sb << nl;
+ // out << "return try " << prxImpl << ".ice_read(from: self)";
+ out << "#warning(\"add generated proxy arrays\")" << nl;
+ out << "preconditionFailure(\"TODO\")";
+ out << eb << nl;
+ out << eb << nl;
+}
+
+void
+SwiftGenerator::writeStaticId(IceUtilInternal::Output& out, const ClassDefPtr& p)
+{
+ const string prx = fixName(p) + "Prx";
+ const string prxImpl = "_" + prx + "I";
+
+ out << nl << "public func ice_staticId(_: " << prx << ".Protocol) -> String";
+ out << sb << nl;
+ out << "return " << prxImpl << ".ice_staticId()";
+ out << eb << nl;
+}
+
+void
+SwiftGenerator::writeMarshalUnmarshalCode(IceUtilInternal::Output& out, const ClassDefPtr& p, const OperationPtr& op)
+{
+ const string prx = fixName(p) + "Prx";
+ const string proxyImpl = "_" + prx + "I";
+ const string returnType = typeToString(op->returnType());
+ const ParamDeclList inParams = op->inParameters();
+ const ParamDeclList outParams = op->outParameters();
+ const bool returnsData = op->returnsData();
+ const bool returnsInputStream = !op->outParameters().empty() || op->returnType();
+ StringList returnTuple;
+
+ out << "let impl = self as! " << proxyImpl;
+ out << nl << "let os = impl._createOutputStream()";
+ out << nl << "os.startEncapsulation()";
+
+ for(ParamDeclList::const_iterator q = inParams.begin(); q != inParams.end(); ++q)
+ {
+ const SequencePtr sequence = SequencePtr::dynamicCast(op->returnType());
+ if(isProxyType((*q)->type()))
+ {
+ out << nl << "os.write(proxy: " << (*q)->name() << ")";
+ }
+ else if(sequence && isProxyType(sequence->type()))
+ {
+ out << nl << "os.write(proxyArray: " << (*q)->name() << ")";
+ }
+ else
+ {
+ out << nl << (*q)->name() << ".ice_write(to: os)";
+
+ }
+ }
+ out << nl << "os.endEncapsulation()";
+
+ out << nl << "let " << (returnsInputStream ? "ins " : "_ ");
+ out << "= try impl._invoke(";
+
+ out.useCurrentPosAsIndent();
+ out << "operation: \"" << op->name() << "\",";
+ out << nl << "mode: " << modeToString(op->mode()) << ",";
+ out << nl << "twowayOnly: " << (returnsData ? "true" : "false") << ",";
+ out << nl << "inParams: os,";
+ out << nl << "hasOutParams: " << (op->outParameters().empty() ? "false" : "true");
+ out << ")";
+ out.restoreIndent();
+ out << nl;
+
+ //
+ // TODO: Sequence and optioanl read (eg. optional tags and array min size)
+ //
+
+ for(ParamDeclList::const_iterator q = outParams.begin(); q != outParams.end(); ++q)
+ {
+ out << "let " << (*q)->name() << " = try " << typeToString((*q)->type()) << "(from: ins)";
+ returnTuple.push_back((*q)->name());
+ }
+
+ if(!returnType.empty())
+ {
+ const SequencePtr sequence = SequencePtr::dynamicCast(op->returnType());
+ if(isProxyType(op->returnType()))
+ {
+ const ProxyPtr proxy = ProxyPtr::dynamicCast(op->returnType());
+ if(proxy)
+ {
+ const string retPrx = getAbsolute(proxy->_class(), "", "Prx");
+ out << nl << "let ret = try ins.read(proxy: " << retPrx << ".self)";
+ }
+ else
+ {
+ out << nl << "let ret = try ins.read(proxy: ObjectPrx.self)";
+ }
+ returnTuple.push_front("ret");
+ }
+ else if(sequence && isProxyType(sequence->type()))
+ {
+ const ProxyPtr proxy = ProxyPtr::dynamicCast(op->returnType());
+ if(proxy)
+ {
+ const string retPrx = getAbsolute(proxy->_class(), "", "Prx");
+ out << nl << "let ret = try ins.read(proxyArray: " << retPrx << ".self)";
+ }
+ else
+ {
+ out << nl << "let ret = try ins.read(proxyArray: ObjectPrx.self)";
+ }
+ returnTuple.push_front("ret");
+ }
+ else if(op->returnIsOptional())
+ {
+ out << nl << "var ret: " << returnType;
+ out << nl << "try " << "ret.ice_read(from: ins)";
+ returnTuple.push_front("ret");
+ }
+ else
+ {
+ out << nl << "var ret = " << returnType << "()";
+ out << nl << "try " << "ret.ice_read(from: ins)";
+ returnTuple.push_front("ret");
+ }
+ }
+
+ if(!returnTuple.empty())
+ {
+ out << nl << "return ";
+ writeTuple(out, returnTuple);
+ }
+}
+
+const string SwiftGenerator::MetaDataVisitor::_msg= "ignoring invalid metadata";
+
+bool
+SwiftGenerator::MetaDataVisitor::visitModuleStart(const ModulePtr& p)
+{
+ validate(p);
+ return true;
+}
+
+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& cont)
+{
+ ModulePtr m = ModulePtr::dynamicCast(cont);
+ if(m)
+ {
+ bool error = false;
+ bool found = false;
+ StringList meta = cont->getMetaData();
+
+ for(StringList::iterator p = meta.begin(); p != meta.end();)
+ {
+ string s = *p++;
+
+ // Module metadata must be of the form swift:module:{{modulename}}:{{prefix}}
+ const string modulePrefix = "swift:module:";
+ string module;
+ string prefix;
+ if(s.find(modulePrefix) == 0)
+ {
+ found = true;
+ string metadata = trim(s.substr(modulePrefix.size()));
+
+ size_t pos = metadata.find(":");
+ if(pos != string::npos)
+ {
+ module = metadata.substr(0, pos);
+ prefix = metadata.substr(pos+1, metadata.size());
+ }
+
+ if(module.empty() || prefix.empty())
+ {
+ m->definitionContext()->warning(InvalidMetaData, m->definitionContext()->filename(),
+ m->line(), _msg + " `" + s + "'");
+ meta.remove(s);
+ error = true;
+ }
+ else
+ {
+ if(!addModule(m, module, prefix))
+ {
+ modulePrefixError(m, s);
+ }
+ }
+ }
+ // else
+ // {
+ // m->definitionContext()->warning(InvalidMetaData, m->definitionContext()->filename(),
+ // m->line(), _msg + " `" + s + "'");
+ // meta.remove(s);
+ // error = true;
+ // }
+ }
+ m->setMetaData(meta);
+ }
+}
+
+void
+SwiftGenerator::MetaDataVisitor::modulePrefixError(const ModulePtr& m, const std::string& metadata)
+{
+ string file = m->definitionContext()->filename();
+ string line = m->line();
+ ModulePrefix mp = modulePrefix(m);
+ string old_file = mp.m->definitionContext()->filename();
+ string old_line = mp.m->line();
+ ostringstream os;
+ if(!metadata.empty())
+ {
+ os << _msg << " `" << metadata << "': ";
+ }
+ os << "inconsistent module prefix previously defined ";
+ if(old_file != file)
+ {
+ os << "in " << old_file << ":";
+ }
+ else
+ {
+ os << "at line ";
+ }
+ os << line;
+ os << " as `" << mp.name << "'" << endl;
+ m->definitionContext()->warning(All, file, line, os.str());
+}