1 //
2 // Copyright (c) ZeroC, Inc. All rights reserved.
3 //
4
5 #include <ObjCUtil.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 using namespace std;
22 using namespace Slice;
23 using namespace IceUtil;
24 using namespace IceUtilInternal;
25
26 Slice::ObjCGenerator::ModuleMap Slice::ObjCGenerator::_modules;
27
28 static string
lookupKwd(const string & name,int baseType,bool mangleCasts=false)29 lookupKwd(const string& name, int baseType, bool mangleCasts = false)
30 {
31 //
32 // All lists in this method *must* be kept in case-insensitive
33 // alphabetical order.
34 //
35 static string keywordList[] =
36 {
37 "auto", "BOOL", "break", "bycopy", "byref", "case", "char", "const", "continue",
38 "default", "do", "double", "else", "enum", "extern", "float", "for", "goto",
39 "id", "if", "IMP", "in", "inline", "inout", "int", "long", "nil", "NO", "oneway", "out",
40 "register", "return", "SEL", "self", "short", "signed", "sizeof", "static", "struct", "super", "switch",
41 "typedef", "union", "unsigned", "void", "volatile", "while", "YES"
42 };
43
44 static string nsObjectList[] =
45 {
46 "autorelease", "class", "classForCoder", "copy", "dealloc", "description", "hash", "init", "isa",
47 "isProxy", "mutableCopy", "release", "retain", "retainCount", "superclass", "zone"
48 };
49 static string nsExceptionList[] =
50 {
51 "callStackReturnAddresses", "name", "raise", "reason", "reserved", "userInfo",
52 };
53
54 bool found = binary_search(&keywordList[0],
55 &keywordList[sizeof(keywordList) / sizeof(*keywordList)],
56 name,
57 Slice::CICompare());
58 if(!found)
59 {
60 switch(baseType)
61 {
62 case BaseTypeNone:
63 break;
64
65 case BaseTypeException:
66 found = binary_search(&nsExceptionList[0],
67 &nsExceptionList[sizeof(nsExceptionList) / sizeof(*nsExceptionList)],
68 name,
69 Slice::CICompare());
70 if(found)
71 {
72 break;
73 }
74 /* FALLTHROUGH */
75
76 case BaseTypeObject:
77 found = binary_search(&nsObjectList[0],
78 &nsObjectList[sizeof(nsObjectList) / sizeof(*nsObjectList)],
79 name,
80 Slice::CICompare());
81 break;
82 }
83 }
84 if(found || (mangleCasts && (name == "checkedCast" || name == "uncheckedCast")))
85 {
86 return name + "_";
87 }
88 return name;
89 }
90
91 static string
lookupParamIdKwd(const string & name)92 lookupParamIdKwd(const string& name)
93 {
94 //
95 // All lists in this method *must* be kept in case-insensitive
96 // alphabetical order.
97 //
98 static string keywordList[] =
99 {
100 "nil", "NO", "YES"
101 };
102 if(binary_search(&keywordList[0],
103 &keywordList[sizeof(keywordList) / sizeof(*keywordList)],
104 name,
105 Slice::CICompare()))
106 {
107 return name + "_";
108 }
109 return name;
110 }
111
112 bool
addModule(const ModulePtr & m,const string & name)113 Slice::ObjCGenerator::addModule(const ModulePtr& m, const string& name)
114 {
115 string scoped = m->scoped();
116 ModuleMap::const_iterator i = _modules.find(scoped);
117 if(i != _modules.end())
118 {
119 if(i->second.name != name)
120 {
121 return false;
122 }
123 }
124 else
125 {
126 ModulePrefix mp;
127 mp.m = m;
128 mp.name = name;
129 _modules[scoped] = mp;
130 }
131 return true;
132 }
133
134 Slice::ObjCGenerator::ModulePrefix
modulePrefix(const ModulePtr & m)135 Slice::ObjCGenerator::modulePrefix(const ModulePtr& m)
136 {
137 return _modules[m->scoped()];
138 }
139
140 string
moduleName(const ModulePtr & m)141 Slice::ObjCGenerator::moduleName(const ModulePtr& m)
142 {
143 return _modules[m->scoped()].name;
144 }
145
146 ModulePtr
findModule(const ContainedPtr & cont,int,bool)147 Slice::ObjCGenerator::findModule(const ContainedPtr& cont, int /*baseTypes*/, bool /*mangleCasts*/)
148 {
149 ModulePtr m = ModulePtr::dynamicCast(cont);
150 ContainerPtr container = cont->container();
151 while(container && !m)
152 {
153 ContainedPtr contained = ContainedPtr::dynamicCast(container);
154 container = contained->container();
155 m = ModulePtr::dynamicCast(contained);
156 }
157 assert(m);
158 return m;
159 }
160
161 //
162 // If the passed name is a scoped name, return the identical scoped
163 // name, but with all components that are Objective-C keywords
164 // replaced by their prefixed version; otherwise, if the passed name
165 // is not scoped, but an Objective-C keyword, return the prefixed
166 // name; otherwise, check if the name is one of the method names of
167 // baseTypes; if so, returned the prefixed name; otherwise, return the
168 // name unchanged.
169 //
170 string
fixId(const string & name,int baseTypes,bool mangleCasts)171 Slice::ObjCGenerator::fixId(const string& name, int baseTypes, bool mangleCasts)
172 {
173 if(name.empty())
174 {
175 return name;
176 }
177 return lookupKwd(name, baseTypes, mangleCasts);
178 }
179
180 string
fixId(const ContainedPtr & cont,int baseTypes,bool mangleCasts)181 Slice::ObjCGenerator::fixId(const ContainedPtr& cont, int baseTypes, bool mangleCasts)
182 {
183 return fixId(cont->name(), baseTypes, mangleCasts);
184 }
185
186 string
fixName(const ContainedPtr & cont,int baseTypes,bool mangleCasts)187 Slice::ObjCGenerator::fixName(const ContainedPtr& cont, int baseTypes, bool mangleCasts)
188 {
189 return moduleName(findModule(cont, baseTypes, mangleCasts)) + cont->name();
190 }
191
192 string
getParamId(const ContainedPtr & param)193 Slice::ObjCGenerator::getParamId(const ContainedPtr& param)
194 {
195 string n;
196 if(ParamDeclPtr::dynamicCast(param) && param->findMetaData("objc:param:", n))
197 {
198 return lookupParamIdKwd(n.substr(11));
199 }
200 else
201 {
202 return lookupParamIdKwd(param->name());
203 }
204 }
205
206 string
getParamName(const ContainedPtr & param,bool internal)207 Slice::ObjCGenerator::getParamName(const ContainedPtr& param, bool internal)
208 {
209 if(internal)
210 {
211 return "iceP_" + param->name();
212 }
213 else
214 {
215 return fixId(param->name());
216 }
217 }
218
219 string
getFactoryMethod(const ContainedPtr & p,bool deprecated)220 Slice::ObjCGenerator::getFactoryMethod(const ContainedPtr& p, bool deprecated)
221 {
222 ClassDefPtr def = ClassDefPtr::dynamicCast(p);
223 if(def && def->declaration()->isLocal())
224 {
225 deprecated = false; // Local classes don't have this issue since they were added after this fix.
226 }
227
228 //
229 // If deprecated is true, we return uDPConnectionInfo for a class
230 // named UDPConnectionInfo, return udpConnectionInfo otherwise.
231 //
232 string name = fixId(p->name());
233 if(name.empty())
234 {
235 return name;
236 }
237 else if(deprecated || name.size() < 2 || !isupper(*(name.begin() + 1)))
238 {
239 *name.begin() = static_cast<char>(tolower(*name.begin()));
240 }
241 else
242 {
243 for(string::iterator q = name.begin(); q != name.end() && isalpha(*q); ++q)
244 {
245 if(q != name.end() - 1 && isalpha(*(q + 1)) && !isupper(*(q + 1)))
246 {
247 break;
248 }
249 *q = static_cast<char>(tolower(*q));
250 }
251 }
252 return name;
253 }
254
255 string
typeToString(const TypePtr & type)256 Slice::ObjCGenerator::typeToString(const TypePtr& type)
257 {
258 if(!type)
259 {
260 return "void";
261 }
262
263 static const char* builtinTable[] =
264 {
265 "ICEByte",
266 "BOOL",
267 "ICEShort",
268 "ICEInt",
269 "ICELong",
270 "ICEFloat",
271 "ICEDouble",
272 "NSString",
273 "ICEObject",
274 "id<ICEObjectPrx>",
275 "id", // Dummy--we don't support Slice local Object
276 "ICEObject"
277 };
278
279 BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
280 if(builtin)
281 {
282 return builtinTable[builtin->kind()];
283 }
284
285 ProxyPtr proxy = ProxyPtr::dynamicCast(type);
286 if(proxy)
287 {
288 string mName = moduleName(findModule(proxy->_class()));
289 return "id<" + mName + (proxy->_class()->name()) + "Prx>";
290 }
291
292 SequencePtr seq = SequencePtr::dynamicCast(type);
293 if(seq)
294 {
295 return fixName(seq);
296 }
297
298 DictionaryPtr d = DictionaryPtr::dynamicCast(type);
299 if(d)
300 {
301 return fixName(d);
302 }
303
304 ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
305 if(cl)
306 {
307 if(cl->isInterface())
308 {
309 if(cl->definition() && cl->definition()->isDelegate())
310 {
311 return fixName(cl);
312 }
313 else if(cl->isLocal())
314 {
315 return "id<" + fixName(cl) + ">";
316 }
317 else
318 {
319 return "ICEObject";
320 }
321 }
322 else if(cl->isLocal())
323 {
324 string name = fixName(cl);
325 return name + "<" + name + ">";
326 }
327 }
328
329 ContainedPtr contained = ContainedPtr::dynamicCast(type);
330 if(contained)
331 {
332 return fixName(contained);
333 }
334
335 return "???";
336 }
337
338 string
inTypeToString(const TypePtr & type,bool optional,bool autoreleasing,bool reference)339 Slice::ObjCGenerator::inTypeToString(const TypePtr& type, bool optional, bool autoreleasing, bool reference)
340 {
341 string s;
342 if(optional)
343 {
344 s = "id";
345 }
346 else
347 {
348 s = typeToString(type);
349 if(mapsToPointerType(type))
350 {
351 s += "*";
352 }
353 }
354 if(autoreleasing && !isValueType(type))
355 {
356 s += " ICE_AUTORELEASING_QUALIFIER";
357 }
358 if(reference)
359 {
360 s += "*";
361 }
362 return s;
363 }
364
365 string
outTypeToString(const TypePtr & type,bool optional,bool autoreleasing,bool reference)366 Slice::ObjCGenerator::outTypeToString(const TypePtr& type, bool optional, bool autoreleasing, bool reference)
367 {
368 if(!type)
369 {
370 return "void";
371 }
372
373 string s;
374 if(optional)
375 {
376 s = "id";
377 }
378 else
379 {
380 SequencePtr seq = SequencePtr::dynamicCast(type);
381 DictionaryPtr d = DictionaryPtr::dynamicCast(type);
382 if(isString(type))
383 {
384 s = "NSMutableString";
385 }
386 else if(seq)
387 {
388 string prefix = moduleName(findModule(seq));
389 s = prefix + "Mutable" + seq->name();
390 }
391 else if(d)
392 {
393 string prefix = moduleName(findModule(d));
394 s = prefix + "Mutable" + d->name();
395 }
396 else
397 {
398 s = typeToString(type);
399 }
400 if(mapsToPointerType(type))
401 {
402 s += "*";
403 }
404 }
405 if(autoreleasing && (!isValueType(type) || optional))
406 {
407 s += " ICE_AUTORELEASING_QUALIFIER";
408 }
409 if(reference)
410 {
411 s += "*";
412 }
413 return s;
414 }
415
416 string
typeToObjCTypeString(const TypePtr & type)417 Slice::ObjCGenerator::typeToObjCTypeString(const TypePtr& type)
418 {
419 ProxyPtr proxy = ProxyPtr::dynamicCast(type);
420 if(proxy)
421 {
422 return moduleName(findModule(proxy->_class())) + (proxy->_class()->name()) + "Prx";
423 }
424 else
425 {
426 return typeToString(type);
427 }
428 }
429
430 bool
isValueType(const TypePtr & type)431 Slice::ObjCGenerator::isValueType(const TypePtr& type)
432 {
433 if(!type)
434 {
435 return true;
436 }
437 BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
438 if(builtin)
439 {
440 switch(builtin->kind())
441 {
442 case Builtin::KindString:
443 case Builtin::KindObject:
444 case Builtin::KindValue:
445 case Builtin::KindObjectProxy:
446 case Builtin::KindLocalObject:
447 {
448 return false;
449 break;
450 }
451 default:
452 {
453 return true;
454 break;
455 }
456 }
457 }
458 if(EnumPtr::dynamicCast(type))
459 {
460 return true;
461 }
462 return false;
463 }
464
465 bool
isString(const TypePtr & type)466 Slice::ObjCGenerator::isString(const TypePtr& type)
467 {
468 if(!type)
469 {
470 return false;
471 }
472 BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
473 return builtin && builtin->kind() == Builtin::KindString;
474 }
475 bool
isClass(const TypePtr & type)476 Slice::ObjCGenerator::isClass(const TypePtr& type)
477 {
478 BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
479 if(builtin)
480 {
481 return builtin->kind() == Builtin::KindObject || builtin->kind() == Builtin::KindValue;
482 }
483 return ClassDeclPtr::dynamicCast(type);
484 }
485
486 bool
mapsToPointerType(const TypePtr & type)487 Slice::ObjCGenerator::mapsToPointerType(const TypePtr& type)
488 {
489 if(isValueType(type))
490 {
491 return false;
492 }
493 BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
494 if(builtin)
495 {
496 return builtin->kind() != Builtin::KindObjectProxy && builtin->kind() != Builtin::KindLocalObject;
497 }
498 ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
499 if(cl && cl->isInterface())
500 {
501 if(cl->isLocal() || (cl->definition() && cl->definition()->isDelegate()))
502 {
503 return false;
504 }
505 else
506 {
507 return true;
508 }
509 }
510 return !ProxyPtr::dynamicCast(type);
511 }
512
513 string
getBuiltinName(const BuiltinPtr & builtin)514 Slice::ObjCGenerator::getBuiltinName(const BuiltinPtr& builtin)
515 {
516 switch(builtin->kind())
517 {
518 case Builtin::KindByte:
519 {
520 return "Byte";
521 }
522 case Builtin::KindBool:
523 {
524 return "Bool";
525 }
526 case Builtin::KindShort:
527 {
528 return "Short";
529 }
530 case Builtin::KindInt:
531 {
532 return "Int";
533 }
534 case Builtin::KindLong:
535 {
536 return "Long";
537 }
538 case Builtin::KindFloat:
539 {
540 return "Float";
541 }
542 case Builtin::KindDouble:
543 {
544 return "Double";
545 }
546 case Builtin::KindString:
547 {
548 return "String";
549 }
550 case Builtin::KindObject:
551 case Builtin::KindValue:
552 {
553 return "Object";
554 }
555 case Builtin::KindObjectProxy:
556 {
557 return "Proxy";
558 }
559 default:
560 {
561 assert(false);
562 }
563 }
564 return "NO__SUCH__TYPE";
565 }
566
567 string
getOptionalHelperGetter(const TypePtr & type)568 Slice::ObjCGenerator::getOptionalHelperGetter(const TypePtr& type)
569 {
570 if(isValueType(type))
571 {
572 BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
573 if(builtin)
574 {
575 return "get" + getBuiltinName(builtin);
576 }
577 if(EnumPtr::dynamicCast(type))
578 {
579 return "getInt";
580 }
581 }
582 return "get";
583 }
584
585 //
586 // Split a scoped name into its components and return the components as a list of (unscoped) identifiers.
587 //
588 StringList
splitScopedName(const string & scoped)589 Slice::ObjCGenerator::splitScopedName(const string& scoped)
590 {
591 assert(scoped[0] == ':');
592 StringList ids;
593 string::size_type next = 0;
594 string::size_type pos;
595 while((pos = scoped.find("::", next)) != string::npos)
596 {
597 pos += 2;
598 if(pos != scoped.size())
599 {
600 string::size_type endpos = scoped.find("::", pos);
601 if(endpos != string::npos)
602 {
603 ids.push_back(scoped.substr(pos, endpos - pos));
604 }
605 }
606 next = pos;
607 }
608 if(next != scoped.size())
609 {
610 ids.push_back(scoped.substr(next));
611 }
612 else
613 {
614 ids.push_back("");
615 }
616
617 return ids;
618 }
619
620 string
getOptionalFormat(const TypePtr & type)621 Slice::ObjCGenerator::getOptionalFormat(const TypePtr& type)
622 {
623 BuiltinPtr bp = BuiltinPtr::dynamicCast(type);
624 if(bp)
625 {
626 switch(bp->kind())
627 {
628 case Builtin::KindByte:
629 case Builtin::KindBool:
630 {
631 return "ICEOptionalFormatF1";
632 }
633 case Builtin::KindShort:
634 {
635 return "ICEOptionalFormatF2";
636 }
637 case Builtin::KindInt:
638 case Builtin::KindFloat:
639 {
640 return "ICEOptionalFormatF4";
641 }
642 case Builtin::KindLong:
643 case Builtin::KindDouble:
644 {
645 return "ICEOptionalFormatF8";
646 }
647 case Builtin::KindString:
648 {
649 return "ICEOptionalFormatVSize";
650 }
651 case Builtin::KindObject:
652 case Builtin::KindValue:
653 {
654 return "ICEOptionalFormatClass";
655 }
656 case Builtin::KindObjectProxy:
657 {
658 return "ICEOptionalFormatFSize";
659 }
660 case Builtin::KindLocalObject:
661 {
662 assert(false);
663 break;
664 }
665 }
666 }
667
668 if(EnumPtr::dynamicCast(type))
669 {
670 return "ICEOptionalFormatSize";
671 }
672
673 SequencePtr seq = SequencePtr::dynamicCast(type);
674 if(seq)
675 {
676 return seq->type()->isVariableLength() ? "ICEOptionalFormatFSize" : "ICEOptionalFormatVSize";
677 }
678
679 DictionaryPtr d = DictionaryPtr::dynamicCast(type);
680 if(d)
681 {
682 return (d->keyType()->isVariableLength() || d->valueType()->isVariableLength()) ?
683 "ICEOptionalFormatFSize" : "ICEOptionalFormatVSize";
684 }
685
686 StructPtr st = StructPtr::dynamicCast(type);
687 if(st)
688 {
689 return st->isVariableLength() ? "ICEOptionalFormatFSize" : "ICEOptionalFormatVSize";
690 }
691
692 if(ProxyPtr::dynamicCast(type))
693 {
694 return "ICEOptionalFormatFSize";
695 }
696
697 ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
698 assert(cl);
699 return "ICEOptionalFormatClass";
700 }
701
702 void
writeMarshalUnmarshalCode(Output & out,const TypePtr & type,const string & param,bool marshal,bool autoreleased) const703 Slice::ObjCGenerator::writeMarshalUnmarshalCode(Output &out, const TypePtr& type, const string& param,
704 bool marshal, bool autoreleased) const
705 {
706 string stream = marshal ? "ostr" : "istr";
707 BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
708
709 if(builtin)
710 {
711 string name;
712 if(builtin->kind() == Builtin::KindObject || builtin->kind() == Builtin::KindValue)
713 {
714 if(marshal)
715 {
716 out << nl << "[" << stream << " writeValue:" << param << "];";
717 }
718 else
719 {
720 if(autoreleased)
721 {
722 out << nl << "[" << stream << " readValue:&" << param << "];";
723 }
724 else
725 {
726 out << nl << "[" << stream << " newValue:&" << param << "];";
727 }
728 }
729 }
730 else if(builtin->kind() == Builtin::KindObjectProxy)
731 {
732 if(marshal)
733 {
734 out << nl << "[" << stream << " writeProxy:" << param << "];";
735 }
736 else
737 {
738 if(autoreleased)
739 {
740 out << nl << param << " = [" << stream << " readProxy:[ICEObjectPrx class]];";
741 }
742 else
743 {
744 out << nl << param << " = [" << stream << " newProxy:[ICEObjectPrx class]];";
745 }
746 }
747 }
748 else
749 {
750 if(marshal)
751 {
752 out << nl << "[" << stream << " write" << getBuiltinName(builtin) << ":" << param << "];";
753 }
754 else
755 {
756 if(autoreleased || isValueType(builtin))
757 {
758 out << nl << param << " = [" << stream << " read" << getBuiltinName(builtin) << "];";
759 }
760 else
761 {
762 out << nl << param << " = [" << stream << " new" << getBuiltinName(builtin) << "];";
763 }
764 }
765 }
766 return;
767 }
768
769 ProxyPtr prx = ProxyPtr::dynamicCast(type);
770 if(prx)
771 {
772 if(marshal)
773 {
774 out << nl << "[" << stream << " writeProxy:(id<ICEObjectPrx>)" << param << "];";
775 }
776 else
777 {
778 string name = moduleName(findModule(prx->_class())) + prx->_class()->name() + "Prx";
779 out << nl << param << " = (id<" << name << ">)[" << stream;
780 if(autoreleased)
781 {
782 out << " readProxy:";
783 }
784 else
785 {
786 out << " newProxy:";
787 }
788 //
789 // We use objc_getClass to get the proxy class instead of [name class]. This is to avoid
790 // a warning if the proxy is forward declared.
791 //
792 if(prx->_class()->definition())
793 {
794 out << "[" << name << " class]];";
795 }
796 else
797 {
798 out << "objc_getClass(\"" << name << "\")];";
799 }
800 }
801 return;
802 }
803
804 ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
805 if(cl)
806 {
807 if(marshal)
808 {
809 // Cast avoids warning for forward-declared classes.
810 out << nl << "[" << stream << " writeValue:(ICEObject*)" << param << "];";
811 }
812 else
813 {
814 if(autoreleased)
815 {
816 out << nl << "[" << stream << " " << "readValue:(ICEObject**)&" << param;
817 }
818 else
819 {
820 out << nl << "[" << stream << " " << "newValue:(ICEObject**)&" << param;
821 }
822
823 if(cl->isInterface())
824 {
825 out << "];";
826 }
827 else
828 {
829 string name = moduleName(findModule(cl)) + cl->name();
830 if(cl->definition())
831 {
832 out << " expectedType:[" << name << " class]];";
833 }
834 else
835 {
836 out << " expectedType:objc_getClass(\"" << name << "\")];";
837 }
838 }
839 }
840 return;
841 }
842
843 EnumPtr en = EnumPtr::dynamicCast(type);
844 if(en)
845 {
846 if(marshal)
847 {
848 out << nl << "[" << stream << " writeEnumerator:" << param << " min:" << en->minValue()
849 << " max:" << en->maxValue() << "];";
850 }
851 else
852 {
853 out << nl << param << " = " << "[" << stream << " readEnumerator:" << en->minValue()
854 << " max:" << en->maxValue() << "];";
855 }
856 return;
857 }
858
859 ContainedPtr c = ContainedPtr::dynamicCast(type);
860 assert(c);
861 string name = moduleName(findModule(c)) + c->name() + "Helper";
862 if(marshal)
863 {
864 out << nl << "[" + name << " write:" << param << " stream:" << stream << "];";
865 }
866 else
867 {
868 if(StructPtr::dynamicCast(type))
869 {
870 if(autoreleased)
871 {
872 out << nl << "[" << name << " read:" << stream << " value:&" << param << "];";
873 }
874 else
875 {
876 out << nl << "[" << name << " readRetained:" << stream << " value:&" << param << "];";
877 }
878 }
879 else
880 {
881 if(autoreleased)
882 {
883 out << nl << param << " = [" << name << " read:" << stream << "];";
884 }
885 else
886 {
887 out << nl << param << " = [" << name << " readRetained:" << stream << "];";
888 }
889 }
890 }
891 }
892
893 void
writeOptMemberMarshalUnmarshalCode(Output & out,const TypePtr & type,const string & param,bool marshal) const894 Slice::ObjCGenerator::writeOptMemberMarshalUnmarshalCode(Output &out, const TypePtr& type, const string& param,
895 bool marshal) const
896 {
897 string stream = marshal ? "ostr" : "istr";
898 string optionalHelper;
899 string helper;
900
901 BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
902 if(builtin)
903 {
904 if(builtin->kind() == Builtin::KindObjectProxy)
905 {
906 optionalHelper = "ICEVarLengthOptionalHelper";
907 helper = "[ICEProxyHelper class]";
908 }
909 else
910 {
911 writeMarshalUnmarshalCode(out, type, param, marshal, false);
912 return;
913 }
914 }
915
916 ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
917 if(cl)
918 {
919 writeMarshalUnmarshalCode(out, type, param, marshal, false);
920 return;
921 }
922
923 EnumPtr en = EnumPtr::dynamicCast(type);
924 if(en)
925 {
926 writeMarshalUnmarshalCode(out, type, param, marshal, false);
927 return;
928 }
929
930 ProxyPtr prx = ProxyPtr::dynamicCast(type);
931 if(prx)
932 {
933 optionalHelper = "ICEVarLengthOptionalHelper";
934 helper = "objc_getClass(\"" + moduleName(findModule(prx->_class())) + prx->_class()->name() + "PrxHelper\")";
935 }
936
937 StructPtr st = StructPtr::dynamicCast(type);
938 if(st)
939 {
940 if(st->isVariableLength())
941 {
942 optionalHelper = "ICEVarLengthOptionalHelper";
943 }
944 else
945 {
946 optionalHelper = "ICEFixedLengthOptionalHelper";
947 }
948 helper = "[" + typeToString(st) + "Helper class]";
949 }
950
951 SequencePtr seq = SequencePtr::dynamicCast(type);
952 if(seq)
953 {
954 TypePtr element = seq->type();
955 if(element->isVariableLength())
956 {
957 optionalHelper = "ICEVarLengthOptionalHelper";
958 }
959 else if(element->minWireSize() == 1)
960 {
961 writeMarshalUnmarshalCode(out, type, param, marshal, false);
962 return;
963 }
964 else
965 {
966 optionalHelper = "ICEFixedSequenceOptionalHelper";
967 }
968 helper = "[" + moduleName(findModule(seq)) + seq->name() + "Helper class]";
969 }
970
971 DictionaryPtr d = DictionaryPtr::dynamicCast(type);
972 if(d)
973 {
974 if(d->keyType()->isVariableLength() || d->valueType()->isVariableLength())
975 {
976 optionalHelper = "ICEVarLengthOptionalHelper";
977 }
978 else
979 {
980 optionalHelper = "ICEFixedDictionaryOptionalHelper";
981 }
982 helper = "[" + moduleName(findModule(d)) + d->name() + "Helper class]";
983 }
984
985 out << nl;
986 if(marshal)
987 {
988 out << "[" << optionalHelper << " write:" << param << " stream:" << stream << " helper:" << helper << "];";
989 }
990 else
991 {
992 out << param << " = [" << optionalHelper << " readRetained:" << stream << " helper:" << helper << "];";
993 }
994
995 }
996
997 void
writeOptParamMarshalUnmarshalCode(Output & out,const TypePtr & type,const string & param,int tag,bool marshal) const998 Slice::ObjCGenerator::writeOptParamMarshalUnmarshalCode(Output &out, const TypePtr& type, const string& param,
999 int tag, bool marshal) const
1000 {
1001 string helper;
1002 BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
1003 ProxyPtr proxy = ProxyPtr::dynamicCast(type);
1004 if(builtin)
1005 {
1006 helper = "ICE" + getBuiltinName(builtin) + "Helper";
1007 }
1008 else if(proxy)
1009 {
1010 helper = moduleName(findModule(proxy->_class())) + (proxy->_class()->name()) + "PrxHelper";
1011 }
1012 else
1013 {
1014 helper = typeToString(type) + "Helper";
1015 }
1016
1017 ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
1018 if(cl)
1019 {
1020 out << nl;
1021 if(marshal)
1022 {
1023 out << "[" << helper << " writeOptional:" << param << " stream:ostr tag:" << tag << "];";
1024 }
1025 else
1026 {
1027 out << "[" << helper << " readOptional:&" << param << " stream:istr tag:" << tag << "];";
1028 }
1029 return;
1030 }
1031
1032 out << nl;
1033 if(marshal)
1034 {
1035 out << "[" << helper << " writeOptional:" << param << " stream:ostr tag:" << tag << "];";
1036 }
1037 else
1038 {
1039 out << param << " = [" << helper << " readOptional:istr tag:" << tag << "];";
1040 }
1041 }
1042
1043 void
validateMetaData(const UnitPtr & u)1044 Slice::ObjCGenerator::validateMetaData(const UnitPtr& u)
1045 {
1046 MetaDataVisitor visitor;
1047 u->visit(&visitor, true);
1048 }
1049
1050 const string Slice::ObjCGenerator::MetaDataVisitor::_objcPrefix = "objc:";
1051 const string Slice::ObjCGenerator::MetaDataVisitor::_msg = "ignoring invalid metadata";
1052
1053 bool
visitUnitStart(const UnitPtr & p)1054 Slice::ObjCGenerator::MetaDataVisitor::visitUnitStart(const UnitPtr& p)
1055 {
1056 //
1057 // Validate global metadata in the top-level file and all included files.
1058 //
1059 StringList files = p->allFiles();
1060
1061 for(StringList::iterator q = files.begin(); q != files.end(); ++q)
1062 {
1063 string file = *q;
1064 DefinitionContextPtr dc = p->findDefinitionContext(file);
1065 assert(dc);
1066 StringList globalMetaData = dc->getMetaData();
1067 int headerDir = 0;
1068 int dllExport = 0;
1069 for(StringList::const_iterator r = globalMetaData.begin(); r != globalMetaData.end();)
1070 {
1071 string s = *r++;
1072
1073 if(s.find(_objcPrefix) == 0)
1074 {
1075 static const string objcHeaderDirPrefix = "objc:header-dir:";
1076 static const string objcDllExportPrefix = "objc:dll-export:";
1077 if(s.find(objcHeaderDirPrefix) == 0 && s.size() > objcHeaderDirPrefix.size())
1078 {
1079 headerDir++;
1080 if(headerDir > 1)
1081 {
1082 ostringstream ostr;
1083 ostr << "ignoring invalid global metadata `" << s
1084 << "': directive can appear only once per file";
1085 dc->warning(InvalidMetaData, file, -1, ostr.str());
1086 globalMetaData.remove(s);
1087 }
1088 continue;
1089 }
1090 else if(s.find(objcDllExportPrefix) == 0 && s.size() > objcDllExportPrefix.size())
1091 {
1092 dllExport++;
1093 if(dllExport > 1)
1094 {
1095 ostringstream ostr;
1096 ostr << "ignoring invalid global metadata `" << s
1097 << "': directive can appear only once per file";
1098 dc->warning(InvalidMetaData, file, -1, ostr.str());
1099 globalMetaData.remove(s);
1100 }
1101 continue;
1102 }
1103
1104 ostringstream ostr;
1105 ostr << "ignoring invalid global metadata `" << s << "'";
1106 dc->warning(InvalidMetaData, file, -1, ostr.str());
1107
1108 globalMetaData.remove(s);
1109 }
1110 }
1111 dc->setMetaData(globalMetaData);
1112 }
1113
1114 return true;
1115 }
1116
1117 bool
visitModuleStart(const ModulePtr & p)1118 Slice::ObjCGenerator::MetaDataVisitor::visitModuleStart(const ModulePtr& p)
1119 {
1120 validate(p);
1121 return true;
1122 }
1123
1124 void
visitModuleEnd(const ModulePtr &)1125 Slice::ObjCGenerator::MetaDataVisitor::visitModuleEnd(const ModulePtr&)
1126 {
1127 }
1128
1129 void
visitClassDecl(const ClassDeclPtr & p)1130 Slice::ObjCGenerator::MetaDataVisitor::visitClassDecl(const ClassDeclPtr& p)
1131 {
1132 validate(p);
1133 }
1134
1135 bool
visitClassDefStart(const ClassDefPtr & p)1136 Slice::ObjCGenerator::MetaDataVisitor::visitClassDefStart(const ClassDefPtr& p)
1137 {
1138 validate(p);
1139 return true;
1140 }
1141
1142 void
visitClassDefEnd(const ClassDefPtr &)1143 Slice::ObjCGenerator::MetaDataVisitor::visitClassDefEnd(const ClassDefPtr&)
1144 {
1145 }
1146
1147 bool
visitExceptionStart(const ExceptionPtr & p)1148 Slice::ObjCGenerator::MetaDataVisitor::visitExceptionStart(const ExceptionPtr& p)
1149 {
1150 validate(p);
1151 return true;
1152 }
1153
1154 void
visitExceptionEnd(const ExceptionPtr &)1155 Slice::ObjCGenerator::MetaDataVisitor::visitExceptionEnd(const ExceptionPtr&)
1156 {
1157 }
1158
1159 bool
visitStructStart(const StructPtr & p)1160 Slice::ObjCGenerator::MetaDataVisitor::visitStructStart(const StructPtr& p)
1161 {
1162 validate(p);
1163 return true;
1164 }
1165
1166 void
visitStructEnd(const StructPtr &)1167 Slice::ObjCGenerator::MetaDataVisitor::visitStructEnd(const StructPtr&)
1168 {
1169 }
1170
1171 void
visitOperation(const OperationPtr & p)1172 Slice::ObjCGenerator::MetaDataVisitor::visitOperation(const OperationPtr& p)
1173 {
1174 validate(p);
1175 }
1176
1177 void
visitParamDecl(const ParamDeclPtr & p)1178 Slice::ObjCGenerator::MetaDataVisitor::visitParamDecl(const ParamDeclPtr& p)
1179 {
1180 validate(p);
1181 }
1182
1183 void
visitDataMember(const DataMemberPtr & p)1184 Slice::ObjCGenerator::MetaDataVisitor::visitDataMember(const DataMemberPtr& p)
1185 {
1186 validate(p);
1187 }
1188
1189 void
visitSequence(const SequencePtr & p)1190 Slice::ObjCGenerator::MetaDataVisitor::visitSequence(const SequencePtr& p)
1191 {
1192 validate(p);
1193 }
1194
1195 void
visitDictionary(const DictionaryPtr & p)1196 Slice::ObjCGenerator::MetaDataVisitor::visitDictionary(const DictionaryPtr& p)
1197 {
1198 validate(p);
1199 }
1200
1201 void
visitEnum(const EnumPtr & p)1202 Slice::ObjCGenerator::MetaDataVisitor::visitEnum(const EnumPtr& p)
1203 {
1204 validate(p);
1205 }
1206
1207 void
visitConst(const ConstPtr & p)1208 Slice::ObjCGenerator::MetaDataVisitor::visitConst(const ConstPtr& p)
1209 {
1210 validate(p);
1211 }
1212
1213 void
validate(const ContainedPtr & cont)1214 Slice::ObjCGenerator::MetaDataVisitor::validate(const ContainedPtr& cont)
1215 {
1216 ModulePtr m = ModulePtr::dynamicCast(cont);
1217 if(m)
1218 {
1219 bool error = false;
1220 bool foundPrefix = false;
1221
1222 StringList meta = getMetaData(m);
1223 for(StringList::iterator p = meta.begin(); p != meta.end();)
1224 {
1225 string s = *p++;
1226 const string prefix = "objc:prefix:";
1227 string name;
1228 if(s.find(prefix) == 0)
1229 {
1230 foundPrefix = true;
1231 name = trim(s.substr(prefix.size()));
1232 if(name.empty())
1233 {
1234 m->definitionContext()->warning(InvalidMetaData, m->definitionContext()->filename(),
1235 m->line(), _msg + " `" + s + "'");
1236 meta.remove(s);
1237 error = true;
1238 }
1239 else
1240 {
1241 if(!addModule(m, name))
1242 {
1243 modulePrefixError(m, s);
1244 }
1245 }
1246 }
1247 else
1248 {
1249 m->definitionContext()->warning(InvalidMetaData, m->definitionContext()->filename(),
1250 m->line(), _msg + " `" + s + "'");
1251 meta.remove(s);
1252 error = true;
1253 }
1254 }
1255 setMetaData(m, meta);
1256
1257 if(!error && !foundPrefix)
1258 {
1259 StringList names = splitScopedName(m->scoped());
1260 string name;
1261 for(StringList::const_iterator i = names.begin(); i != names.end(); ++i)
1262 {
1263 name += *i;
1264 }
1265 if(!addModule(m, name))
1266 {
1267 modulePrefixError(m, "");
1268 }
1269 }
1270 }
1271
1272 EnumPtr en = EnumPtr::dynamicCast(cont);
1273 if(en)
1274 {
1275 StringList meta = getMetaData(en);
1276 for(StringList::iterator p = meta.begin(); p != meta.end();)
1277 {
1278 string s = *p;
1279 if(s != "objc:scoped")
1280 {
1281 en->definitionContext()->warning(InvalidMetaData, en->definitionContext()->filename(),
1282 en->line(), _msg + " `" + s + "'");
1283 meta.erase(p++);
1284 }
1285 else
1286 {
1287 ++p;
1288 }
1289 }
1290 setMetaData(en, meta);
1291 }
1292 }
1293
1294 StringList
getMetaData(const ContainedPtr & cont)1295 Slice::ObjCGenerator::MetaDataVisitor::getMetaData(const ContainedPtr& cont)
1296 {
1297 StringList localMetaData = cont->getMetaData();
1298 for(StringList::const_iterator p = localMetaData.begin(); p != localMetaData.end();)
1299 {
1300 string s = *p++;
1301 if(s.find(_objcPrefix) != 0)
1302 {
1303 localMetaData.remove(s);
1304 }
1305 }
1306 return localMetaData;
1307 }
1308
1309 void
setMetaData(const ContainedPtr & cont,const StringList & metadata)1310 Slice::ObjCGenerator::MetaDataVisitor::setMetaData(const ContainedPtr& cont, const StringList& metadata)
1311 {
1312 StringList localMetaData = cont->getMetaData();
1313 for(StringList::const_iterator p = localMetaData.begin(); p != localMetaData.end();)
1314 {
1315 string s = *p++;
1316 if(s.find(_objcPrefix) == 0)
1317 {
1318 localMetaData.remove(s);
1319 }
1320 }
1321 localMetaData.insert(localMetaData.end(), metadata.begin(), metadata.end());
1322 cont->setMetaData(localMetaData);
1323 }
1324
1325 void
modulePrefixError(const ModulePtr & m,const string & metadata)1326 Slice::ObjCGenerator::MetaDataVisitor::modulePrefixError(const ModulePtr& m, const string& metadata)
1327 {
1328 string file = m->definitionContext()->filename();
1329 string line = m->line();
1330 ModulePrefix mp = modulePrefix(m);
1331 string old_file = mp.m->definitionContext()->filename();
1332 string old_line = mp.m->line();
1333 ostringstream os;
1334 if(!metadata.empty())
1335 {
1336 os << _msg << " `" << metadata << "': ";
1337 }
1338 os << "inconsistent module prefix previously defined ";
1339 if(old_file != file)
1340 {
1341 os << "in " << old_file << ":";
1342 }
1343 else
1344 {
1345 os << "at line ";
1346 }
1347 os << line;
1348 os << " as `" << mp.name << "'" << endl;
1349 m->definitionContext()->warning(All, file, line, os.str());
1350 }
1351