xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/d/dmd/json.c (revision 4c3eb207d36f67d31994830c0a694161fc1ca39b)
1 
2 /* Compiler implementation of the D programming language
3  * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved
4  * written by Walter Bright
5  * http://www.digitalmars.com
6  * Distributed under the Boost Software License, Version 1.0.
7  * http://www.boost.org/LICENSE_1_0.txt
8  * https://github.com/D-Programming-Language/dmd/blob/master/src/json.c
9  */
10 
11 // This implements the JSON capability.
12 
13 #include "root/dsystem.h"
14 #include "root/rmem.h"
15 
16 #include "mars.h"
17 #include "dsymbol.h"
18 #include "template.h"
19 #include "aggregate.h"
20 #include "declaration.h"
21 #include "enum.h"
22 #include "module.h"
23 #include "json.h"
24 #include "mtype.h"
25 #include "attrib.h"
26 #include "cond.h"
27 #include "init.h"
28 #include "import.h"
29 #include "id.h"
30 #include "hdrgen.h"
31 
32 class ToJsonVisitor : public Visitor
33 {
34 public:
35     OutBuffer *buf;
36     int indentLevel;
37     const char *filename;
38 
ToJsonVisitor(OutBuffer * buf)39     ToJsonVisitor(OutBuffer *buf)
40         : buf(buf), indentLevel(0), filename(NULL)
41     {
42     }
43 
indent()44     void indent()
45     {
46         if (buf->offset >= 1 &&
47             buf->data[buf->offset - 1] == '\n')
48             for (int i = 0; i < indentLevel; i++)
49                 buf->writeByte(' ');
50     }
51 
removeComma()52     void removeComma()
53     {
54         if (buf->offset >= 2 &&
55             buf->data[buf->offset - 2] == ',' &&
56             (buf->data[buf->offset - 1] == '\n' || buf->data[buf->offset - 1] == ' '))
57             buf->offset -= 2;
58     }
59 
comma()60     void comma()
61     {
62         if (indentLevel > 0)
63             buf->writestring(",\n");
64     }
65 
stringStart()66     void stringStart()
67     {
68         buf->writeByte('\"');
69     }
70 
stringEnd()71     void stringEnd()
72     {
73         buf->writeByte('\"');
74     }
75 
stringPart(const char * s)76     void stringPart(const char *s)
77     {
78         for (; *s; s++)
79         {
80             utf8_t c = (utf8_t) *s;
81             switch (c)
82             {
83                 case '\n':
84                     buf->writestring("\\n");
85                     break;
86 
87                 case '\r':
88                     buf->writestring("\\r");
89                     break;
90 
91                 case '\t':
92                     buf->writestring("\\t");
93                     break;
94 
95                 case '\"':
96                     buf->writestring("\\\"");
97                     break;
98 
99                 case '\\':
100                     buf->writestring("\\\\");
101                     break;
102 
103                 case '\b':
104                     buf->writestring("\\b");
105                     break;
106 
107                 case '\f':
108                     buf->writestring("\\f");
109                     break;
110 
111                 default:
112                     if (c < 0x20)
113                         buf->printf("\\u%04x", c);
114                     else
115                     {
116                         // Note that UTF-8 chars pass through here just fine
117                         buf->writeByte(c);
118                     }
119                     break;
120             }
121         }
122     }
123 
124     // Json value functions
125 
126     /*********************************
127      * Encode string into buf, and wrap it in double quotes.
128      */
value(const char * s)129     void value(const char *s)
130     {
131         stringStart();
132         stringPart(s);
133         stringEnd();
134     }
135 
value(int value)136     void value(int value)
137     {
138         buf->printf("%d", value);
139     }
140 
valueBool(bool value)141     void valueBool(bool value)
142     {
143         buf->writestring(value ? "true" : "false");
144     }
145 
146     /*********************************
147      * Item is an intented value and a comma, for use in arrays
148      */
item(const char * s)149     void item(const char *s)
150     {
151         indent();
152         value(s);
153         comma();
154     }
155 
item(int i)156     void item(int i)
157     {
158         indent();
159         value(i);
160         comma();
161     }
162 
itemBool(bool b)163     void itemBool(bool b)
164     {
165         indent();
166         valueBool(b);
167         comma();
168     }
169 
170 
171     // Json array functions
172 
arrayStart()173     void arrayStart()
174     {
175         indent();
176         buf->writestring("[\n");
177         indentLevel++;
178     }
179 
arrayEnd()180     void arrayEnd()
181     {
182         indentLevel--;
183         removeComma();
184         if (buf->offset >= 2 &&
185             buf->data[buf->offset - 2] == '[' &&
186             buf->data[buf->offset - 1] == '\n')
187             buf->offset -= 1;
188         else if (!(buf->offset >= 1 &&
189             buf->data[buf->offset - 1] == '['))
190         {
191             buf->writestring("\n");
192             indent();
193         }
194         buf->writestring("]");
195         comma();
196     }
197 
198 
199     // Json object functions
200 
objectStart()201     void objectStart()
202     {
203         indent();
204         buf->writestring("{\n");
205         indentLevel++;
206     }
207 
objectEnd()208     void objectEnd()
209     {
210         indentLevel--;
211         removeComma();
212         if (buf->offset >= 2 &&
213             buf->data[buf->offset - 2] == '{' &&
214             buf->data[buf->offset - 1] == '\n')
215             buf->offset -= 1;
216         else
217         {
218             buf->writestring("\n");
219             indent();
220         }
221         buf->writestring("}");
222         comma();
223     }
224 
225     // Json object property functions
226 
propertyStart(const char * name)227     void propertyStart(const char *name)
228     {
229         indent();
230         value(name);
231         buf->writestring(" : ");
232     }
233 
property(const char * name,const char * s)234     void property(const char *name, const char *s)
235     {
236         if (s == NULL) return;
237 
238         propertyStart(name);
239         value(s);
240         comma();
241     }
242 
property(const char * name,int i)243     void property(const char *name, int i)
244     {
245         propertyStart(name);
246         value(i);
247         comma();
248     }
249 
propertyBool(const char * name,bool b)250     void propertyBool(const char *name, bool b)
251     {
252         propertyStart(name);
253         valueBool(b);
254         comma();
255     }
256 
257 
property(const char * name,TRUST trust)258     void property(const char *name, TRUST trust)
259     {
260         switch (trust)
261         {
262             case TRUSTdefault:
263                 // Should not be printed
264                 //property(name, "default");
265                 break;
266             case TRUSTsystem:
267                 property(name, "system");
268                 break;
269             case TRUSTtrusted:
270                 property(name, "trusted");
271                 break;
272             case TRUSTsafe:
273                 property(name, "safe");
274                 break;
275             default:
276                 assert(false);
277         }
278     }
279 
property(const char * name,PURE purity)280     void property(const char *name, PURE purity)
281     {
282         switch (purity)
283         {
284             case PUREimpure:
285                 // Should not be printed
286                 //property(name, "impure");
287                 break;
288             case PUREweak:
289                 property(name, "weak");
290                 break;
291             case PUREconst:
292                 property(name, "const");
293                 break;
294             case PUREstrong:
295                 property(name, "strong");
296                 break;
297             case PUREfwdref:
298                 property(name, "fwdref");
299                 break;
300             default:
301                 assert(false);
302         }
303     }
304 
property(const char * name,LINK linkage)305     void property(const char *name, LINK linkage)
306     {
307         switch (linkage)
308         {
309             case LINKdefault:
310                 // Should not be printed
311                 //property(name, "default");
312                 break;
313             case LINKd:
314                 // Should not be printed
315                 //property(name, "d");
316                 break;
317             case LINKc:
318                 property(name, "c");
319                 break;
320             case LINKcpp:
321                 property(name, "cpp");
322                 break;
323             case LINKwindows:
324                 property(name, "windows");
325                 break;
326             case LINKpascal:
327                 property(name, "pascal");
328                 break;
329             default:
330                 assert(false);
331         }
332     }
333 
propertyStorageClass(const char * name,StorageClass stc)334     void propertyStorageClass(const char *name, StorageClass stc)
335     {
336         stc &= STCStorageClass;
337         if (stc)
338         {
339             propertyStart(name);
340             arrayStart();
341 
342             while (stc)
343             {
344                 const char *p = stcToChars(stc);
345                 assert(p);
346                 item(p);
347             }
348 
349             arrayEnd();
350         }
351     }
352 
property(const char * linename,const char * charname,Loc * loc)353     void property(const char *linename, const char *charname, Loc *loc)
354     {
355         if (loc)
356         {
357             const char *filename = loc->filename;
358             if (filename)
359             {
360                 if (!this->filename || strcmp(filename, this->filename))
361                 {
362                     this->filename = filename;
363                     property("file", filename);
364                 }
365             }
366 
367             if (loc->linnum)
368             {
369                 property(linename, loc->linnum);
370                 if (loc->charnum)
371                     property(charname, loc->charnum);
372             }
373         }
374     }
375 
property(const char * name,Type * type)376     void property(const char *name, Type *type)
377     {
378         if (type)
379         {
380             property(name, type->toChars());
381         }
382     }
383 
property(const char * name,const char * deconame,Type * type)384     void property(const char *name, const char *deconame, Type *type)
385     {
386         if (type)
387         {
388             if (type->deco)
389                 property(deconame, type->deco);
390             else
391                 property(name, type->toChars());
392         }
393     }
394 
property(const char * name,Parameters * parameters)395     void property(const char *name, Parameters *parameters)
396     {
397         if (parameters == NULL || parameters->dim == 0)
398             return;
399 
400         propertyStart(name);
401         arrayStart();
402 
403         if (parameters)
404         {
405             for (size_t i = 0; i < parameters->dim; i++)
406             {
407                 Parameter *p = (*parameters)[i];
408                 objectStart();
409 
410                 if (p->ident)
411                     property("name", p->ident->toChars());
412 
413                 property("type", "deco", p->type);
414 
415                 propertyStorageClass("storageClass", p->storageClass);
416 
417                 if (p->defaultArg)
418                     property("default", p->defaultArg->toChars());
419 
420 
421                 objectEnd();
422             }
423         }
424 
425         arrayEnd();
426     }
427 
428     /* ========================================================================== */
429 
jsonProperties(Dsymbol * s)430     void jsonProperties(Dsymbol *s)
431     {
432         if (s->isModule())
433             return;
434 
435         if (!s->isTemplateDeclaration()) // TemplateDeclaration::kind() acts weird sometimes
436         {
437             property("name", s->toChars());
438             property("kind", s->kind());
439         }
440 
441         if (s->prot().kind != PROTpublic)   // TODO: How about package(names)?
442             property("protection", protectionToChars(s->prot().kind));
443 
444         if (EnumMember *em = s->isEnumMember())
445         {
446             if (em->origValue)
447                 property("value", em->origValue->toChars());
448         }
449 
450         property("comment", (const char *)s->comment);
451 
452         property("line", "char", &s->loc);
453     }
454 
jsonProperties(Declaration * d)455     void jsonProperties(Declaration *d)
456     {
457         if (d->storage_class & STClocal)
458             return;
459         jsonProperties((Dsymbol *)d);
460 
461         propertyStorageClass("storageClass", d->storage_class);
462 
463         property("type", "deco", d->type);
464 
465         // Emit originalType if it differs from type
466         if (d->type != d->originalType && d->originalType)
467         {
468             const char *ostr = d->originalType->toChars();
469             if (d->type)
470             {
471                 const char *tstr = d->type->toChars();
472                 if (strcmp(tstr, ostr))
473                 {
474                     //printf("tstr = %s, ostr = %s\n", tstr, ostr);
475                     property("originalType", ostr);
476                 }
477             }
478             else
479                 property("originalType", ostr);
480         }
481     }
482 
jsonProperties(TemplateDeclaration * td)483     void jsonProperties(TemplateDeclaration *td)
484     {
485         jsonProperties((Dsymbol *)td);
486 
487         if (td->onemember && td->onemember->isCtorDeclaration())
488             property("name", "this");  // __ctor -> this
489         else
490             property("name", td->ident->toChars());  // Foo(T) -> Foo
491     }
492 
493     /* ========================================================================== */
494 
visit(Dsymbol *)495     void visit(Dsymbol *)
496     {
497     }
498 
visit(Module * s)499     void visit(Module *s)
500     {
501         objectStart();
502 
503         if (s->md)
504             property("name", s->md->toChars());
505 
506         property("kind", s->kind());
507 
508         filename = s->srcfile->toChars();
509         property("file", filename);
510 
511         property("comment", (const char *)s->comment);
512 
513         propertyStart("members");
514         arrayStart();
515         for (size_t i = 0; i < s->members->dim; i++)
516         {
517             (*s->members)[i]->accept(this);
518         }
519         arrayEnd();
520 
521         objectEnd();
522     }
523 
visit(Import * s)524     void visit(Import *s)
525     {
526         if (s->id == Id::object)
527             return;
528 
529         objectStart();
530 
531         propertyStart("name");
532         stringStart();
533         if (s->packages && s->packages->dim)
534         {
535             for (size_t i = 0; i < s->packages->dim; i++)
536             {
537                 Identifier *pid = (*s->packages)[i];
538                 stringPart(pid->toChars());
539                 buf->writeByte('.');
540             }
541         }
542         stringPart(s->id->toChars());
543         stringEnd();
544         comma();
545 
546         property("kind", s->kind());
547         property("comment", (const char *)s->comment);
548         property("line", "char", &s->loc);
549         if (s->prot().kind != PROTpublic)
550             property("protection", protectionToChars(s->prot().kind));
551         if (s->aliasId)
552             property("alias", s->aliasId->toChars());
553 
554         bool hasRenamed = false;
555         bool hasSelective = false;
556         for (size_t i = 0; i < s->aliases.dim; i++)
557         {
558             // avoid empty "renamed" and "selective" sections
559             if (hasRenamed && hasSelective)
560                 break;
561             else if (s->aliases[i])
562                 hasRenamed = true;
563             else
564                 hasSelective = true;
565         }
566 
567         if (hasRenamed)
568         {
569             // import foo : alias1 = target1;
570             propertyStart("renamed");
571             objectStart();
572             for (size_t i = 0; i < s->aliases.dim; i++)
573             {
574                 Identifier *name = s->names[i];
575                 Identifier *alias = s->aliases[i];
576                 if (alias) property(alias->toChars(), name->toChars());
577             }
578             objectEnd();
579         }
580 
581         if (hasSelective)
582         {
583             // import foo : target1;
584             propertyStart("selective");
585             arrayStart();
586             for (size_t i = 0; i < s->names.dim; i++)
587             {
588                 Identifier *name = s->names[i];
589                 if (!s->aliases[i]) item(name->toChars());
590             }
591             arrayEnd();
592         }
593 
594         objectEnd();
595     }
596 
visit(AttribDeclaration * d)597     void visit(AttribDeclaration *d)
598     {
599         Dsymbols *ds = d->include(NULL, NULL);
600 
601         if (ds)
602         {
603             for (size_t i = 0; i < ds->dim; i++)
604             {
605                 Dsymbol *s = (*ds)[i];
606                 s->accept(this);
607             }
608         }
609     }
610 
visit(ConditionalDeclaration * d)611     void visit(ConditionalDeclaration *d)
612     {
613         if (d->condition->inc)
614         {
615             visit((AttribDeclaration *)d);
616         }
617     }
618 
visit(TypeInfoDeclaration *)619     void visit(TypeInfoDeclaration *) {}
visit(PostBlitDeclaration *)620     void visit(PostBlitDeclaration *) {}
621 
visit(Declaration * d)622     void visit(Declaration *d)
623     {
624         objectStart();
625 
626         //property("unknown", "declaration");
627 
628         jsonProperties(d);
629 
630         objectEnd();
631     }
632 
visit(AggregateDeclaration * d)633     void visit(AggregateDeclaration *d)
634     {
635         objectStart();
636 
637         jsonProperties(d);
638 
639         ClassDeclaration *cd = d->isClassDeclaration();
640         if (cd)
641         {
642             if (cd->baseClass && cd->baseClass->ident != Id::Object)
643             {
644                 property("base", cd->baseClass->toPrettyChars(true));
645             }
646             if (cd->interfaces.length)
647             {
648                 propertyStart("interfaces");
649                 arrayStart();
650                 for (size_t i = 0; i < cd->interfaces.length; i++)
651                 {
652                     BaseClass *b = cd->interfaces.ptr[i];
653                     item(b->sym->toPrettyChars(true));
654                 }
655                 arrayEnd();
656             }
657         }
658 
659         if (d->members)
660         {
661             propertyStart("members");
662             arrayStart();
663             for (size_t i = 0; i < d->members->dim; i++)
664             {
665                 Dsymbol *s = (*d->members)[i];
666                 s->accept(this);
667             }
668             arrayEnd();
669         }
670 
671         objectEnd();
672     }
673 
visit(FuncDeclaration * d)674     void visit(FuncDeclaration *d)
675     {
676         objectStart();
677 
678         jsonProperties(d);
679 
680         TypeFunction *tf = (TypeFunction *)d->type;
681         if (tf && tf->ty == Tfunction)
682             property("parameters", tf->parameters);
683 
684         property("endline", "endchar", &d->endloc);
685 
686         if (d->foverrides.dim)
687         {
688             propertyStart("overrides");
689             arrayStart();
690             for (size_t i = 0; i < d->foverrides.dim; i++)
691             {
692                 FuncDeclaration *fd = d->foverrides[i];
693                 item(fd->toPrettyChars());
694             }
695             arrayEnd();
696         }
697 
698         if (d->fdrequire)
699         {
700             propertyStart("in");
701             d->fdrequire->accept(this);
702         }
703 
704         if (d->fdensure)
705         {
706             propertyStart("out");
707             d->fdensure->accept(this);
708         }
709 
710         objectEnd();
711     }
712 
visit(TemplateDeclaration * d)713     void visit(TemplateDeclaration *d)
714     {
715         objectStart();
716 
717         // TemplateDeclaration::kind returns the kind of its Aggregate onemember, if it is one
718         property("kind", "template");
719 
720         jsonProperties(d);
721 
722         propertyStart("parameters");
723         arrayStart();
724         for (size_t i = 0; i < d->parameters->dim; i++)
725         {
726             TemplateParameter *s = (*d->parameters)[i];
727             objectStart();
728 
729             property("name", s->ident->toChars());
730 
731             TemplateTypeParameter *type = s->isTemplateTypeParameter();
732             if (type)
733             {
734                 if (s->isTemplateThisParameter())
735                     property("kind", "this");
736                 else
737                     property("kind", "type");
738                 property("type", "deco", type->specType);
739 
740                 property("default", "defaultDeco", type->defaultType);
741             }
742 
743             TemplateValueParameter *value = s->isTemplateValueParameter();
744             if (value)
745             {
746                 property("kind", "value");
747 
748                 property("type", "deco", value->valType);
749 
750                 if (value->specValue)
751                     property("specValue", value->specValue->toChars());
752 
753                 if (value->defaultValue)
754                     property("defaultValue", value->defaultValue->toChars());
755             }
756 
757             TemplateAliasParameter *alias = s->isTemplateAliasParameter();
758             if (alias)
759             {
760                 property("kind", "alias");
761 
762                 property("type", "deco", alias->specType);
763 
764                 if (alias->specAlias)
765                     property("specAlias", alias->specAlias->toChars());
766 
767                 if (alias->defaultAlias)
768                     property("defaultAlias", alias->defaultAlias->toChars());
769             }
770 
771             TemplateTupleParameter *tuple = s->isTemplateTupleParameter();
772             if (tuple)
773             {
774                 property("kind", "tuple");
775             }
776 
777             objectEnd();
778         }
779         arrayEnd();
780 
781         Expression *expression = d->constraint;
782         if (expression)
783         {
784             property("constraint", expression->toChars());
785         }
786 
787         propertyStart("members");
788         arrayStart();
789         for (size_t i = 0; i < d->members->dim; i++)
790         {
791             Dsymbol *s = (*d->members)[i];
792             s->accept(this);
793         }
794         arrayEnd();
795 
796         objectEnd();
797     }
798 
visit(EnumDeclaration * d)799     void visit(EnumDeclaration *d)
800     {
801         if (d->isAnonymous())
802         {
803             if (d->members)
804             {
805                 for (size_t i = 0; i < d->members->dim; i++)
806                 {
807                     Dsymbol *s = (*d->members)[i];
808                     s->accept(this);
809                 }
810             }
811             return;
812         }
813 
814         objectStart();
815 
816         jsonProperties(d);
817 
818         property("base", "baseDeco", d->memtype);
819 
820         if (d->members)
821         {
822             propertyStart("members");
823             arrayStart();
824             for (size_t i = 0; i < d->members->dim; i++)
825             {
826                 Dsymbol *s = (*d->members)[i];
827                 s->accept(this);
828             }
829             arrayEnd();
830         }
831 
832         objectEnd();
833     }
834 
visit(EnumMember * s)835     void visit(EnumMember *s)
836     {
837         objectStart();
838 
839         jsonProperties((Dsymbol*)s);
840 
841         property("type", "deco", s->origType);
842 
843         objectEnd();
844     }
845 
visit(VarDeclaration * d)846     void visit(VarDeclaration *d)
847     {
848         if (d->storage_class & STClocal)
849             return;
850         objectStart();
851 
852         jsonProperties(d);
853 
854         if (d->_init)
855             property("init", d->_init->toChars());
856 
857         if (d->isField())
858             property("offset", d->offset);
859 
860         if (d->alignment && d->alignment != STRUCTALIGN_DEFAULT)
861             property("align", d->alignment);
862 
863         objectEnd();
864     }
865 
visit(TemplateMixin * d)866     void visit(TemplateMixin *d)
867     {
868         objectStart();
869 
870         jsonProperties(d);
871 
872         objectEnd();
873     }
874 };
875 
876 
json_generate(OutBuffer * buf,Modules * modules)877 void json_generate(OutBuffer *buf, Modules *modules)
878 {
879     ToJsonVisitor json(buf);
880 
881     json.arrayStart();
882     for (size_t i = 0; i < modules->dim; i++)
883     {
884         Module *m = (*modules)[i];
885         if (global.params.verbose)
886             message("json gen %s", m->toChars());
887         m->accept(&json);
888     }
889     json.arrayEnd();
890     json.removeComma();
891 }
892