1 //
2 // Copyright (c) ZeroC, Inc. All rights reserved.
3 //
4
5 #include <JsUtil.h>
6 #include <Slice/Util.h>
7 #include <IceUtil/Functional.h>
8 #include <IceUtil/StringUtil.h>
9
10 #include <sys/types.h>
11 #include <sys/stat.h>
12
13 #ifdef _WIN32
14 #include <direct.h>
15 #endif
16
17 #ifndef _WIN32
18 #include <unistd.h>
19 #endif
20
21 // TODO: fix this warning!
22 #if defined(_MSC_VER)
23 # pragma warning(disable:4456) // shadow
24 # pragma warning(disable:4457) // shadow
25 # pragma warning(disable:4459) // shadow
26 #elif defined(__clang__)
27 # pragma clang diagnostic ignored "-Wshadow"
28 #elif defined(__GNUC__)
29 # pragma GCC diagnostic ignored "-Wshadow"
30 #endif
31
32 using namespace std;
33 using namespace Slice;
34 using namespace IceUtil;
35 using namespace IceUtilInternal;
36
37 string
relativePath(const string & p1,const string & p2)38 Slice::relativePath(const string& p1, const string& p2)
39 {
40 vector<string> tokens1;
41 vector<string> tokens2;
42
43 splitString(p1, "/\\", tokens1);
44 splitString(p2, "/\\", tokens2);
45
46 string f1 = tokens1.back();
47 string f2 = tokens2.back();
48
49 tokens1.pop_back();
50 tokens2.pop_back();
51
52 vector<string>::const_iterator i1 = tokens1.begin();
53 vector<string>::const_iterator i2 = tokens2.begin();
54
55 while(i1 != tokens1.end() && i2 != tokens2.end() && *i1 == *i2)
56 {
57 i1++;
58 i2++;
59 }
60
61 //
62 // Different volumes, relative path not possible.
63 //
64 if(i1 == tokens1.begin() && i2 == tokens2.begin())
65 {
66 return p1;
67 }
68
69 string newPath;
70 if(i2 == tokens2.end())
71 {
72 newPath += "./";
73 for (; i1 != tokens1.end(); ++i1)
74 {
75 newPath += *i1 + "/";
76 }
77 }
78 else
79 {
80 for(size_t i = tokens2.end() - i2; i > 0; i--)
81 {
82 newPath += "../";
83 }
84
85 for(; i1 != tokens1.end(); ++i1)
86 {
87 newPath += *i1 + "/";
88 }
89 }
90 newPath += f1;
91
92 return newPath;
93 }
94
95 static string
lookupKwd(const string & name)96 lookupKwd(const string& name)
97 {
98 //
99 // Keyword list. *Must* be kept in alphabetical order.
100 //
101 static const string keywordList[] =
102 {
103 "await", "break", "case", "catch", "class", "const", "continue", "debugger", "default", "delete", "do",
104 "else", "enum", "export", "extends", "false", "finally", "for", "function", "if", "implements", "import",
105 "in", "instanceof", "interface", "let", "new", "null", "package", "private", "protected", "public", "return",
106 "static", "super", "switch", "this", "throw", "true", "try", "typeof", "var", "void", "while", "with",
107 "yield"
108 };
109 bool found = binary_search(&keywordList[0],
110 &keywordList[sizeof(keywordList) / sizeof(*keywordList)],
111 name,
112 Slice::CICompare());
113 if(found)
114 {
115 return "_" + name;
116 }
117
118 return name;
119 }
120
121 //
122 // Split a scoped name into its components and return the components as a list of (unscoped) identifiers.
123 //
124 static StringList
splitScopedName(const string & scoped)125 splitScopedName(const string& scoped)
126 {
127 assert(scoped[0] == ':');
128 StringList ids;
129 string::size_type next = 0;
130 string::size_type pos;
131 while((pos = scoped.find("::", next)) != string::npos)
132 {
133 pos += 2;
134 if(pos != scoped.size())
135 {
136 string::size_type endpos = scoped.find("::", pos);
137 if(endpos != string::npos)
138 {
139 ids.push_back(scoped.substr(pos, endpos - pos));
140 }
141 }
142 next = pos;
143 }
144 if(next != scoped.size())
145 {
146 ids.push_back(scoped.substr(next));
147 }
148 else
149 {
150 ids.push_back("");
151 }
152
153 return ids;
154 }
155
156 static StringList
fixIds(const StringList & ids)157 fixIds(const StringList& ids)
158 {
159 StringList newIds;
160 for(StringList::const_iterator i = ids.begin(); i != ids.end(); ++i)
161 {
162 newIds.push_back(lookupKwd(*i));
163 }
164 return newIds;
165 }
166
167 string
getModuleMetadata(const TypePtr & type)168 Slice::JsGenerator::getModuleMetadata(const TypePtr& type)
169 {
170 static const char* builtinModuleTable[] =
171 {
172 "", // byte
173 "", // bool
174 "", // short
175 "", // int
176 "ice", // long
177 "", // float
178 "", // double
179 "", // string
180 "ice", // Ice.Value
181 "ice", // Ice.ObjectPrx
182 "", // LocalObject
183 "ice" // Ice.Object
184 };
185
186 BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
187 if(builtin)
188 {
189 return builtinModuleTable[builtin->kind()];
190 }
191
192 ProxyPtr proxy = ProxyPtr::dynamicCast(type);
193 return getModuleMetadata(proxy ? ContainedPtr::dynamicCast(proxy->_class()->definition()) :
194 ContainedPtr::dynamicCast(type));
195 }
196
197 string
getModuleMetadata(const ContainedPtr & p)198 Slice::JsGenerator::getModuleMetadata(const ContainedPtr& p)
199 {
200 //
201 // Check if the file contains the python:pkgdir global metadata.
202 //
203 DefinitionContextPtr dc = p->definitionContext();
204 assert(dc);
205 const string prefix = "js:module:";
206 const string value = dc->findMetaData(prefix);
207 return value.empty() ? value : value.substr(prefix.size());
208 }
209
210 bool
isClassType(const TypePtr & type)211 Slice::JsGenerator::isClassType(const TypePtr& type)
212 {
213 BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
214 return (builtin && (builtin->kind() == Builtin::KindObject || builtin->kind() == Builtin::KindValue)) ||
215 ClassDeclPtr::dynamicCast(type);
216 }
217
218 //
219 // If the passed name is a scoped name, return the identical scoped name,
220 // but with all components that are JS keywords replaced by
221 // their "_"-prefixed version; otherwise, if the passed name is
222 // not scoped, but a JS keyword, return the "_"-prefixed name.
223 //
224 string
fixId(const string & name)225 Slice::JsGenerator::fixId(const string& name)
226 {
227 if(name.empty())
228 {
229 return name;
230 }
231 if(name[0] != ':')
232 {
233 return lookupKwd(name);
234 }
235
236 const StringList ids = splitScopedName(name);
237 const StringList newIds = fixIds(ids);
238
239 stringstream result;
240 for(StringList::const_iterator j = newIds.begin(); j != newIds.end(); ++j)
241 {
242 if(j != newIds.begin())
243 {
244 result << '.';
245 }
246 result << *j;
247 }
248 return result.str();
249 }
250
251 string
fixId(const ContainedPtr & cont)252 Slice::JsGenerator::fixId(const ContainedPtr& cont)
253 {
254 return fixId(cont->name());
255 }
256
257 string
importPrefix(const TypePtr & type,const ContainedPtr & toplevel,const vector<pair<string,string>> & imports)258 Slice::JsGenerator::importPrefix(const TypePtr& type,
259 const ContainedPtr& toplevel,
260 const vector<pair<string, string> >& imports)
261 {
262 BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
263 if(builtin)
264 {
265 return typeToString(type, toplevel, imports, true);
266 }
267 else if(ProxyPtr::dynamicCast(type))
268 {
269 ProxyPtr proxy = ProxyPtr::dynamicCast(type);
270 return importPrefix(ContainedPtr::dynamicCast(proxy->_class()->definition()), toplevel, imports);
271 }
272 else if(ContainedPtr::dynamicCast(type))
273 {
274 bool local = false;
275 if(toplevel)
276 {
277 if(ConstructedPtr::dynamicCast(toplevel))
278 {
279 local = ConstructedPtr::dynamicCast(toplevel)->isLocal();
280 }
281 else if(ClassDefPtr::dynamicCast(toplevel))
282 {
283 local = ClassDefPtr::dynamicCast(toplevel)->isLocal();
284 }
285 }
286
287 ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
288 if(cl && cl->isInterface() && !local)
289 {
290 return "iceNS0.";
291 }
292 else
293 {
294 return importPrefix(ContainedPtr::dynamicCast(type), toplevel, imports);
295 }
296 }
297 return "";
298 }
299
300 string
importPrefix(const ContainedPtr & contained,const ContainedPtr & toplevel,const vector<pair<string,string>> & imports)301 Slice::JsGenerator::importPrefix(const ContainedPtr& contained,
302 const ContainedPtr& toplevel,
303 const vector<pair<string, string> >& imports)
304 {
305 string m1 = getModuleMetadata(contained);
306 string m2 = getModuleMetadata(toplevel);
307
308 string p;
309
310 if(m1.empty())
311 {
312 string p1 = contained->definitionContext()->filename();
313 string p2 = toplevel->definitionContext()->filename();
314
315 p = relativePath(p1, p2);
316
317 string::size_type pos = p.rfind('.');
318 if (pos != string::npos)
319 {
320 p.erase(pos);
321 }
322 }
323 else if(m1 == "ice" && m1 != m2)
324 {
325 return "iceNS0.";
326 }
327 else if(m1 != m2)
328 {
329 p = m1;
330 }
331
332 if(!p.empty())
333 {
334 for(vector<pair<string, string> >::const_iterator i = imports.begin(); i != imports.end(); ++i)
335 {
336 if(i->first == p)
337 {
338 return i->second + ".";
339 }
340 }
341 }
342
343 return "";
344 }
345
346 bool
findMetaData(const string & prefix,const StringList & metaData,string & value)347 Slice::JsGenerator::findMetaData(const string& prefix, const StringList& metaData, string& value)
348 {
349 for(StringList::const_iterator i = metaData.begin(); i != metaData.end(); i++)
350 {
351 string s = *i;
352 if(s.find(prefix) == 0)
353 {
354 value = s.substr(prefix.size());
355 return true;
356 }
357 }
358 return false;
359 }
360
361 string
importPrefix(const string & type,const ContainedPtr & toplevel)362 Slice::JsGenerator::importPrefix(const string& type, const ContainedPtr& toplevel)
363 {
364 const string module = getModuleMetadata(toplevel);
365 return (type.find("Ice.") == 0 && module != "ice") ? "iceNS0." : "";
366 }
367
368 string
getUnqualified(const string & type,const string & scope,const string & importPrefix)369 Slice::JsGenerator::getUnqualified(const string& type, const string& scope, const string& importPrefix)
370 {
371 if(importPrefix.empty())
372 {
373 const string localScope = getLocalScope(scope) + ".";
374 if(type.find(localScope) == 0)
375 {
376 string t = type.substr(localScope.size());
377 if(t.find(".") == string::npos)
378 {
379 return t;
380 }
381 }
382 }
383 return type;
384 }
385
386 string
typeToString(const TypePtr & type,const ContainedPtr & toplevel,const vector<pair<string,string>> & imports,bool typescript,bool definition)387 Slice::JsGenerator::typeToString(const TypePtr& type,
388 const ContainedPtr& toplevel,
389 const vector<pair<string, string> >& imports,
390 bool typescript,
391 bool definition)
392 {
393 if(!type)
394 {
395 return "void";
396 }
397
398 bool local = false;
399 if(toplevel)
400 {
401 if(ConstructedPtr::dynamicCast(toplevel))
402 {
403 local = ConstructedPtr::dynamicCast(toplevel)->isLocal();
404 }
405 else if(ClassDefPtr::dynamicCast(toplevel))
406 {
407 local = ClassDefPtr::dynamicCast(toplevel)->isLocal();
408 }
409 }
410
411 static const char* typeScriptBuiltinTable[] =
412 {
413 "number", // byte
414 "boolean", // bool
415 "number", // short
416 "number", // int
417 "Ice.Long", // long
418 "number", // float
419 "number", // double
420 "string",
421 "Ice.Object",
422 "Ice.ObjectPrx",
423 "Object",
424 "Ice.Value"
425 };
426
427 static const char* javaScriptBuiltinTable[] =
428 {
429 "Number", // byte
430 "Boolean", // bool
431 "Number", // short
432 "Number", // int
433 "Ice.Long", // long
434 "Number", // float
435 "Number", // double
436 "String",
437 "Ice.Value",
438 "Ice.ObjectPrx",
439 "Object",
440 "Ice.Value"
441 };
442
443 BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
444 if(builtin)
445 {
446 if(typescript)
447 {
448 int kind = (!local && builtin->kind() == Builtin::KindObject) ? Builtin::KindValue : builtin->kind();
449 ostringstream os;
450 if(getModuleMetadata(type) == "ice" && getModuleMetadata(toplevel) != "ice")
451 {
452 os << "iceNS0.";
453 }
454 os << getUnqualified(typeScriptBuiltinTable[kind], toplevel->scope(), "iceNS0.");
455 return os.str();
456 }
457 else
458 {
459 return javaScriptBuiltinTable[builtin->kind()];
460 }
461 }
462
463 ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
464 if(cl)
465 {
466 string prefix;
467 ostringstream os;
468 if(typescript)
469 {
470 if(cl->isInterface() && !local)
471 {
472 prefix = importPrefix("Ice.Value", toplevel);
473 }
474 else
475 {
476 prefix = importPrefix(ContainedPtr::dynamicCast(cl), toplevel, imports);
477 }
478 }
479 os << prefix;
480 if(!prefix.empty() && typescript)
481 {
482 if(cl->isInterface() && !local)
483 {
484 os << getUnqualified("Ice.Value", toplevel->scope(), prefix);
485 }
486 else
487 {
488 os << getUnqualified(fixId(cl->scoped()), toplevel->scope(), prefix);
489 }
490 }
491 else
492 {
493 os << fixId(cl->scoped());
494 }
495 return os.str();
496 }
497
498 ProxyPtr proxy = ProxyPtr::dynamicCast(type);
499 if(proxy)
500 {
501 ostringstream os;
502 ClassDefPtr def = proxy->_class()->definition();
503 if(!def->isInterface() && def->allOperations().empty())
504 {
505 if(getModuleMetadata(toplevel) != "ice")
506 {
507 os << "iceNS0.";
508 }
509 os << getUnqualified(typeScriptBuiltinTable[Builtin::KindObjectProxy],
510 toplevel->scope(),
511 getModuleMetadata(toplevel));
512 }
513 else
514 {
515 string prefix;
516 if(typescript)
517 {
518 prefix = importPrefix(ContainedPtr::dynamicCast(def), toplevel, imports);
519 os << prefix;
520 }
521
522 if(prefix.empty() && typescript)
523 {
524 os << getUnqualified(fixId(proxy->_class()->scoped() + "Prx"), toplevel->scope(), prefix);
525 }
526 else
527 {
528 os << fixId(proxy->_class()->scoped() + "Prx");
529 }
530 }
531 return os.str();
532 }
533
534 if(!typescript || definition)
535 {
536 SequencePtr seq = SequencePtr::dynamicCast(type);
537 if (seq)
538 {
539 BuiltinPtr b = BuiltinPtr::dynamicCast(seq->type());
540 if (b && b->kind() == Builtin::KindByte)
541 {
542 return "Uint8Array";
543 }
544 else
545 {
546 return typeToString(seq->type(), toplevel, imports, typescript) + "[]";
547 }
548 }
549
550 DictionaryPtr d = DictionaryPtr::dynamicCast(type);
551 if(d)
552 {
553 const TypePtr keyType = d->keyType();
554 BuiltinPtr builtin = BuiltinPtr::dynamicCast(keyType);
555 ostringstream os;
556 if ((builtin && builtin->kind() == Builtin::KindLong) || StructPtr::dynamicCast(keyType))
557 {
558 const string prefix = importPrefix("Ice.HashMap", toplevel);
559 os << prefix << getUnqualified("Ice.HashMap", toplevel->scope(), prefix);
560 }
561 else
562 {
563 os << "Map";
564 }
565
566 if (typescript)
567 {
568 os << "<"
569 << typeToString(keyType, toplevel, imports, true) << ", "
570 << typeToString(d->valueType(), toplevel, imports, true) << ">";
571 }
572 return os.str();
573 }
574 }
575
576 ContainedPtr contained = ContainedPtr::dynamicCast(type);
577 if(contained)
578 {
579 ostringstream os;
580 string prefix;
581 if(typescript)
582 {
583 prefix = importPrefix(contained, toplevel, imports);
584 os << prefix;
585 }
586
587 if(prefix.empty() && typescript)
588 {
589 os << getUnqualified(fixId(contained->scoped()), toplevel->scope(), prefix);
590 }
591 else
592 {
593 os << fixId(contained->scoped());
594 }
595 return os.str();
596 }
597
598 return "???";
599 }
600
601 string
typeToString(const TypePtr & type,const ContainedPtr & toplevel,const std::vector<std::pair<std::string,std::string>> & imports,bool typeScript,bool definition,bool usealias)602 Slice::JsGenerator::typeToString(const TypePtr& type,
603 const ContainedPtr& toplevel,
604 const std::vector<std::pair<std::string, std::string> >& imports,
605 bool typeScript,
606 bool definition,
607 bool usealias)
608 {
609 string t = typeToString(type, toplevel, imports, typeScript, definition);
610 if(usealias)
611 {
612 string m1 = getModuleMetadata(type);
613 string m2 = getModuleMetadata(toplevel);
614 if (!m1.empty() && m1 == m2)
615 {
616 // we are using the same module
617 return t;
618 }
619 string p = importPrefix(type, toplevel, imports);
620
621 //
622 // When using an import prefix we don't need an alias, prefixes use iceNSXX that is reserved
623 // name prefix
624 //
625 string::size_type i = t.find(".");
626 if(p.empty() && i != string::npos)
627 {
628 const string scoped = fixId(toplevel->scoped()) + ".";
629 if(scoped.find("." + t.substr(0, i + 1)) != string::npos)
630 {
631 replace(t.begin(), t.end(), '.', '_');
632 t = "iceA_" + t;
633 }
634 }
635 }
636 return t;
637 }
638
639 string
getLocalScope(const string & scope,const string & separator)640 Slice::JsGenerator::getLocalScope(const string& scope, const string& separator)
641 {
642 assert(!scope.empty());
643
644 //
645 // Remove trailing "::" if present.
646 //
647 string fixedScope;
648 if(scope[scope.size() - 1] == ':')
649 {
650 assert(scope[scope.size() - 2] == ':');
651 fixedScope = scope.substr(0, scope.size() - 2);
652 }
653 else
654 {
655 fixedScope = scope;
656 }
657
658 if(fixedScope.empty())
659 {
660 return "";
661 }
662 const StringList ids = fixIds(splitScopedName(fixedScope));
663
664 //
665 // Return local scope for "::A::B::C" as A.B.C
666 //
667 stringstream result;
668 for(StringList::const_iterator i = ids.begin(); i != ids.end(); ++i)
669 {
670 if(i != ids.begin())
671 {
672 result << separator;
673 }
674 result << *i;
675 }
676 return result.str();
677 }
678
679 void
writeMarshalUnmarshalCode(Output & out,const TypePtr & type,const string & param,bool marshal)680 Slice::JsGenerator::writeMarshalUnmarshalCode(Output &out,
681 const TypePtr& type,
682 const string& param,
683 bool marshal)
684 {
685 string stream = marshal ? "ostr" : "istr";
686
687 BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
688 if(builtin)
689 {
690 switch(builtin->kind())
691 {
692 case Builtin::KindByte:
693 {
694 if(marshal)
695 {
696 out << nl << stream << ".writeByte(" << param << ");";
697 }
698 else
699 {
700 out << nl << param << " = " << stream << ".readByte()" << ';';
701 }
702 return;
703 }
704 case Builtin::KindBool:
705 {
706 if(marshal)
707 {
708 out << nl << stream << ".writeBool(" << param << ");";
709 }
710 else
711 {
712 out << nl << param << " = " << stream << ".readBool()" << ';';
713 }
714 return;
715 }
716 case Builtin::KindShort:
717 {
718 if(marshal)
719 {
720 out << nl << stream << ".writeShort(" << param << ");";
721 }
722 else
723 {
724 out << nl << param << " = " << stream << ".readShort()" << ';';
725 }
726 return;
727 }
728 case Builtin::KindInt:
729 {
730 if(marshal)
731 {
732 out << nl << stream << ".writeInt(" << param << ");";
733 }
734 else
735 {
736 out << nl << param << " = " << stream << ".readInt()" << ';';
737 }
738 return;
739 }
740 case Builtin::KindLong:
741 {
742 if(marshal)
743 {
744 out << nl << stream << ".writeLong(" << param << ");";
745 }
746 else
747 {
748 out << nl << param << " = " << stream << ".readLong()" << ';';
749 }
750 return;
751 }
752 case Builtin::KindFloat:
753 {
754 if(marshal)
755 {
756 out << nl << stream << ".writeFloat(" << param << ");";
757 }
758 else
759 {
760 out << nl << param << " = " << stream << ".readFloat()" << ';';
761 }
762 return;
763 }
764 case Builtin::KindDouble:
765 {
766 if(marshal)
767 {
768 out << nl << stream << ".writeDouble(" << param << ");";
769 }
770 else
771 {
772 out << nl << param << " = " << stream << ".readDouble()" << ';';
773 }
774 return;
775 }
776 case Builtin::KindString:
777 {
778 if(marshal)
779 {
780 out << nl << stream << ".writeString(" << param << ");";
781 }
782 else
783 {
784 out << nl << param << " = " << stream << ".readString()" << ';';
785 }
786 return;
787 }
788 case Builtin::KindObject:
789 case Builtin::KindValue:
790 {
791 // Handle by isClassType below.
792 break;
793 }
794 case Builtin::KindObjectProxy:
795 {
796 if(marshal)
797 {
798 out << nl << stream << ".writeProxy(" << param << ");";
799 }
800 else
801 {
802 out << nl << param << " = " << stream << ".readProxy();";
803 }
804 return;
805 }
806 case Builtin::KindLocalObject:
807 {
808 assert(false);
809 return;
810 }
811 }
812 }
813
814 if(EnumPtr::dynamicCast(type))
815 {
816 if(marshal)
817 {
818 out << nl << typeToString(type) << "._write(" << stream << ", " << param << ");";
819 }
820 else
821 {
822 out << nl << param << " = " << typeToString(type) << "._read(" << stream << ");";
823 }
824 return;
825 }
826
827 if(ProxyPtr::dynamicCast(type) || StructPtr::dynamicCast(type))
828 {
829 if(marshal)
830 {
831 out << nl << typeToString(type) << ".write(" << stream << ", " << param << ");";
832 }
833 else
834 {
835 out << nl << param << " = " << typeToString(type) << ".read(" << stream << ", " << param << ");";
836 }
837 return;
838 }
839
840 if(isClassType(type))
841 {
842 if(marshal)
843 {
844 out << nl << stream << ".writeValue(" << param << ");";
845 }
846 else
847 {
848 out << nl << stream << ".readValue(obj => " << param << " = obj, " << typeToString(type) << ");";
849 }
850 return;
851 }
852
853 if(SequencePtr::dynamicCast(type) || DictionaryPtr::dynamicCast(type))
854 {
855 if(marshal)
856 {
857 out << nl << getHelper(type) <<".write(" << stream << ", " << param << ");";
858 }
859 else
860 {
861 out << nl << param << " = " << getHelper(type) << ".read(" << stream << ");";
862 }
863 return;
864 }
865
866 assert(false);
867 }
868
869 void
writeOptionalMarshalUnmarshalCode(Output & out,const TypePtr & type,const string & param,int tag,bool marshal)870 Slice::JsGenerator::writeOptionalMarshalUnmarshalCode(Output &out,
871 const TypePtr& type,
872 const string& param,
873 int tag,
874 bool marshal)
875 {
876 string stream = marshal ? "ostr" : "istr";
877
878 if(isClassType(type))
879 {
880 if(marshal)
881 {
882 out << nl << stream << ".writeOptionalValue(" << tag << ", " << param << ");";
883 }
884 else
885 {
886 out << nl << stream << ".readOptionalValue(" << tag << ", obj => " << param << " = obj, "
887 << typeToString(type) << ");";
888 }
889 return;
890 }
891
892 if(EnumPtr::dynamicCast(type))
893 {
894 if(marshal)
895 {
896 out << nl << typeToString(type) <<"._writeOpt(" << stream << ", " << tag << ", " << param << ");";
897 }
898 else
899 {
900 out << nl << param << " = " << typeToString(type) << "._readOpt(" << stream << ", " << tag << ");";
901 }
902 return;
903 }
904
905 if(marshal)
906 {
907 out << nl << getHelper(type) <<".writeOptional(" << stream << ", " << tag << ", " << param << ");";
908 }
909 else
910 {
911 out << nl << param << " = " << getHelper(type) << ".readOptional(" << stream << ", " << tag << ");";
912 }
913 }
914
915 std::string
getHelper(const TypePtr & type)916 Slice::JsGenerator::getHelper(const TypePtr& type)
917 {
918 BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
919 if(builtin)
920 {
921 switch(builtin->kind())
922 {
923 case Builtin::KindByte:
924 {
925 return "Ice.ByteHelper";
926 }
927 case Builtin::KindBool:
928 {
929 return "Ice.BoolHelper";
930 }
931 case Builtin::KindShort:
932 {
933 return "Ice.ShortHelper";
934 }
935 case Builtin::KindInt:
936 {
937 return "Ice.IntHelper";
938 }
939 case Builtin::KindLong:
940 {
941 return "Ice.LongHelper";
942 }
943 case Builtin::KindFloat:
944 {
945 return "Ice.FloatHelper";
946 }
947 case Builtin::KindDouble:
948 {
949 return "Ice.DoubleHelper";
950 }
951 case Builtin::KindString:
952 {
953 return "Ice.StringHelper";
954 }
955 case Builtin::KindObject:
956 case Builtin::KindValue:
957 {
958 return "Ice.ObjectHelper";
959 }
960 case Builtin::KindObjectProxy:
961 {
962 return "Ice.ObjectPrx";
963 }
964 case Builtin::KindLocalObject:
965 {
966 assert(false);
967 break;
968 }
969 }
970 }
971
972 if(EnumPtr::dynamicCast(type))
973 {
974 return typeToString(type) + "._helper";
975 }
976
977 if(StructPtr::dynamicCast(type))
978 {
979 return typeToString(type);
980 }
981
982 ProxyPtr prx = ProxyPtr::dynamicCast(type);
983 if(prx)
984 {
985 ClassDefPtr def = prx->_class()->definition();
986 if(def->isInterface() || def->allOperations().size() > 0)
987 {
988 return typeToString(type);
989 }
990 else
991 {
992 return "Ice.ObjectPrx";
993 }
994 }
995
996 if(SequencePtr::dynamicCast(type) || DictionaryPtr::dynamicCast(type))
997 {
998 stringstream s;
999 s << getLocalScope(ContainedPtr::dynamicCast(type)->scoped()) << "Helper";
1000 return s.str();
1001 }
1002
1003 if(ClassDeclPtr::dynamicCast(type))
1004 {
1005 return "Ice.ObjectHelper";
1006 }
1007
1008 assert(false);
1009 return "???";
1010 }
1011