summaryrefslogtreecommitdiff
path: root/cpp/src
diff options
context:
space:
mode:
authorJose <jose@zeroc.com>2018-10-16 00:53:00 +0200
committerJose <jose@zeroc.com>2018-10-16 00:53:00 +0200
commitcf8292f9cdadcb6619287ada4f5273c25c5a3cfb (patch)
tree4a227f287d2a5e22e36b1f488f00a3c96add7a44 /cpp/src
parentUpdated VS2017 requirement (diff)
downloadice-cf8292f9cdadcb6619287ada4f5273c25c5a3cfb.tar.bz2
ice-cf8292f9cdadcb6619287ada4f5273c25c5a3cfb.tar.xz
ice-cf8292f9cdadcb6619287ada4f5273c25c5a3cfb.zip
Typescript support
Diffstat (limited to 'cpp/src')
-rw-r--r--cpp/src/Slice/Parser.cpp11
-rw-r--r--cpp/src/Slice/Parser.h2
-rw-r--r--cpp/src/Slice/SliceUtil.cpp4
-rw-r--r--cpp/src/slice2js/Gen.cpp1605
-rw-r--r--cpp/src/slice2js/Gen.h93
-rw-r--r--cpp/src/slice2js/JsUtil.cpp496
-rw-r--r--cpp/src/slice2js/JsUtil.h34
-rw-r--r--cpp/src/slice2js/Main.cpp31
8 files changed, 2036 insertions, 240 deletions
diff --git a/cpp/src/Slice/Parser.cpp b/cpp/src/Slice/Parser.cpp
index 19ed36efd5f..e1be83afdc4 100644
--- a/cpp/src/Slice/Parser.cpp
+++ b/cpp/src/Slice/Parser.cpp
@@ -362,10 +362,11 @@ Slice::SyntaxTreeBase::visit(ParserVisitor*, bool)
{
}
-Slice::SyntaxTreeBase::SyntaxTreeBase(const UnitPtr& unit) :
- _unit(unit)
+Slice::SyntaxTreeBase::SyntaxTreeBase(const UnitPtr& unit, const DefinitionContextPtr& definitionContext) :
+ _unit(unit),
+ _definitionContext(definitionContext)
{
- if(_unit)
+ if(!_definitionContext && _unit)
{
_definitionContext = unit->currentDefinitionContext();
}
@@ -4359,8 +4360,8 @@ Slice::Proxy::_class() const
}
Slice::Proxy::Proxy(const ClassDeclPtr& cl) :
- SyntaxTreeBase(cl->unit()),
- Type(cl->unit()),
+ SyntaxTreeBase(cl->unit(), cl->definitionContext()),
+ Type(cl->unit()),
_classDecl(cl)
{
}
diff --git a/cpp/src/Slice/Parser.h b/cpp/src/Slice/Parser.h
index 736c6c3c59c..219c14ae151 100644
--- a/cpp/src/Slice/Parser.h
+++ b/cpp/src/Slice/Parser.h
@@ -319,7 +319,7 @@ public:
protected:
- SyntaxTreeBase(const UnitPtr&);
+ SyntaxTreeBase(const UnitPtr&, const DefinitionContextPtr& = 0);
UnitPtr _unit;
DefinitionContextPtr _definitionContext;
diff --git a/cpp/src/Slice/SliceUtil.cpp b/cpp/src/Slice/SliceUtil.cpp
index ae45fe5967d..85dee38106c 100644
--- a/cpp/src/Slice/SliceUtil.cpp
+++ b/cpp/src/Slice/SliceUtil.cpp
@@ -44,6 +44,10 @@ normalizePath(const string& path)
{
startReplace = 2;
}
+ else
+ {
+ result[0] = toUpper(result.substr(0, 1))[0];
+ }
#endif
string::size_type pos;
while((pos = result.find("//", startReplace)) != string::npos)
diff --git a/cpp/src/slice2js/Gen.cpp b/cpp/src/slice2js/Gen.cpp
index 7a4e61f3115..be159aa206b 100644
--- a/cpp/src/slice2js/Gen.cpp
+++ b/cpp/src/slice2js/Gen.cpp
@@ -11,19 +11,11 @@
#include <IceUtil/StringUtil.h>
#include <IceUtil/InputUtil.h>
#include <Gen.h>
-#include <limits>
-#include <sys/stat.h>
-#ifndef _WIN32
-#include <unistd.h>
-#else
-#include <direct.h>
-#endif
#include <IceUtil/Iterator.h>
#include <IceUtil/UUID.h>
#include <Slice/Checksum.h>
#include <Slice/FileTracker.h>
#include <Slice/Util.h>
-#include <string.h>
using namespace std;
using namespace Slice;
@@ -86,9 +78,289 @@ getDeprecateReason(const ContainedPtr& p1, const ContainedPtr& p2, const string&
return deprecateReason;
}
+void
+printHeader(IceUtilInternal::Output& out)
+{
+ static const char* header =
+ "// **********************************************************************\n"
+ "//\n"
+ "// Copyright (c) 2003-2018 ZeroC, Inc. All rights reserved.\n"
+ "//\n"
+ "// This copy of Ice is licensed to you under the terms described in the\n"
+ "// ICE_LICENSE file included in this distribution.\n"
+ "//\n"
+ "// **********************************************************************\n"
+ ;
+
+ out << header;
+ out << "//\n";
+ out << "// Ice version " << ICE_STRING_VERSION << "\n";
+ out << "//\n";
+}
+
+string
+escapeParam(const ParamDeclList& params, const string& name)
+{
+ string r = name;
+ for(ParamDeclList::const_iterator p = params.begin(); p != params.end(); ++p)
+ {
+ if(Slice::JsGenerator::fixId((*p)->name()) == name)
+ {
+ r = name + "_";
+ break;
+ }
+ }
+ return r;
+}
+
+void
+writeDocLines(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
+writeSeeAlso(Output& out, const StringList& lines, const string& space = " ")
+{
+ for(StringList::const_iterator i = lines.begin(); i != lines.end(); ++i)
+ {
+ out << nl << " *";
+ if(!i->empty())
+ {
+ out << space << "@see " << *i;
+ }
+ }
+}
+
+string
+getDocSentence(const StringList& lines)
+{
+ //
+ // Extract the first sentence.
+ //
+ ostringstream ostr;
+ 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)
+ {
+ ostr << " ";
+ }
+ string::size_type pos = i->find('.');
+ if(pos == string::npos)
+ {
+ ostr << *i;
+ }
+ else if(pos == i->size() - 1)
+ {
+ ostr << *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)
+ {
+ ostr << i->substr(0, pos + 1);
+ break;
+ }
+ else
+ {
+ ostr << *i;
+ }
+ }
+ }
+
+ return ostr.str();
+}
+
+void
+writeDocSummary(Output& out, const ContainedPtr& p)
+{
+ if(p->comment().empty())
+ {
+ return;
+ }
+
+ CommentPtr doc = p->parseComment(false);
+
+ out << nl << "/**";
+
+ if(!doc->overview().empty())
+ {
+ writeDocLines(out, doc->overview(), true);
+ }
+
+ if(!doc->misc().empty())
+ {
+ writeDocLines(out, doc->misc(), true);
+ }
+
+ if(!doc->seeAlso().empty())
+ {
+ writeSeeAlso(out, doc->seeAlso());
+ }
+
+ if(!doc->deprecated().empty())
+ {
+ out << nl << " *";
+ out << nl << " * @deprecated ";
+ writeDocLines(out, doc->deprecated(), false);
+ }
+ else if(doc->isDeprecated())
+ {
+ out << nl << " *";
+ out << nl << " * @deprecated";
+ }
+
+ out << nl << " */";
+}
+
+enum OpDocParamType { OpDocInParams, OpDocOutParams, OpDocAllParams };
+
+void
+writeOpDocParams(Output& out, const OperationPtr& op, const CommentPtr& doc, OpDocParamType type,
+ const StringList& preParams = StringList(), const StringList& postParams = StringList())
+{
+ ParamDeclList params;
+ switch (type)
+ {
+ case OpDocInParams:
+ params = op->inParameters();
+ break;
+ case OpDocOutParams:
+ params = op->outParameters();
+ break;
+ case OpDocAllParams:
+ params = op->parameters();
+ break;
+ }
+
+ if (!preParams.empty())
+ {
+ writeDocLines(out, preParams, true);
+ }
+
+ map<string, StringList> paramDoc = doc->parameters();
+ for (ParamDeclList::iterator p = params.begin(); p != params.end(); ++p)
+ {
+ map<string, StringList>::iterator q = paramDoc.find((*p)->name());
+ if(q != paramDoc.end())
+ {
+ out << nl << " * @param " << Slice::JsGenerator::fixId(q->first) << " ";
+ writeDocLines(out, q->second, false);
+ }
+ }
+
+ if(!postParams.empty())
+ {
+ writeDocLines(out, postParams, true);
+ }
+}
+
+void
+writeOpDocExceptions(Output& out, const OperationPtr& op, const CommentPtr& doc)
+{
+ map<string, StringList> exDoc = doc->exceptions();
+ for (map<string, StringList>::iterator p = exDoc.begin(); p != exDoc.end(); ++p)
+ {
+ //
+ // Try to locate the exception's definition using the name given in the comment.
+ //
+ string name = p->first;
+ ExceptionPtr ex = op->container()->lookupException(name, false);
+ if (ex)
+ {
+ name = ex->scoped().substr(2);
+ }
+ out << nl << " * @throws " << name << " ";
+ writeDocLines(out, p->second, false);
+ }
}
-Slice::JsVisitor::JsVisitor(Output& out) : _out(out)
+void
+writeOpDocSummary(Output& out, const OperationPtr& op, const CommentPtr& doc, OpDocParamType type, bool showExceptions,
+ const StringList& preParams = StringList(), const StringList& postParams = StringList(),
+ const StringList& returns = StringList())
+{
+ out << nl << "/**";
+
+ if (!doc->overview().empty())
+ {
+ writeDocLines(out, doc->overview(), true);
+ }
+
+ writeOpDocParams(out, op, doc, type, preParams, postParams);
+
+ if(!returns.empty())
+ {
+ out << nl << " * @return ";
+ writeDocLines(out, returns, false);
+ }
+
+ if(showExceptions)
+ {
+ writeOpDocExceptions(out, op, doc);
+ }
+
+ if(!doc->misc().empty())
+ {
+ writeDocLines(out, doc->misc(), true);
+ }
+
+ if(!doc->seeAlso().empty())
+ {
+ writeSeeAlso(out, doc->seeAlso());
+ }
+
+ if(!doc->deprecated().empty())
+ {
+ out << nl << " *";
+ out << nl << " * @deprecated ";
+ writeDocLines(out, doc->deprecated(), false);
+ }
+ else if(doc->isDeprecated())
+ {
+ out << nl << " *";
+ out << nl << " * @deprecated";
+ }
+
+ out << nl << " */";
+}
+
+}
+
+Slice::JsVisitor::JsVisitor(Output& out, const vector<pair<string, string>>& imports) :
+ _out(out),
+ _imports(imports)
{
}
@@ -96,6 +368,12 @@ Slice::JsVisitor::~JsVisitor()
{
}
+vector<pair<string, string>>
+Slice::JsVisitor::imports() const
+{
+ return _imports;
+}
+
void
Slice::JsVisitor::writeMarshalDataMembers(const DataMemberList& dataMembers, const DataMemberList& optionalMembers)
{
@@ -131,7 +409,7 @@ Slice::JsVisitor::writeUnmarshalDataMembers(const DataMemberList& dataMembers, c
}
void
-Slice::JsVisitor::writeInitDataMembers(const DataMemberList& dataMembers, const string& scope)
+Slice::JsVisitor::writeInitDataMembers(const DataMemberList& dataMembers)
{
for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q)
{
@@ -188,7 +466,7 @@ Slice::JsVisitor::getValue(const string& scope, const TypePtr& type)
EnumPtr en = EnumPtr::dynamicCast(type);
if(en)
{
- return getReference(scope, en->scoped()) + '.' + fixId((*en->enumerators().begin())->name());
+ return fixId(en->scoped()) + '.' + fixId((*en->enumerators().begin())->name());
}
StructPtr st = StructPtr::dynamicCast(type);
@@ -208,7 +486,7 @@ Slice::JsVisitor::writeConstantValue(const string& scope, const TypePtr& type, c
ConstPtr constant = ConstPtr::dynamicCast(valueType);
if(constant)
{
- os << getReference(scope, constant->scoped());
+ os << fixId(constant->scoped());
}
else
{
@@ -243,7 +521,7 @@ Slice::JsVisitor::writeConstantValue(const string& scope, const TypePtr& type, c
{
EnumeratorPtr lte = EnumeratorPtr::dynamicCast(valueType);
assert(lte);
- os << getReference(scope, ep->scoped()) << '.' << fixId(lte->name());
+ os << fixId(ep->scoped()) << '.' << fixId(lte->name());
}
else
{
@@ -331,18 +609,20 @@ Slice::JsVisitor::writeDocComment(const ContainedPtr& p, const string& deprecate
_out << nl << " **/";
}
-Slice::Gen::Gen(const string& base, const vector<string>& includePaths, const string& dir) :
+Slice::Gen::Gen(const string& base, const vector<string>& includePaths, const string& dir, bool typeScript) :
_includePaths(includePaths),
- _useStdout(false)
+ _useStdout(false),
+ _typeScript(typeScript)
{
_fileBase = base;
+
string::size_type pos = base.find_last_of("/\\");
if(pos != string::npos)
{
_fileBase = base.substr(pos + 1);
}
- string file = _fileBase + ".js";
+ string file = _fileBase + (typeScript ? ".d.ts" : ".js");
if(!dir.empty())
{
@@ -358,14 +638,16 @@ Slice::Gen::Gen(const string& base, const vector<string>& includePaths, const st
}
FileTracker::instance()->addFile(file);
- printHeader();
+ printHeader(_out);
printGeneratedHeader(_out, _fileBase + ".ice");
}
-Slice::Gen::Gen(const string& base, const vector<string>& includePaths, const string& dir, ostream& out) :
+Slice::Gen::Gen(const string& base, const vector<string>& includePaths, const string& dir, bool typeScript,
+ ostream& out) :
_out(out),
_includePaths(includePaths),
- _useStdout(true)
+ _useStdout(true),
+ _typeScript(typeScript)
{
_fileBase = base;
string::size_type pos = base.find_last_of("/\\");
@@ -374,7 +656,7 @@ Slice::Gen::Gen(const string& base, const vector<string>& includePaths, const st
_fileBase = base.substr(pos + 1);
}
- printHeader();
+ printHeader(_out);
printGeneratedHeader(_out, _fileBase + ".ice");
}
@@ -390,70 +672,106 @@ void
Slice::Gen::generate(const UnitPtr& p)
{
//
- // Check for global "js:ice-build" and "js:es6-module"
- // metadata. If this is set then we are building Ice.
+ // Check for "js:module:ice" metadata. If this
+ // is set then we are building Ice.
+ //
+ ModuleList modules = p->modules();
+ bool icejs = false;
+ for(ModuleList::const_iterator i = modules.begin(); i != modules.end(); i++)
+ {
+ if(p->topLevelFile() == (*i)->definitionContext()->filename() &&
+ getModuleMetadata(ContainedPtr::dynamicCast(*i)) == "ice")
+ {
+ icejs = true;
+ break;
+ }
+ }
+
+ //
+ // Check for global "js:es6-module" metadata.
//
DefinitionContextPtr dc = p->findDefinitionContext(p->topLevelFile());
assert(dc);
StringList globalMetaData = dc->getMetaData();
- bool icejs = find(globalMetaData.begin(), globalMetaData.end(), "js:ice-build") != globalMetaData.end();
bool es6module = find(globalMetaData.begin(), globalMetaData.end(), "js:es6-module") != globalMetaData.end();
- _out << nl << "/* eslint-disable */";
- _out << nl << "/* jshint ignore: start */";
- _out << nl;
+ if(_typeScript)
+ {
+ TypeScriptRequireVisitor requireVisitor(_out);
+ p->visit(&requireVisitor, false);
+ requireVisitor.writeRequires(p);
+
+ //
+ // If at some point TypeScript adds an operator to refer to a type in the global scope
+ // we can get rid of the TypeScriptAliasVisitor and use this. For now we need to generate
+ // a type alias when there is an abiguity.
+ // see: https://github.com/Microsoft/TypeScript/issues/983
+ //
+ TypeScriptAliasVisitor aliasVisitor(_out);
+ p->visit(&aliasVisitor, false);
+ aliasVisitor.writeAlias(p);
- if(!es6module)
+ TypeScriptVisitor typeScriptVisitor(_out, requireVisitor.imports());
+ p->visit(&typeScriptVisitor, false);
+ }
+ else
{
- if(icejs)
- {
- _out.zeroIndent();
- _out << nl << "/* slice2js browser-bundle-skip */";
- _out.restoreIndent();
- }
- _out << nl << "(function(module, require, exports)";
- _out << sb;
- if(icejs)
+ _out << nl << "/* eslint-disable */";
+ _out << nl << "/* jshint ignore: start */";
+ _out << nl;
+
+ if(!es6module)
{
- _out.zeroIndent();
- _out << nl << "/* slice2js browser-bundle-skip-end */";
- _out.restoreIndent();
+ if(icejs)
+ {
+ _out.zeroIndent();
+ _out << nl << "/* slice2js browser-bundle-skip */";
+ _out.restoreIndent();
+ }
+ _out << nl << "(function(module, require, exports)";
+ _out << sb;
+ if(icejs)
+ {
+ _out.zeroIndent();
+ _out << nl << "/* slice2js browser-bundle-skip-end */";
+ _out.restoreIndent();
+ }
}
- }
- RequireVisitor requireVisitor(_out, _includePaths, icejs, es6module);
- p->visit(&requireVisitor, false);
- vector<string> seenModules = requireVisitor.writeRequires(p);
+ RequireVisitor requireVisitor(_out, _includePaths, icejs, es6module);
+ p->visit(&requireVisitor, false);
+ vector<string> seenModules = requireVisitor.writeRequires(p);
- TypesVisitor typesVisitor(_out, seenModules, icejs);
- p->visit(&typesVisitor, false);
+ TypesVisitor typesVisitor(_out, seenModules, icejs);
+ p->visit(&typesVisitor, false);
- //
- // Export the top-level modules.
- //
- ExportVisitor exportVisitor(_out, icejs, es6module);
- p->visit(&exportVisitor, false);
+ //
+ // Export the top-level modules.
+ //
+ ExportVisitor exportVisitor(_out, icejs, es6module);
+ p->visit(&exportVisitor, false);
- if(!es6module)
- {
- if(icejs)
+ if(!es6module)
{
- _out.zeroIndent();
- _out << nl << "/* slice2js browser-bundle-skip */";
- _out.restoreIndent();
- }
+ if(icejs)
+ {
+ _out.zeroIndent();
+ _out << nl << "/* slice2js browser-bundle-skip */";
+ _out.restoreIndent();
+ }
- _out << eb;
- _out << nl << "(typeof(global) !== \"undefined\" && typeof(global.process) !== \"undefined\" ? module : undefined,"
- << nl << " typeof(global) !== \"undefined\" && typeof(global.process) !== \"undefined\" ? require :"
- << nl << " (typeof WorkerGlobalScope !== \"undefined\" && self instanceof WorkerGlobalScope) ? self.Ice._require : window.Ice._require,"
- << nl << " typeof(global) !== \"undefined\" && typeof(global.process) !== \"undefined\" ? exports :"
- << nl << " (typeof WorkerGlobalScope !== \"undefined\" && self instanceof WorkerGlobalScope) ? self : window));";
+ _out << eb;
+ _out << nl << "(typeof(global) !== \"undefined\" && typeof(global.process) !== \"undefined\" ? module : undefined,"
+ << nl << " typeof(global) !== \"undefined\" && typeof(global.process) !== \"undefined\" ? require :"
+ << nl << " (typeof WorkerGlobalScope !== \"undefined\" && self instanceof WorkerGlobalScope) ? self.Ice._require : window.Ice._require,"
+ << nl << " typeof(global) !== \"undefined\" && typeof(global.process) !== \"undefined\" ? exports :"
+ << nl << " (typeof WorkerGlobalScope !== \"undefined\" && self instanceof WorkerGlobalScope) ? self : window));";
- if(icejs)
- {
- _out.zeroIndent();
- _out << nl << "/* slice2js browser-bundle-skip-end */";
- _out.restoreIndent();
+ if(icejs)
+ {
+ _out.zeroIndent();
+ _out << nl << "/* slice2js browser-bundle-skip-end */";
+ _out.restoreIndent();
+ }
}
}
}
@@ -464,26 +782,6 @@ Slice::Gen::closeOutput()
_out.close();
}
-void
-Slice::Gen::printHeader()
-{
- static const char* header =
-"// **********************************************************************\n"
-"//\n"
-"// Copyright (c) 2003-2018 ZeroC, Inc. All rights reserved.\n"
-"//\n"
-"// This copy of Ice is licensed to you under the terms described in the\n"
-"// ICE_LICENSE file included in this distribution.\n"
-"//\n"
-"// **********************************************************************\n"
- ;
-
- _out << header;
- _out << "//\n";
- _out << "// Ice version " << ICE_STRING_VERSION << "\n";
- _out << "//\n";
-}
-
Slice::Gen::RequireVisitor::RequireVisitor(IceUtilInternal::Output& out, vector<string> includePaths,
bool icejs, bool es6modules) :
JsVisitor(out),
@@ -549,9 +847,17 @@ void
Slice::Gen::RequireVisitor::visitSequence(const SequencePtr& seq)
{
BuiltinPtr builtin = BuiltinPtr::dynamicCast(seq->type());
- if(builtin && builtin->kind() == Builtin::KindObject)
+ if(builtin)
{
- _seenObjectSeq = true;
+ switch(builtin->kind())
+ {
+ case Builtin::KindObject:
+ _seenObjectSeq = true;
+ case Builtin::KindObjectProxy:
+ _seenObjectProxySeq = true;
+ default:
+ break;
+ }
}
}
@@ -559,9 +865,17 @@ void
Slice::Gen::RequireVisitor::visitDictionary(const DictionaryPtr& dict)
{
BuiltinPtr builtin = BuiltinPtr::dynamicCast(dict->valueType());
- if(builtin && builtin->kind() == Builtin::KindObject)
+ if(builtin)
{
- _seenObjectDict = true;
+ switch(builtin->kind())
+ {
+ case Builtin::KindObject:
+ _seenObjectDict = true;
+ case Builtin::KindObjectProxy:
+ _seenObjectProxyDict = true;
+ default:
+ break;
+ }
}
}
@@ -579,66 +893,12 @@ bool iceBuiltinModule(const string& name)
return name == "Glacier2" || name == "Ice" || name == "IceGrid" || name == "IceMX" || name == "IceStorm";
}
-string
-relativePath(string p1, string p2)
-{
- vector<string> tokens1;
- vector<string> tokens2;
-
- splitString(p1, "/\\", tokens1);
- splitString(p2, "/\\", tokens2);
-
- string f1 = tokens1.back();
- string f2 = tokens2.back();
-
- tokens1.pop_back();
- tokens2.pop_back();
-
- vector<string>::const_iterator i1 = tokens1.begin();
- vector<string>::const_iterator i2 = tokens2.begin();
-
- while(i1 != tokens1.end() && i2 != tokens2.end() && *i1 == *i2)
- {
- i1++;
- i2++;
- }
-
- //
- // Different volumes, relative path not possible.
- //
- if(i1 == tokens1.begin() && i2 == tokens2.begin())
- {
- return p1;
- }
-
- string newPath;
- if(i2 == tokens2.end())
- {
- newPath += "./";
- for(; i1 != tokens1.end(); ++i1)
- {
- newPath += *i1 + "/";
- }
- }
- else
- {
- for(;i2 != tokens2.end();++i2)
- {
- newPath += "../";
- }
- }
- newPath += f1;
-
- return newPath;
-}
-
}
vector<string>
Slice::Gen::RequireVisitor::writeRequires(const UnitPtr& p)
{
vector<string> seenModules;
-
map<string, list<string> > requires;
if(_icejs)
{
@@ -925,7 +1185,7 @@ Slice::Gen::TypesVisitor::visitClassDefStart(const ClassDefPtr& p)
{
base = bases.front();
bases.erase(bases.begin());
- baseRef = getReference(scope, base->scoped());
+ baseRef = fixId(base->scoped());
}
else
{
@@ -1040,7 +1300,7 @@ Slice::Gen::TypesVisitor::visitClassDefStart(const ClassDefPtr& p)
{
_out << nl << "super" << spar << baseParamNames << epar << ';';
}
- writeInitDataMembers(dataMembers, scope);
+ writeInitDataMembers(dataMembers);
_out << eb;
if(!p->isLocal())
@@ -1091,12 +1351,12 @@ Slice::Gen::TypesVisitor::visitClassDefStart(const ClassDefPtr& p)
//
// Define servant an proxy types for non local classes
//
- if(!p->isLocal())
+ if(!p->isLocal() && (p->isInterface() || !p->allOperations().empty()))
{
_out << sp;
writeDocComment(p, getDeprecateReason(p, 0, "type"));
_out << nl << localScope << "." << (p->isInterface() ? p->name() : p->name() + "Disp") << " = class extends ";
- if(hasBaseClass)
+ if(hasBaseClass && !base->allOperations().empty())
{
_out << getLocalScope(base->scope()) << "." << base->name() << "Disp";
}
@@ -1140,7 +1400,7 @@ Slice::Gen::TypesVisitor::visitClassDefStart(const ClassDefPtr& p)
// Generate a proxy class for interfaces or classes with operations.
//
string proxyType = "undefined";
- if(p->isInterface() || p->allOperations().size() > 0)
+ if(p->isInterface() || !p->allOperations().empty())
{
proxyType = localScope + '.' + prxName;
string baseProxy = "Ice.ObjectPrx";
@@ -1442,7 +1702,7 @@ Slice::Gen::TypesVisitor::visitExceptionStart(const ExceptionPtr& p)
string baseRef;
if(base)
{
- baseRef = getReference(scope, base->scoped());
+ baseRef = fixId(base->scoped());
}
else
{
@@ -1514,7 +1774,7 @@ Slice::Gen::TypesVisitor::visitExceptionStart(const ExceptionPtr& p)
_out << "_cause = \"\"" << epar;
_out << sb;
_out << nl << "super" << spar << baseParamNames << "_cause" << epar << ';';
- writeInitDataMembers(dataMembers, scope);
+ writeInitDataMembers(dataMembers);
_out << eb;
_out << sp;
@@ -1529,8 +1789,6 @@ Slice::Gen::TypesVisitor::visitExceptionStart(const ExceptionPtr& p)
_out << nl << "return \"" << p->scoped() << "\";";
_out << eb;
- // TODO: equals?
-
if(!p->isLocal())
{
_out << sp;
@@ -1630,7 +1888,7 @@ Slice::Gen::TypesVisitor::visitStructStart(const StructPtr& p)
_out << epar;
_out << sb;
- writeInitDataMembers(dataMembers, scope);
+ writeInitDataMembers(dataMembers);
_out << eb;
if(!p->isLocal())
@@ -1900,3 +2158,1038 @@ Slice::Gen::ExportVisitor::visitModuleStart(const ModulePtr& p)
}
return false;
}
+
+Slice::Gen::TypeScriptRequireVisitor::TypeScriptRequireVisitor(IceUtilInternal::Output& out) :
+ JsVisitor(out),
+ _nextImport(0)
+{
+}
+
+string
+Slice::Gen::TypeScriptRequireVisitor::nextImportPrefix()
+{
+ ostringstream ns;
+ ns << "iceNS" << _nextImport++;
+ return ns.str();
+}
+
+void
+Slice::Gen::TypeScriptRequireVisitor::addImport(const TypePtr& definition, const ContainedPtr& toplevel)
+{
+ if(!BuiltinPtr::dynamicCast(definition))
+ {
+ const string m1 = getModuleMetadata(definition);
+ const string m2 = getModuleMetadata(toplevel);
+
+ const string p1 = definition->definitionContext()->filename();
+ const string p2 = toplevel->definitionContext()->filename();
+
+ addImport(m1, m2, p1, p2);
+ }
+}
+
+void
+Slice::Gen::TypeScriptRequireVisitor::addImport(const ContainedPtr& definition, const ContainedPtr& toplevel)
+{
+ const string m1 = getModuleMetadata(definition);
+ const string m2 = getModuleMetadata(toplevel);
+
+ const string p1 = definition->definitionContext()->filename();
+ const string p2 = toplevel->definitionContext()->filename();
+
+ addImport(m1, m2, p1, p2);
+}
+
+void
+Slice::Gen::TypeScriptRequireVisitor::addImport(const string& m1, const string& m2,
+ const string& p1, const string& p2)
+{
+ //
+ // Generate an import for a definition that is outside a JS module and comes from
+ // a different definition context or for a definition defined in a module different
+ // than the current module.
+ //
+ if(m1.empty())
+ {
+ if(p1 != p2)
+ {
+ string relpath = relativePath(p1, p2);
+
+ string::size_type pos = relpath.rfind('.');
+ if(pos != string::npos)
+ {
+ relpath.erase(pos);
+ }
+
+ for(vector<pair<string, string>>::const_iterator i = _imports.begin(); i != _imports.end(); ++i)
+ {
+ if(i->first == relpath)
+ {
+ return;
+ }
+ }
+ _imports.push_back(make_pair(relpath, nextImportPrefix()));
+ }
+ }
+ else if(m1 != m2)
+ {
+ for(vector<pair<string, string>>::const_iterator i = _imports.begin(); i != _imports.end(); ++i)
+ {
+ if(i->first == m1)
+ {
+ return;
+ }
+ }
+ _imports.push_back(make_pair(m1, nextImportPrefix()));
+ }
+}
+
+bool
+Slice::Gen::TypeScriptRequireVisitor::visitModuleStart(const ModulePtr& p)
+{
+ //
+ // Import ice module if not building Ice
+ //
+ if(UnitPtr::dynamicCast(p->container()))
+ {
+ const string prefix = "js:module:";
+ string m;
+ findMetaData(prefix, p->getMetaData(), m);
+ if(_imports.empty() && m != "ice")
+ {
+ _imports.push_back(make_pair("ice", nextImportPrefix()));
+ }
+ }
+ return true;
+}
+
+bool
+Slice::Gen::TypeScriptRequireVisitor::visitClassDefStart(const ClassDefPtr& p)
+{
+ //
+ // Add imports required for base classes
+ //
+ ClassList bases = p->bases();
+ for(ClassList::const_iterator i = bases.begin(); i != bases.end(); ++i)
+ {
+ addImport(ContainedPtr::dynamicCast(*i), p);
+ }
+
+ //
+ // Add imports required for data members
+ //
+ const DataMemberList allDataMembers = p->allDataMembers();
+ for(DataMemberList::const_iterator i = allDataMembers.begin(); i != allDataMembers.end(); ++i)
+ {
+ addImport((*i)->type(), p);
+ }
+
+ //
+ // Add imports required for operation parameters and return type
+ //
+ const OperationList operationList = p->allOperations();
+ for(OperationList::const_iterator i = operationList.begin(); i != operationList.end(); ++i)
+ {
+ const TypePtr ret = (*i)->returnType();
+ if(ret && ret->definitionContext())
+ {
+ addImport(ret, p);
+ }
+
+ const ParamDeclList paramList = (*i)->parameters();
+ for(ParamDeclList::const_iterator j = paramList.begin(); j != paramList.end(); ++j)
+ {
+ addImport((*j)->type(), p);
+ }
+ }
+ return false;
+}
+
+bool
+Slice::Gen::TypeScriptRequireVisitor::visitStructStart(const StructPtr& p)
+{
+ //
+ // Add imports required for data members
+ //
+ const DataMemberList dataMembers = p->dataMembers();
+ for(DataMemberList::const_iterator i = dataMembers.begin(); i != dataMembers.end(); ++i)
+ {
+ addImport((*i)->type(), p);
+ }
+ return false;
+}
+
+bool
+Slice::Gen::TypeScriptRequireVisitor::visitExceptionStart(const ExceptionPtr& p)
+{
+ //
+ // Add imports required for base exceptions
+ //
+ ExceptionPtr base = p->base();
+ if(base)
+ {
+ addImport(ContainedPtr::dynamicCast(base), p);
+ }
+
+ //
+ // Add imports required for data members
+ //
+ const DataMemberList allDataMembers = p->allDataMembers();
+ for(DataMemberList::const_iterator i = allDataMembers.begin(); i != allDataMembers.end(); ++i)
+ {
+ addImport((*i)->type(), p);
+ }
+ return false;
+}
+
+void
+Slice::Gen::TypeScriptRequireVisitor::visitSequence(const SequencePtr& seq)
+{
+ //
+ // Add import required for the sequence element type
+ //
+ addImport(seq->type(), seq);
+}
+
+void
+Slice::Gen::TypeScriptRequireVisitor::visitDictionary(const DictionaryPtr& dict)
+{
+ //
+ // Add imports required for the dictionary key and value types
+ //
+ addImport(dict->keyType(), dict);
+ addImport(dict->valueType(), dict);
+}
+
+void
+Slice::Gen::TypeScriptRequireVisitor::writeRequires(const UnitPtr& p)
+{
+ for(vector<pair<string, string>>::const_iterator i = _imports.begin(); i != _imports.end(); ++i)
+ {
+ _out << nl << "import * as " << i->second << " from \"" << i->first << "\"";
+ }
+}
+
+Slice::Gen::TypeScriptAliasVisitor::TypeScriptAliasVisitor(IceUtilInternal::Output& out) :
+ JsVisitor(out)
+{
+}
+
+void
+Slice::Gen::TypeScriptAliasVisitor::addAlias(const ExceptionPtr& type, const ContainedPtr& toplevel)
+{
+ string m1 = getModuleMetadata(ContainedPtr::dynamicCast(type));
+ string m2 = getModuleMetadata(toplevel);
+
+ //
+ // Do not add alias for a type defined in the current module
+ //
+ if(!m1.empty() && m1 == m2)
+ {
+ return;
+ }
+
+ const string prefix = importPrefix(ContainedPtr::dynamicCast(type), toplevel, imports());
+ const string typeS = prefix + getUnqualified(fixId(type->scoped()), toplevel->scope(), prefix);
+
+ addAlias(typeS, prefix, toplevel);
+}
+
+void
+Slice::Gen::TypeScriptAliasVisitor::addAlias(const TypePtr& type, const ContainedPtr& toplevel)
+{
+ string m1 = getModuleMetadata(type);
+ string m2 = getModuleMetadata(toplevel);
+
+ //
+ // Do not add alias for a type defined in the current module
+ //
+ if(!m1.empty() && m1 == m2)
+ {
+ return;
+ }
+
+ addAlias(typeToString(type, toplevel, imports(), true),
+ importPrefix(type, toplevel, imports()),
+ toplevel);
+}
+
+void
+Slice::Gen::TypeScriptAliasVisitor::addAlias(const string& type, const string& prefix,
+ const ContainedPtr& toplevel)
+{
+ const string scope = fixId(toplevel->scoped()) + ".";
+ //
+ // When using an import prefix we don't need an alias, prefixes use iceNSXX that is reserved
+ // name prefix
+ //
+ string::size_type i = type.find(".");
+ if(prefix.empty() && i != string::npos)
+ {
+ if(scope.find("." + type.substr(0, i + 1)) != string::npos)
+ {
+ for(vector<pair<string, string>>::const_iterator j = _aliases.begin(); j != _aliases.end(); ++j)
+ {
+ if(j->first == type)
+ {
+ return;
+ }
+ }
+ string alias = type;
+ replace(alias.begin(), alias.end(), '.', '_');
+ //
+ // We prefix alias with iceA this avoid conflict with iceNSX used for
+ // import prefixes
+ //
+ _aliases.push_back(make_pair(type, "iceA_" + alias));
+ }
+ }
+}
+
+bool
+Slice::Gen::TypeScriptAliasVisitor::visitModuleStart(const ModulePtr& p)
+{
+ return true;
+}
+
+bool
+Slice::Gen::TypeScriptAliasVisitor::visitClassDefStart(const ClassDefPtr& p)
+{
+ ModulePtr module = ModulePtr::dynamicCast(p->container());
+ //
+ // Add alias required for base classes
+ //
+ ClassList bases = p->bases();
+ for(ClassList::const_iterator i = bases.begin(); i != bases.end(); ++i)
+ {
+ addAlias(TypePtr::dynamicCast((*i)->declaration()), module);
+ }
+
+ //
+ // Add alias required for data members
+ //
+ const DataMemberList allDataMembers = p->allDataMembers();
+ for(DataMemberList::const_iterator i = allDataMembers.begin(); i != allDataMembers.end(); ++i)
+ {
+ addAlias((*i)->type(), module);
+ }
+
+ //
+ // Add alias required for operation parameters
+ //
+ const OperationList operationList = p->allOperations();
+ for(OperationList::const_iterator i = operationList.begin(); i != operationList.end(); ++i)
+ {
+ const TypePtr ret = (*i)->returnType();
+ if(ret && ret->definitionContext())
+ {
+ addAlias(ret, module);
+ }
+
+ const ParamDeclList paramList = (*i)->parameters();
+ for(ParamDeclList::const_iterator j = paramList.begin(); j != paramList.end(); ++j)
+ {
+ addAlias((*j)->type(), module);
+ }
+ }
+ return false;
+}
+
+bool
+Slice::Gen::TypeScriptAliasVisitor::visitStructStart(const StructPtr& p)
+{
+ ModulePtr module = ModulePtr::dynamicCast(p->container());
+ //
+ // Add alias required for data members
+ //
+ const DataMemberList dataMembers = p->dataMembers();
+ for(DataMemberList::const_iterator i = dataMembers.begin(); i != dataMembers.end(); ++i)
+ {
+ addAlias((*i)->type(), module);
+ }
+ return false;
+}
+
+bool
+Slice::Gen::TypeScriptAliasVisitor::visitExceptionStart(const ExceptionPtr& p)
+{
+ ModulePtr module = ModulePtr::dynamicCast(p->container());
+ //
+ // Add alias required for base exception
+ //
+ ExceptionPtr base = p->base();
+ if(base)
+ {
+ addAlias(base, module);
+ }
+
+ //
+ // Add alias required for data members
+ //
+ const DataMemberList allDataMembers = p->allDataMembers();
+ for(DataMemberList::const_iterator i = allDataMembers.begin(); i != allDataMembers.end(); ++i)
+ {
+ addAlias((*i)->type(), module);
+ }
+ return false;
+}
+
+void
+Slice::Gen::TypeScriptAliasVisitor::visitSequence(const SequencePtr& seq)
+{
+ addAlias(seq->type(), ModulePtr::dynamicCast(seq->container()));
+}
+
+void
+Slice::Gen::TypeScriptAliasVisitor::visitDictionary(const DictionaryPtr& dict)
+{
+ ModulePtr module = ModulePtr::dynamicCast(dict->container());
+ addAlias(dict->keyType(), module);
+ addAlias(dict->valueType(), module);
+}
+
+void
+Slice::Gen::TypeScriptAliasVisitor::writeAlias(const UnitPtr& p)
+{
+ if(!_aliases.empty())
+ {
+ _out << sp;
+ for(vector<pair<string, string>>::const_iterator i = _aliases.begin(); i != _aliases.end(); ++i)
+ {
+ _out << nl << "type " << i->second << " = " << i->first << ";";
+ }
+ }
+}
+
+Slice::Gen::TypeScriptVisitor::TypeScriptVisitor(::IceUtilInternal::Output& out,
+ const vector<pair<string, string>>& imports) :
+ JsVisitor(out, imports)
+{
+}
+
+bool
+Slice::Gen::TypeScriptVisitor::visitModuleStart(const ModulePtr& p)
+{
+ UnitPtr unit = UnitPtr::dynamicCast(p->container());
+ if(unit)
+ {
+ string module = getModuleMetadata(ContainedPtr::dynamicCast(p));
+
+ _out << sp;
+ if(module.empty())
+ {
+ _out << nl << "export namespace " << fixId(p->name()) << sb;
+ }
+ else
+ {
+ _out << nl << "declare module \"" << fixId(module) << "\"" << sb;
+ _out << nl << "namespace " << fixId(p->name()) << sb;
+ }
+ }
+ else
+ {
+ _out << nl << "namespace " << fixId(p->name()) << sb;
+ }
+ return true;
+}
+
+void
+Slice::Gen::TypeScriptVisitor::visitModuleEnd(const ModulePtr& p)
+{
+ _out << eb; // namespace end
+
+ if(UnitPtr::dynamicCast(p->container()))
+ {
+ string module = getModuleMetadata(ContainedPtr::dynamicCast(p));
+ if(!module.empty())
+ {
+ _out << eb; // module end
+ }
+ }
+}
+
+bool
+Slice::Gen::TypeScriptVisitor::visitClassDefStart(const ClassDefPtr& p)
+{
+ const string toplevelModule = getModuleMetadata(ContainedPtr::dynamicCast(p));
+ const string icePrefix = importPrefix("Ice.", p);
+ if(p->isDelegate())
+ {
+ // A delegate only has one operation
+ OperationPtr op = p->allOperations().front();
+ CommentPtr comment = op->parseComment(false);
+ if(comment)
+ {
+ writeOpDocSummary(_out, op, comment, OpDocAllParams, true, StringList(), StringList(), comment->returns());
+ }
+ _out << nl << "type " << fixId(p->name()) << " = " << spar;
+ ParamDeclList paramList = op->parameters();
+ for(ParamDeclList::iterator q = paramList.begin(); q != paramList.end(); ++q)
+ {
+ ostringstream os;
+ os << fixId((*q)->name()) << ":";
+ if((*q)->isOutParam())
+ {
+ os << icePrefix << getUnqualified("Ice.Holder", p->scope(), icePrefix) << "<";
+ }
+ os << typeToString((*q)->type(), p, imports(), true, false, true);
+ if((*q)->isOutParam())
+ {
+ os << ">";
+ }
+ _out << os.str();
+ }
+ _out << epar << " => ";
+ TypePtr ret = op->returnType();
+ if(ret)
+ {
+ _out << typeToString(ret, p, imports(), true, false, true) << ";";
+ }
+ else
+ {
+ _out << "void;";
+ }
+ }
+ else if(p->isLocal())
+ {
+ const ClassList bases = p->bases();
+ const DataMemberList dataMembers = p->dataMembers();
+ const DataMemberList allDataMembers = p->allDataMembers();
+
+ _out << sp;
+ writeDocSummary(_out, p);
+ _out << nl;
+ _out << (p->isInterface() ? "interface" : "class") << " " << fixId(p->name());
+ if(!bases.empty() && !bases.front()->isInterface())
+ {
+ const string prefix = importPrefix(ContainedPtr::dynamicCast(bases.front()), p, imports());
+ _out << " extends " << prefix << getUnqualified(fixId(bases.front()->scoped()), p->scope(), prefix);
+ }
+ _out << sb;
+ if(!p->isInterface())
+ {
+ _out << nl << "/**";
+ _out << nl << " * One-shot constructor to initialize all data members.";
+ for(DataMemberList::const_iterator q = allDataMembers.begin(); q != allDataMembers.end(); ++q)
+ {
+ CommentPtr comment = (*q)->parseComment(false);
+ if(comment)
+ {
+ _out << nl << " * @param " << fixId((*q)->name()) << " " << getDocSentence(comment->overview());
+ }
+ }
+ _out << nl << " */";
+ _out << nl << "constructor" << spar;
+ for(DataMemberList::const_iterator q = allDataMembers.begin(); q != allDataMembers.end(); ++q)
+ {
+ _out << (fixId((*q)->name()) + "?:" + typeToString((*q)->type(), p, imports(), true, false, true));
+ }
+ _out << epar << ";";
+
+ for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q)
+ {
+ writeDocSummary(_out, *q);
+ _out << nl << fixId((*q)->name()) << ":" << typeToString((*q)->type(), p, imports(), true, false, true)
+ << ";";
+ }
+ }
+
+ OperationList allOperations = p->allOperations();
+ for(OperationList::const_iterator q = allOperations.begin(); q != allOperations.end(); ++q)
+ {
+ OperationPtr op = *q;
+ ParamDeclList params = op->parameters();
+ ParamDeclList inParams, outParams;
+ for(ParamDeclList::const_iterator r = params.begin(); r != params.end(); ++r)
+ {
+ if((*r)->isOutParam())
+ {
+ outParams.push_back(*r);
+ }
+ else
+ {
+ inParams.push_back(*r);
+ }
+ }
+
+ TypePtr ret = op->returnType();
+ bool async = op->hasMetaData("js:async") || op->hasMetaData("async-oneway");
+ CommentPtr comment = op->parseComment(false);
+ if(comment)
+ {
+ StringList returns;
+ if(async)
+ {
+ returns.push_back("@returns The asynchronous result object for the invocation.");
+ }
+ else if(ret)
+ {
+ returns = comment->returns();
+ }
+ writeOpDocSummary(_out, op, comment, OpDocAllParams, true, StringList(), StringList(), returns);
+ }
+
+ _out << nl << fixId((*q)->name()) << spar;
+ for(ParamDeclList::const_iterator r = inParams.begin(); r != inParams.end(); r++)
+ {
+ _out << (fixId((*r)->name()) + ":" + typeToString((*r)->type(), p, imports(), true, false, true));
+ }
+
+ for(ParamDeclList::const_iterator r = outParams.begin(); r != outParams.end(); r++)
+ {
+ const string prefix = importPrefix("Ice.Holder", p);
+ _out << (fixId((*r)->name()) + ":" + prefix +
+ getUnqualified("Ice.Holder", p->scope(), prefix) + "<" +
+ typeToString((*r)->type(), p, imports(), true, false, true) + ">");
+ }
+
+ _out << epar;
+
+ _out << ":";
+ if(async)
+ {
+ _out << icePrefix << getUnqualified("Ice.AsyncResultBase", p->scope(), icePrefix) << "<";
+ }
+
+ if(ret)
+ {
+ _out << typeToString(ret, p, imports(), true, false, true);
+ }
+ else
+ {
+ _out << "void";
+ }
+
+ if (async)
+ {
+ _out << ">";
+ }
+ _out << ";";
+ }
+
+ if(p->hasMetaData("js:comparable"))
+ {
+ _out << nl << "equals(rhs:any):boolean";
+ }
+ _out << eb;
+ }
+ else
+ {
+ //
+ // Define servant an proxy types for non local classes
+ //
+ _out << sp;
+ _out << nl << "abstract class " << fixId(p->name() + "Prx")
+ << " extends " << icePrefix << getUnqualified("Ice.ObjectPrx", p->scope(), icePrefix);
+ _out << sb;
+ const OperationList ops = p->allOperations();
+ for(OperationList::const_iterator q = ops.begin(); q != ops.end(); ++q)
+ {
+ const OperationPtr op = *q;
+ const ParamDeclList paramList = op->parameters();
+ const TypePtr ret = op->returnType();
+ ParamDeclList inParams, outParams;
+ for(ParamDeclList::const_iterator r = paramList.begin(); r != paramList.end(); ++r)
+ {
+ if((*r)->isOutParam())
+ {
+ outParams.push_back(*r);
+ }
+ else
+ {
+ inParams.push_back(*r);
+ }
+ }
+
+ const string contextParam = escapeParam(paramList, "context");
+ CommentPtr comment = op->parseComment(false);
+ const string contextDoc = "@param " + contextParam + " The Context map to send with the invocation.";
+ const string asyncDoc = "The asynchronous result object for the invocation.";
+ if(comment)
+ {
+ StringList postParams, returns;
+ postParams.push_back(contextDoc);
+ returns.push_back(asyncDoc);
+ writeOpDocSummary(_out, op, comment, OpDocInParams, false, StringList(), postParams, returns);
+ }
+ _out << nl << fixId((*q)->name()) << spar;
+ for(ParamDeclList::const_iterator r = inParams.begin(); r != inParams.end(); ++r)
+ {
+ _out << (fixId((*r)->name()) +
+ ((*r)->optional() ? "?" : "") +
+ ":" +
+ typeToString((*r)->type(), p, imports(), true, false, true));
+ }
+ _out << "context?:Map<string, string>";
+ _out << epar;
+
+ _out << ":" << icePrefix << getUnqualified("Ice.AsyncResult", p->scope(), icePrefix);
+ if(!ret && outParams.empty())
+ {
+ _out << "<void>";
+ }
+ else if((ret && outParams.empty()) || (!ret && outParams.size() == 1))
+ {
+ TypePtr t = ret ? ret : outParams.front()->type();
+ _out << "<" << typeToString(t, p, imports(), true, false, true) << ">";
+ }
+ else
+ {
+ _out << "<[";
+ if(ret)
+ {
+ _out << typeToString(ret, p, imports(), true, false, true) << ", ";
+ }
+
+ for(ParamDeclList::const_iterator i = outParams.begin(); i != outParams.end();)
+ {
+ _out << typeToString((*i)->type(), p, imports(), true, false, true);
+ if(++i != outParams.end())
+ {
+ _out << ", ";
+ }
+ }
+
+ _out << "]>";
+ }
+
+ _out << ";";
+ }
+
+ const string icePrefix = importPrefix("Ice.ObjectPrx", p);
+ _out << sp;
+ _out << nl << "/**";
+ _out << nl << " * Downcasts a proxy without confirming the target object's type via a remote invocation.";
+ _out << nl << " * @param prx The target proxy.";
+ _out << nl << " * @return A proxy with the requested type.";
+ _out << nl << " */";
+ _out << nl << "static uncheckedCast(prx:" << icePrefix
+ << getUnqualified("Ice.ObjectPrx", p->scope(), icePrefix) << ", "
+ << "facet?:string):"
+ << fixId(p->name() + "Prx") << ";";
+ _out << nl << "/**";
+ _out << nl << " * Downcasts a proxy after confirming the target object's type via a remote invocation.";
+ _out << nl << " * @param prx The target proxy.";
+ _out << nl << " * @param facet A facet name.";
+ _out << nl << " * @param context The context map for the invocation.";
+ _out << nl << " * @return A proxy with the requested type and facet, or nil if the target proxy is nil or the target";
+ _out << nl << " * object does not support the requested type.";
+ _out << nl << " */";
+ _out << nl << "static checkedCast(prx:" << icePrefix
+ << getUnqualified("Ice.ObjectPrx", p->scope(), icePrefix) << ", "
+ << "facet?:string, contex?:Map<string, string>):" << icePrefix
+ << getUnqualified("Ice.AsyncResult", p->scope(), icePrefix) << "<" << fixId(p->name() + "Prx") << ">;";
+ _out << eb;
+
+ if(p->isInterface() || !ops.empty())
+ {
+ _out << sp;
+ _out << nl << "abstract class " << fixId(p->name() + (p->isInterface() ? "" : "Disp"))
+ << " extends " << icePrefix << getUnqualified("Ice.Object", p->scope(), icePrefix);
+ _out << sb;
+ for(OperationList::const_iterator q = ops.begin(); q != ops.end(); ++q)
+ {
+ const OperationPtr op = *q;
+ const ParamDeclList paramList = op->parameters();
+ const TypePtr ret = op->returnType();
+ ParamDeclList inParams, outParams;
+ for(ParamDeclList::const_iterator r = paramList.begin(); r != paramList.end(); ++r)
+ {
+ if((*r)->isOutParam())
+ {
+ outParams.push_back(*r);
+ }
+ else
+ {
+ inParams.push_back(*r);
+ }
+ }
+
+ const string currentParam = escapeParam(inParams, "current");
+ CommentPtr comment = p->parseComment(false);
+ const string currentDoc = "@param " + currentParam + " The Current object for the invocation.";
+ const string resultDoc = "The result or a promise like object that will "
+ "be resolved with the result of the invocation.";
+ if(comment)
+ {
+ StringList postParams, returns;
+ postParams.push_back(currentDoc);
+ returns.push_back(resultDoc);
+ writeOpDocSummary(_out, op, comment, OpDocInParams, false, StringList(), postParams, returns);
+ }
+ _out << nl << "abstract " << fixId((*q)->name()) << spar;
+ for(ParamDeclList::const_iterator r = inParams.begin(); r != inParams.end(); ++r)
+ {
+ _out << (fixId((*r)->name()) + ":" + typeToString((*r)->type(), p, imports(), true, false, true));
+ }
+ _out << ("current:" + icePrefix + getUnqualified("Ice.Current", p->scope(), icePrefix));
+ _out << epar << ":";
+
+ if(!ret && outParams.empty())
+ {
+ _out << "PromiseLike<void>|void";
+ }
+ else if((ret && outParams.empty()) || (!ret && outParams.size() == 1))
+ {
+ TypePtr t = ret ? ret : outParams.front()->type();
+ string returnType = typeToString(t, p, imports(), true, false, true);
+ _out << "PromiseLike<" << returnType << ">|" << returnType;
+ }
+ else
+ {
+ ostringstream os;
+ if(ret)
+ {
+ os << typeToString(ret, p, imports(), true, false, true) << ", ";
+ }
+
+ for(ParamDeclList::const_iterator i = outParams.begin(); i != outParams.end();)
+ {
+ os << typeToString((*i)->type(), p, imports(), true, false, true);
+ if(++i != outParams.end())
+ {
+ os << ", ";
+ }
+ }
+ _out << "PromiseLike<[" << os.str() << "]>|[" << os.str() << "]";
+ }
+ _out << ";";
+ }
+ _out << nl << "/**";
+ _out << nl << " * Obtains the Slice type ID of this type.";
+ _out << nl << " * @return The return value is always \"" + p->scoped() + "\".";
+ _out << nl << " */";
+ _out << nl << "static ice_staticId():string;";
+ _out << eb;
+ }
+
+ if(!p->isInterface())
+ {
+ const DataMemberList dataMembers = p->dataMembers();
+ const DataMemberList allDataMembers = p->allDataMembers();
+ _out << sp;
+ writeDocSummary(_out, p);
+ _out << nl << "class " << fixId(p->name()) << " extends ";
+ const string scope = p->scope();
+ const string scoped = p->scoped();
+ ClassList bases = p->bases();
+ if(!bases.empty() && !bases.front()->isInterface())
+ {
+ ClassDefPtr base = bases.front();
+ const string prefix = importPrefix(ContainedPtr::dynamicCast(base), p, imports());
+ _out << prefix << getUnqualified(fixId(base->scoped()), p->scope(), prefix);
+ }
+ else
+ {
+ _out << icePrefix << getUnqualified("Ice.Value", p->scope(), icePrefix);
+ }
+ _out << sb;
+ _out << nl << "/**";
+ _out << nl << " * One-shot constructor to initialize all data members.";
+ for(DataMemberList::const_iterator q = allDataMembers.begin(); q != allDataMembers.end(); ++q)
+ {
+ CommentPtr comment = (*q)->parseComment(false);
+ if(comment)
+ {
+ _out << nl << " * @param " << fixId((*q)->name()) << " " << getDocSentence(comment->overview());
+ }
+ }
+ _out << nl << " */";
+ _out << nl << "constructor" << spar;
+ for(DataMemberList::const_iterator q = allDataMembers.begin(); q != allDataMembers.end(); ++q)
+ {
+ _out << (fixId((*q)->name()) + "?:" + typeToString((*q)->type(), p, imports(), true, false, true));
+ }
+ _out << epar << ";";
+ for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q)
+ {
+ writeDocSummary(_out, *q);
+ _out << nl << fixId((*q)->name()) << ":" << typeToString((*q)->type(), p, imports(), true, false, true)
+ << ";";
+ }
+ _out << eb;
+ }
+ }
+ return false;
+}
+
+bool
+Slice::Gen::TypeScriptVisitor::visitExceptionStart(const ExceptionPtr& p)
+{
+ const string name = fixId(p->name());
+ const DataMemberList dataMembers = p->dataMembers();
+ const DataMemberList allDataMembers = p->allDataMembers();
+ const string toplevelModule = getModuleMetadata(ContainedPtr::dynamicCast(p));
+ const string icePrefix = importPrefix("Ice.", p);
+
+ ExceptionPtr base = p->base();
+ string baseRef;
+ if(base)
+ {
+ const string prefix = importPrefix(ContainedPtr::dynamicCast(base), p, imports());
+ baseRef = prefix + getUnqualified(fixId(base->scoped()), p->scope(), prefix);
+ }
+ else
+ {
+ baseRef = p->isLocal() ?
+ icePrefix + getUnqualified("Ice.LocalException", p->scope(), icePrefix) :
+ icePrefix + getUnqualified("Ice.UserException", p->scope(), icePrefix);
+ }
+
+ _out << sp;
+ writeDocSummary(_out, p);
+ _out << nl << "class " << name << " extends " << baseRef << sb;
+ if(!allDataMembers.empty())
+ {
+ _out << nl << "/**";
+ _out << nl << " * One-shot constructor to initialize all data members.";
+ for(DataMemberList::const_iterator q = allDataMembers.begin(); q != allDataMembers.end(); ++q)
+ {
+ CommentPtr comment = (*q)->parseComment(false);
+ if(comment)
+ {
+ _out << nl << " * @param " << fixId((*q)->name()) << " " << getDocSentence(comment->overview());
+ }
+ }
+ _out << nl << " */";
+ _out << nl << "constructor" << spar;
+ for(DataMemberList::const_iterator q = allDataMembers.begin(); q != allDataMembers.end(); ++q)
+ {
+ _out << (fixId((*q)->name()) + "?:" + typeToString((*q)->type(), p, imports(), true, false, true));
+ }
+ _out << epar << ";";
+ }
+ for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q)
+ {
+ _out << nl << fixId((*q)->name()) << ":" << typeToString((*q)->type(), p, imports(), true, false, true) << ";";
+ }
+ _out << eb;
+ return false;
+}
+
+bool
+Slice::Gen::TypeScriptVisitor::visitStructStart(const StructPtr& p)
+{
+ const string icePrefix = importPrefix("Ice.", p);
+ const string name = fixId(p->name());
+ const DataMemberList dataMembers = p->dataMembers();
+ const string toplevelModule = getModuleMetadata(ContainedPtr::dynamicCast(p));
+ _out << sp;
+ writeDocSummary(_out, p);
+ _out << nl << "class " << name << sb;
+ _out << nl << "constructor" << spar;
+ for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q)
+ {
+ _out << (fixId((*q)->name()) + "?:" + typeToString((*q)->type(), p, imports(), true, false, true));
+ }
+ _out << epar << ";";
+
+ _out << nl << "clone():" << name << ";";
+ _out << nl << "equals(rhs:any):boolean;";
+
+ //
+ // Only generate hashCode if this structure type is a legal dictionary key type.
+ //
+ bool containsSequence = false;
+ bool legalKeyType = Dictionary::legalKeyType(p, containsSequence);
+ if(legalKeyType)
+ {
+ _out << nl << "hashCode():number;";
+ }
+
+ for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q)
+ {
+ _out << nl << fixId((*q)->name()) << ":" << typeToString((*q)->type(), p, imports(), true, false, true) << ";";
+ }
+
+ //
+ // Streaming API
+ //
+ _out << nl << "static write(outs:" << icePrefix << getUnqualified("Ice.OutputStream", p->scope(), icePrefix)
+ << ", value:" << name << "):void;";
+ _out << nl << "static read(ins:" << icePrefix << getUnqualified("Ice.InputStream", p->scope(), icePrefix) << "):"
+ << name << ";";
+ _out << eb;
+ return false;
+}
+
+void
+Slice::Gen::TypeScriptVisitor::visitSequence(const SequencePtr& p)
+{
+ const string icePrefix = importPrefix("Ice.", p);
+ const string toplevelModule = getModuleMetadata(ContainedPtr::dynamicCast(p));
+ const string name = fixId(p->name());
+ _out << sp;
+ writeDocSummary(_out, p);
+ _out << nl << "type " << name << " = " << typeToString(p, p, imports(), true, true) << ";";
+
+ _out << sp;
+ _out << nl << "class " << fixId(p->name() + "Helper");
+ _out << sb;
+ //
+ // Streaming API
+ //
+ _out << nl << "static write(outs:" << icePrefix << getUnqualified("Ice.OutputStream", p->scope(), icePrefix)
+ << ", value:" << name << "):void;";
+ _out << nl << "static read(ins:" << icePrefix << getUnqualified("Ice.InputStream", p->scope(), icePrefix) << "):"
+ << name << ";";
+ _out << eb;
+}
+
+void
+Slice::Gen::TypeScriptVisitor::visitDictionary(const DictionaryPtr& p)
+{
+ const string icePrefix = importPrefix("Ice.", p);
+ const string toplevelModule = getModuleMetadata(ContainedPtr::dynamicCast(p));
+ const string name = fixId(p->name());
+ _out << sp;
+ writeDocSummary(_out, p);
+ _out << nl << "class " << name << " extends " << typeToString(p, p, imports(), true, true);
+ _out << sb;
+ _out << eb;
+
+ _out << sp;
+ _out << nl << "class " << fixId(p->name() + "Helper");
+ _out << sb;
+ //
+ // Streaming API
+ //
+ _out << nl << "static write(outs:" << icePrefix << getUnqualified("Ice.OutputStream", p->scope(), icePrefix)
+ << ", value:" << name << "):void;";
+ _out << nl << "static read(ins:" << icePrefix << getUnqualified("Ice.InputStream", p->scope(), icePrefix) << "):"
+ << name << ";";
+ _out << eb;
+}
+
+void
+Slice::Gen::TypeScriptVisitor::visitEnum(const EnumPtr& p)
+{
+ _out << sp;
+ writeDocSummary(_out, p);
+ _out << nl << "class " << fixId(p->name());
+ _out << sb;
+ const EnumeratorList enumerators = p->enumerators();
+ for(EnumeratorList::const_iterator en = enumerators.begin(); en != enumerators.end(); ++en)
+ {
+ writeDocSummary(_out, *en);
+ _out << nl << "static readonly " << fixId((*en)->name()) << ":" << fixId(p->name()) << ";";
+ }
+ _out << nl;
+ _out << nl << "static valueOf(value:number):" << fixId(p->name()) << ";";
+ _out << nl << "equals(other:any):boolean;";
+ _out << nl << "hashCode():number;";
+ _out << nl << "toString():string;";
+ _out << nl;
+ _out << nl << "readonly name:string;";
+ _out << nl << "readonly value:number;";
+ _out << eb;
+}
+
+void
+Slice::Gen::TypeScriptVisitor::visitConst(const ConstPtr& p)
+{
+ const string toplevelModule = getModuleMetadata(p->type());
+ _out << sp;
+ writeDocSummary(_out, p);
+ _out << nl << "const " << fixId(p->name()) << ":" << typeToString(p->type(), p, imports(), true) << ";";
+}
diff --git a/cpp/src/slice2js/Gen.h b/cpp/src/slice2js/Gen.h
index a778ba65fd4..f5bc6216a52 100644
--- a/cpp/src/slice2js/Gen.h
+++ b/cpp/src/slice2js/Gen.h
@@ -19,14 +19,18 @@ class JsVisitor : public JsGenerator, public ParserVisitor
{
public:
- JsVisitor(::IceUtilInternal::Output&);
+ JsVisitor(::IceUtilInternal::Output&,
+ const std::vector<std::pair<std::string, std::string>>& imports =
+ std::vector<std::pair<std::string, std::string>>());
virtual ~JsVisitor();
+ std::vector<std::pair<std::string, std::string>> imports() const;
+
protected:
void writeMarshalDataMembers(const DataMemberList&, const DataMemberList&);
void writeUnmarshalDataMembers(const DataMemberList&, const DataMemberList&);
- void writeInitDataMembers(const DataMemberList&, const std::string&);
+ void writeInitDataMembers(const DataMemberList&);
std::string getValue(const std::string&, const TypePtr&);
@@ -36,6 +40,8 @@ protected:
void writeDocComment(const ContainedPtr&, const std::string&, const std::string& = "");
::IceUtilInternal::Output& _out;
+
+ std::vector<std::pair<std::string, std::string>> _imports;
};
class Gen : public JsGenerator
@@ -44,11 +50,13 @@ public:
Gen(const std::string&,
const std::vector<std::string>&,
- const std::string&);
+ const std::string&,
+ bool);
Gen(const std::string&,
const std::vector<std::string>&,
const std::string&,
+ bool,
std::ostream&);
~Gen();
@@ -58,14 +66,14 @@ public:
private:
- std::ofstream _stdout;
IceUtilInternal::Output _out;
std::vector<std::string> _includePaths;
std::string _fileBase;
bool _useStdout;
-
- void printHeader();
+ bool _typeScript;
+ bool _buildModule;
+ bool _noModule;
class RequireVisitor : public JsVisitor
{
@@ -95,7 +103,9 @@ private:
bool _seenLocalException;
bool _seenEnum;
bool _seenObjectSeq;
+ bool _seenObjectProxySeq;
bool _seenObjectDict;
+ bool _seenObjectProxyDict;
std::vector<std::string> _includePaths;
};
@@ -103,7 +113,7 @@ private:
{
public:
- TypesVisitor(::IceUtilInternal::Output&, std::vector< std::string>, bool);
+ TypesVisitor(::IceUtilInternal::Output&, std::vector<std::string>, bool);
virtual bool visitModuleStart(const ModulePtr&);
virtual void visitModuleEnd(const ModulePtr&);
@@ -130,12 +140,81 @@ private:
ExportVisitor(::IceUtilInternal::Output&, bool, bool);
virtual bool visitModuleStart(const ModulePtr&);
+
private:
bool _icejs;
bool _es6modules;
std::vector<std::string> _exported;
};
+
+ class TypeScriptRequireVisitor : public JsVisitor
+ {
+ public:
+
+ TypeScriptRequireVisitor(::IceUtilInternal::Output&);
+
+ virtual bool visitModuleStart(const ModulePtr&);
+ virtual bool visitClassDefStart(const ClassDefPtr&);
+ virtual bool visitStructStart(const StructPtr&);
+ virtual bool visitExceptionStart(const ExceptionPtr&);
+ virtual void visitSequence(const SequencePtr&);
+ virtual void visitDictionary(const DictionaryPtr&);
+
+ void writeRequires(const UnitPtr&);
+
+ private:
+
+ void addImport(const TypePtr&, const ContainedPtr&);
+ void addImport(const ContainedPtr&, const ContainedPtr&);
+ void addImport(const std::string&, const std::string&, const std::string&, const std::string&);
+
+ std::string nextImportPrefix();
+
+ int _nextImport;
+ std::map<std::string, std::string> _modulePrefix;
+ };
+
+ class TypeScriptAliasVisitor : public JsVisitor
+ {
+ public:
+
+ TypeScriptAliasVisitor(::IceUtilInternal::Output&);
+
+ virtual bool visitModuleStart(const ModulePtr&);
+ virtual bool visitClassDefStart(const ClassDefPtr&);
+ virtual bool visitStructStart(const StructPtr&);
+ virtual bool visitExceptionStart(const ExceptionPtr&);
+ virtual void visitSequence(const SequencePtr&);
+ virtual void visitDictionary(const DictionaryPtr&);
+
+ void writeAlias(const UnitPtr&);
+
+ private:
+
+ void addAlias(const ExceptionPtr&, const ContainedPtr&);
+ void addAlias(const TypePtr&, const ContainedPtr&);
+ void addAlias(const std::string&, const std::string&, const ContainedPtr&);
+ std::vector<std::pair<std::string, std::string>> _aliases;
+ };
+
+ class TypeScriptVisitor : public JsVisitor
+ {
+ public:
+
+ TypeScriptVisitor(::IceUtilInternal::Output&,
+ const std::vector<std::pair<std::string, std::string>>&);
+
+ virtual bool visitModuleStart(const ModulePtr&);
+ virtual void visitModuleEnd(const ModulePtr&);
+ 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&);
+ };
};
}
diff --git a/cpp/src/slice2js/JsUtil.cpp b/cpp/src/slice2js/JsUtil.cpp
index b33dfacb9d6..ec262b7c648 100644
--- a/cpp/src/slice2js/JsUtil.cpp
+++ b/cpp/src/slice2js/JsUtil.cpp
@@ -10,6 +10,7 @@
#include <JsUtil.h>
#include <Slice/Util.h>
#include <IceUtil/Functional.h>
+#include <IceUtil/StringUtil.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -27,6 +28,64 @@ using namespace Slice;
using namespace IceUtil;
using namespace IceUtilInternal;
+string
+Slice::relativePath(const string& p1, const string& p2)
+{
+ vector<string> tokens1;
+ vector<string> tokens2;
+
+ splitString(p1, "/\\", tokens1);
+ splitString(p2, "/\\", tokens2);
+
+ string f1 = tokens1.back();
+ string f2 = tokens2.back();
+
+ tokens1.pop_back();
+ tokens2.pop_back();
+
+ vector<string>::const_iterator i1 = tokens1.begin();
+ vector<string>::const_iterator i2 = tokens2.begin();
+
+ while(i1 != tokens1.end() && i2 != tokens2.end() && *i1 == *i2)
+ {
+ i1++;
+ i2++;
+ }
+
+ //
+ // Different volumes, relative path not possible.
+ //
+ if(i1 == tokens1.begin() && i2 == tokens2.begin())
+ {
+ return p1;
+ }
+
+ string newPath;
+ if(i2 == tokens2.end())
+ {
+ newPath += "./";
+ for (; i1 != tokens1.end(); ++i1)
+ {
+ newPath += *i1 + "/";
+ }
+ }
+ else
+ {
+ for(size_t i = tokens2.end() - i2; i > 0; i--)
+ {
+ newPath += "../";
+ }
+
+ for(; i1 != tokens1.end(); ++i1)
+ {
+ newPath += *i1 + "/";
+ }
+ }
+ newPath += f1;
+
+ return newPath;
+}
+
static string
lookupKwd(const string& name)
{
@@ -99,11 +158,71 @@ fixIds(const StringList& ids)
return newIds;
}
+string
+Slice::JsGenerator::getModuleMetadata(const TypePtr& type)
+{
+ static const char* builtinModuleTable[] =
+ {
+ "", // byte
+ "", // bool
+ "", // short
+ "", // int
+ "ice", // long
+ "", // float
+ "", // double
+ "", // string
+ "ice", // Ice.Value
+ "ice", // Ice.ObjectPrx
+ "", // LocalObject
+ "ice" // Ice.Object
+ };
+
+ BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
+ if(builtin)
+ {
+ return builtinModuleTable[builtin->kind()];
+ }
+
+ ProxyPtr proxy = ProxyPtr::dynamicCast(type);
+ return getModuleMetadata(proxy ? ContainedPtr::dynamicCast(proxy->_class()->definition()) :
+ ContainedPtr::dynamicCast(type));
+}
+
+string
+Slice::JsGenerator::getModuleMetadata(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;
+ }
+ }
+
+ const string prefix = "js:module:";
+ string value;
+ findMetaData(prefix, m->getMetaData(), value);
+ return value;
+}
+
bool
Slice::JsGenerator::isClassType(const TypePtr& type)
{
BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
- return (builtin && (builtin->kind() == Builtin::KindObject || builtin->kind() == Builtin::KindValue)) || ClassDeclPtr::dynamicCast(type);
+ return (builtin && (builtin->kind() == Builtin::KindObject || builtin->kind() == Builtin::KindValue)) ||
+ ClassDeclPtr::dynamicCast(type);
}
//
@@ -146,20 +265,182 @@ Slice::JsGenerator::fixId(const ContainedPtr& cont)
}
string
-Slice::JsGenerator::typeToString(const TypePtr& type)
+Slice::JsGenerator::importPrefix(const TypePtr& type,
+ const ContainedPtr& toplevel,
+ const vector<pair<string, string>>& imports)
+{
+ BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
+ if(builtin)
+ {
+ return typeToString(type, toplevel, imports, true);
+ }
+ else if(ProxyPtr::dynamicCast(type))
+ {
+ ProxyPtr proxy = ProxyPtr::dynamicCast(type);
+ return importPrefix(ContainedPtr::dynamicCast(proxy->_class()->definition()), toplevel, imports);
+ }
+ else if(ContainedPtr::dynamicCast(type))
+ {
+ bool local = false;
+ if(toplevel)
+ {
+ if(ConstructedPtr::dynamicCast(toplevel))
+ {
+ local = ConstructedPtr::dynamicCast(toplevel)->isLocal();
+ }
+ else if(ClassDefPtr::dynamicCast(toplevel))
+ {
+ local = ClassDefPtr::dynamicCast(toplevel)->isLocal();
+ }
+ }
+
+ ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
+ if(cl && cl->isInterface() && !local)
+ {
+ return "iceNS0.";
+ }
+ else
+ {
+ return importPrefix(ContainedPtr::dynamicCast(type), toplevel, imports);
+ }
+ }
+ return "";
+}
+
+string
+Slice::JsGenerator::importPrefix(const ContainedPtr& contained,
+ const ContainedPtr& toplevel,
+ const vector<pair<string, string>>& imports)
+{
+ string m1 = getModuleMetadata(contained);
+ string m2 = getModuleMetadata(toplevel);
+
+ string p;
+
+ if(m1.empty())
+ {
+ string p1 = contained->definitionContext()->filename();
+ string p2 = toplevel->definitionContext()->filename();
+
+ p = relativePath(p1, p2);
+
+ string::size_type pos = p.rfind('.');
+ if (pos != string::npos)
+ {
+ p.erase(pos);
+ }
+ }
+ else if(m1 == "ice" && m1 != m2)
+ {
+ return "iceNS0.";
+ }
+ else if(m1 != m2)
+ {
+ p = m1;
+ }
+
+ if(!p.empty())
+ {
+ for (vector<pair<string, string>>::const_iterator i = imports.begin(); i != imports.end(); ++i)
+ {
+ if (i->first == p)
+ {
+ return i->second + ".";
+ }
+ }
+ }
+
+ return "";
+}
+
+bool
+Slice::JsGenerator::findMetaData(const string& prefix, const StringList& metaData, string& value)
+{
+ for(StringList::const_iterator i = metaData.begin(); i != metaData.end(); i++)
+ {
+ string s = *i;
+ if(s.find(prefix) == 0)
+ {
+ value = s.substr(prefix.size());
+ return true;
+ }
+ }
+ return false;
+}
+
+string
+Slice::JsGenerator::importPrefix(const string& type, const ContainedPtr& toplevel)
+{
+ const string module = getModuleMetadata(toplevel);
+ return (type.find("Ice.") == 0 && module != "ice") ? "iceNS0." : "";
+}
+
+string
+Slice::JsGenerator::getUnqualified(const string& type, const string& scope, const string& importPrefix)
+{
+ if(importPrefix.empty())
+ {
+ const string localScope = getLocalScope(scope) + ".";
+ if(type.find(localScope) == 0)
+ {
+ string t = type.substr(localScope.size());
+ if(t.find(".") == string::npos)
+ {
+ return t;
+ }
+ }
+ }
+ return type;
+}
+
+string
+Slice::JsGenerator::typeToString(const TypePtr& type,
+ const ContainedPtr& toplevel,
+ const vector<pair<string, string>>& imports,
+ bool typescript,
+ bool definition)
{
if(!type)
{
return "void";
}
- static const char* builtinTable[] =
+ bool local = false;
+ if(toplevel)
+ {
+ if(ConstructedPtr::dynamicCast(toplevel))
+ {
+ local = ConstructedPtr::dynamicCast(toplevel)->isLocal();
+ }
+ else if(ClassDefPtr::dynamicCast(toplevel))
+ {
+ local = ClassDefPtr::dynamicCast(toplevel)->isLocal();
+ }
+ }
+
+ static const char* typeScriptBuiltinTable[] =
+ {
+ "number", // byte
+ "boolean", // bool
+ "number", // short
+ "number", // int
+ "Ice.Long", // long
+ "number", // float
+ "number", // double
+ "string",
+ "Ice.Object",
+ "Ice.ObjectPrx",
+ "Object",
+ "Ice.Value"
+ };
+
+ static const char* javaScriptBuiltinTable[] =
{
"Number", // byte
"Boolean", // bool
"Number", // short
"Number", // int
- "Number", // long
+ "Ice.Long", // long
"Number", // float
"Number", // double
"String",
@@ -172,39 +453,186 @@ Slice::JsGenerator::typeToString(const TypePtr& type)
BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
if(builtin)
{
- return builtinTable[builtin->kind()];
+ if(typescript)
+ {
+ int kind = (!local && builtin->kind() == Builtin::KindObject) ? Builtin::KindValue : builtin->kind();
+ ostringstream os;
+ if(getModuleMetadata(type) == "ice" && getModuleMetadata(toplevel) != "ice")
+ {
+ os << "iceNS0.";
+ }
+ os << getUnqualified(typeScriptBuiltinTable[kind], toplevel->scope(), "iceNS0.");
+ return os.str();
+ }
+ else
+ {
+ return javaScriptBuiltinTable[builtin->kind()];
+ }
+ }
+
+ ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
+ if(cl)
+ {
+ string prefix;
+ ostringstream os;
+ if(typescript)
+ {
+ if(cl->isInterface() && !local)
+ {
+ prefix = importPrefix("Ice.Value", toplevel);
+ }
+ else
+ {
+ prefix = importPrefix(ContainedPtr::dynamicCast(cl), toplevel, imports);
+ }
+ }
+ os << prefix;
+ if(!prefix.empty() && typescript)
+ {
+ if(cl->isInterface() && !local)
+ {
+ os << getUnqualified("Ice.Value", toplevel->scope(), prefix);
+ }
+ else
+ {
+ os << getUnqualified(fixId(cl->scoped()), toplevel->scope(), prefix);
+ }
+ }
+ else
+ {
+ os << fixId(cl->scoped());
+ }
+ return os.str();
}
ProxyPtr proxy = ProxyPtr::dynamicCast(type);
if(proxy)
{
- return fixId(proxy->_class()->scoped() + "Prx");
- }
+ ostringstream os;
+ string prefix;
+ if(typescript)
+ {
+ prefix = importPrefix(ContainedPtr::dynamicCast(proxy->_class()->definition()), toplevel, imports);
+ os << prefix;
+ }
- SequencePtr seq = SequencePtr::dynamicCast(type);
- if(seq)
- {
- return typeToString(seq->type()) + "[]";
+ if(prefix.empty() && typescript)
+ {
+ os << getUnqualified(fixId(proxy->_class()->scoped() + "Prx"), toplevel->scope(), prefix);
+ }
+ else
+ {
+ os << fixId(proxy->_class()->scoped() + "Prx");
+ }
+ return os.str();
}
- DictionaryPtr d = DictionaryPtr::dynamicCast(type);
- if(d)
+ if(!typescript || definition)
{
- const TypePtr keyType = d->keyType();
- BuiltinPtr b = BuiltinPtr::dynamicCast(keyType);
- return ((b && b->kind() == Builtin::KindLong) || StructPtr::dynamicCast(keyType)) ? "Ice.HashMap" : "Map";
+ SequencePtr seq = SequencePtr::dynamicCast(type);
+ if (seq)
+ {
+ BuiltinPtr b = BuiltinPtr::dynamicCast(seq->type());
+ if (b && b->kind() == Builtin::KindByte)
+ {
+ return "Uint8Array";
+ }
+ else
+ {
+ return typeToString(seq->type(), toplevel, imports, typescript) + "[]";
+ }
+ }
+
+ DictionaryPtr d = DictionaryPtr::dynamicCast(type);
+ if(d)
+ {
+ const TypePtr keyType = d->keyType();
+ BuiltinPtr builtin = BuiltinPtr::dynamicCast(keyType);
+ ostringstream os;
+ if ((builtin && builtin->kind() == Builtin::KindLong) || StructPtr::dynamicCast(keyType))
+ {
+ const string prefix = importPrefix("Ice.HashMap", toplevel);
+ os << prefix << getUnqualified("Ice.HashMap", toplevel->scope(), prefix);
+ }
+ else
+ {
+ os << "Map";
+ }
+
+ if (typescript)
+ {
+ os << "<"
+ << typeToString(keyType, toplevel, imports, true) << ", "
+ << typeToString(d->valueType(), toplevel, imports, true) << ">";
+ }
+ return os.str();
+ }
}
ContainedPtr contained = ContainedPtr::dynamicCast(type);
if(contained)
{
- return fixId(contained->scoped());
+ ostringstream os;
+ string prefix;
+ if(typescript)
+ {
+ prefix = importPrefix(contained, toplevel, imports);
+ os << prefix;
+ }
+
+ if(prefix.empty() && typescript)
+ {
+ os << getUnqualified(fixId(contained->scoped()), toplevel->scope(), prefix);
+ }
+ else
+ {
+ os << fixId(contained->scoped());
+ }
+ return os.str();
}
return "???";
}
string
+Slice::JsGenerator::typeToString(const TypePtr& type,
+ const ContainedPtr& toplevel,
+ const std::vector<std::pair<std::string, std::string>>& imports,
+ bool typeScript,
+ bool definition,
+ bool usealias)
+{
+ string t = typeToString(type, toplevel, imports, typeScript, definition);
+ if(usealias)
+ {
+ string m1 = getModuleMetadata(type);
+ string m2 = getModuleMetadata(toplevel);
+ if (!m1.empty() && m1 == m2)
+ {
+ // we are using the same module
+ return t;
+ }
+ string p = importPrefix(type, toplevel, imports);
+
+ //
+ // When using an import prefix we don't need an alias, prefixes use iceNSXX that is reserved
+ // name prefix
+ //
+ string::size_type i = t.find(".");
+ if(p.empty() && i != string::npos)
+ {
+ const string scoped = fixId(toplevel->scoped()) + ".";
+ if(scoped.find("." + t.substr(0, i + 1)) != string::npos)
+ {
+ replace(t.begin(), t.end(), '.', '_');
+ t = "iceA_" + t;
+ }
+ }
+ }
+ return t;
+}
+
+string
Slice::JsGenerator::getLocalScope(const string& scope, const string& separator)
{
assert(!scope.empty());
@@ -222,6 +650,7 @@ Slice::JsGenerator::getLocalScope(const string& scope, const string& separator)
{
fixedScope = scope;
}
+
if(fixedScope.empty())
{
return "";
@@ -243,39 +672,6 @@ Slice::JsGenerator::getLocalScope(const string& scope, const string& separator)
return result.str();
}
-string
-Slice::JsGenerator::getReference(const string& scope, const string& target)
-{
- //
- // scope and target should be fully-qualified symbols.
- //
- assert(!scope.empty() && scope[0] == ':' && !target.empty() && target[0] == ':');
-
- //
- // Check whether the target is in the given scope.
- //
- if(target.find(scope) == 0)
- {
- //
- // Remove scope from target, but keep the leading "::".
- //
- const string rem = target.substr(scope.size() - 2);
- assert(!rem.empty());
- const StringList ids = fixIds(splitScopedName(rem));
- stringstream result;
- result << getLocalScope(scope);
- for(StringList::const_iterator i = ids.begin(); i != ids.end(); ++i)
- {
- result << '.' << *i;
- }
- return result.str();
- }
- else
- {
- return fixId(target);
- }
-}
-
void
Slice::JsGenerator::writeMarshalUnmarshalCode(Output &out,
const TypePtr& type,
diff --git a/cpp/src/slice2js/JsUtil.h b/cpp/src/slice2js/JsUtil.h
index 69d9ad6e9c6..e56162a698d 100644
--- a/cpp/src/slice2js/JsUtil.h
+++ b/cpp/src/slice2js/JsUtil.h
@@ -16,20 +16,46 @@
namespace Slice
{
+std::string relativePath(const std::string&, const std::string&);
+
class JsGenerator : private ::IceUtil::noncopyable
{
public:
virtual ~JsGenerator() {};
-protected:
-
static bool isClassType(const TypePtr&);
+ static std::string getModuleMetadata(const TypePtr&);
+ static std::string getModuleMetadata(const ContainedPtr&);
static std::string fixId(const std::string&);
static std::string fixId(const ContainedPtr&);
- static std::string typeToString(const TypePtr&);
+ static bool findMetaData(const std::string&, const StringList&, std::string&);
+ static std::string importPrefix(const TypePtr&,
+ const ContainedPtr&,
+ const std::vector<std::pair<std::string, std::string>>&);
+
+ static std::string importPrefix(const ContainedPtr&,
+ const ContainedPtr&,
+ const std::vector<std::pair<std::string, std::string>>&);
+ static std::string importPrefix(const std::string&, const ContainedPtr&);
+
+ static std::string getUnqualified(const std::string&, const std::string&, const std::string&);
+
+ static std::string typeToString(const TypePtr&,
+ const ContainedPtr& = 0,
+ const std::vector<std::pair<std::string, std::string>>& =
+ std::vector<std::pair<std::string, std::string>>(),
+ bool typeScript = false,
+ bool definition = false);
+
+ static std::string typeToString(const TypePtr&,
+ const ContainedPtr&,
+ const std::vector<std::pair<std::string, std::string>>&,
+ bool typeScript,
+ bool definition,
+ bool usealias);
+
static std::string getLocalScope(const std::string&, const std::string& separator = ".");
- static std::string getReference(const std::string&, const std::string&);
static std::string getHelper(const TypePtr&);
//
diff --git a/cpp/src/slice2js/Main.cpp b/cpp/src/slice2js/Main.cpp
index 46cf1671d48..062abe2083f 100644
--- a/cpp/src/slice2js/Main.cpp
+++ b/cpp/src/slice2js/Main.cpp
@@ -75,6 +75,7 @@ usage(const string& n)
"--depend-file FILE Write dependencies to FILE instead of standard output.\n"
"--validate Validate command line options.\n"
"--stdout Print generated code to stdout.\n"
+ "--typescript Generate TypeScript declaration file\n"
"--depend-json Generate dependency information in JSON format.\n"
"--ice Allow reserved Ice prefix in Slice identifiers\n"
" deprecated: use instead [[\"ice-prefix\"]] metadata.\n"
@@ -95,6 +96,7 @@ compile(const vector<string>& argv)
opts.addOpt("I", "", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat);
opts.addOpt("E");
opts.addOpt("", "stdout");
+ opts.addOpt("", "typescript");
opts.addOpt("", "output-dir", IceUtilInternal::Options::NeedArg);
opts.addOpt("", "depend");
opts.addOpt("", "depend-json");
@@ -172,6 +174,8 @@ compile(const vector<string>& argv)
bool underscore = opts.isSet("underscore");
+ bool typeScript = opts.isSet("typescript");
+
if(args.empty())
{
consoleErr << argv[0] << ": error: no input file" << endl;
@@ -247,16 +251,16 @@ compile(const vector<string>& argv)
for(vector<string>::const_iterator i = sources.begin(); i != sources.end();)
{
- if(depend || dependJSON || dependxml)
- {
- PreprocessorPtr icecpp = Preprocessor::create(argv[0], *i, cppArgs);
- FILE* cppHandle = icecpp->preprocess(false, "-D__SLICE2JS__");
+ PreprocessorPtr icecpp = Preprocessor::create(argv[0], *i, cppArgs);
+ FILE* cppHandle = icecpp->preprocess(true, "-D__SLICE2JS__");
- if(cppHandle == 0)
- {
- return EXIT_FAILURE;
- }
+ if(cppHandle == 0)
+ {
+ return EXIT_FAILURE;
+ }
+ if(depend || dependJSON || dependxml)
+ {
UnitPtr u = Unit::createUnit(false, false, ice, underscore);
int parseStatus = u->parse(*i, cppHandle, debug);
u->destroy();
@@ -292,13 +296,6 @@ compile(const vector<string>& argv)
}
else
{
- PreprocessorPtr icecpp = Preprocessor::create(argv[0], *i, cppArgs);
- FILE* cppHandle = icecpp->preprocess(true, "-D__SLICE2JS__");
-
- if(cppHandle == 0)
- {
- return EXIT_FAILURE;
- }
if(preprocess)
{
char buf[4096];
@@ -335,12 +332,12 @@ compile(const vector<string>& argv)
{
if(useStdout)
{
- Gen gen(icecpp->getBaseName(), includePaths, output, cout);
+ Gen gen(icecpp->getBaseName(), includePaths, output, typeScript, cout);
gen.generate(p);
}
else
{
- Gen gen(icecpp->getBaseName(), includePaths, output);
+ Gen gen(icecpp->getBaseName(), includePaths, output, typeScript);
gen.generate(p);
}
}