xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/d/dmd/json.c (revision 82d56013d7b633d116a93943de88e08335357a7c)
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 
39     ToJsonVisitor(OutBuffer *buf)
40         : buf(buf), indentLevel(0), filename(NULL)
41     {
42     }
43 
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 
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 
60     void comma()
61     {
62         if (indentLevel > 0)
63             buf->writestring(",\n");
64     }
65 
66     void stringStart()
67     {
68         buf->writeByte('\"');
69     }
70 
71     void stringEnd()
72     {
73         buf->writeByte('\"');
74     }
75 
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      */
129     void value(const char *s)
130     {
131         stringStart();
132         stringPart(s);
133         stringEnd();
134     }
135 
136     void value(int value)
137     {
138         buf->printf("%d", value);
139     }
140 
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      */
149     void item(const char *s)
150     {
151         indent();
152         value(s);
153         comma();
154     }
155 
156     void item(int i)
157     {
158         indent();
159         value(i);
160         comma();
161     }
162 
163     void itemBool(bool b)
164     {
165         indent();
166         valueBool(b);
167         comma();
168     }
169 
170 
171     // Json array functions
172 
173     void arrayStart()
174     {
175         indent();
176         buf->writestring("[\n");
177         indentLevel++;
178     }
179 
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 
201     void objectStart()
202     {
203         indent();
204         buf->writestring("{\n");
205         indentLevel++;
206     }
207 
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 
227     void propertyStart(const char *name)
228     {
229         indent();
230         value(name);
231         buf->writestring(" : ");
232     }
233 
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 
243     void property(const char *name, int i)
244     {
245         propertyStart(name);
246         value(i);
247         comma();
248     }
249 
250     void propertyBool(const char *name, bool b)
251     {
252         propertyStart(name);
253         valueBool(b);
254         comma();
255     }
256 
257 
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 
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 
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 
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 
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 
376     void property(const char *name, Type *type)
377     {
378         if (type)
379         {
380             property(name, type->toChars());
381         }
382     }
383 
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 
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 
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 
455     void jsonProperties(Declaration *d)
456     {
457         jsonProperties((Dsymbol *)d);
458 
459         propertyStorageClass("storageClass", d->storage_class);
460 
461         property("type", "deco", d->type);
462 
463         // Emit originalType if it differs from type
464         if (d->type != d->originalType && d->originalType)
465         {
466             const char *ostr = d->originalType->toChars();
467             if (d->type)
468             {
469                 const char *tstr = d->type->toChars();
470                 if (strcmp(tstr, ostr))
471                 {
472                     //printf("tstr = %s, ostr = %s\n", tstr, ostr);
473                     property("originalType", ostr);
474                 }
475             }
476             else
477                 property("originalType", ostr);
478         }
479     }
480 
481     void jsonProperties(TemplateDeclaration *td)
482     {
483         jsonProperties((Dsymbol *)td);
484 
485         if (td->onemember && td->onemember->isCtorDeclaration())
486             property("name", "this");  // __ctor -> this
487         else
488             property("name", td->ident->toChars());  // Foo(T) -> Foo
489     }
490 
491     /* ========================================================================== */
492 
493     void visit(Dsymbol *)
494     {
495     }
496 
497     void visit(Module *s)
498     {
499         objectStart();
500 
501         if (s->md)
502             property("name", s->md->toChars());
503 
504         property("kind", s->kind());
505 
506         filename = s->srcfile->toChars();
507         property("file", filename);
508 
509         property("comment", (const char *)s->comment);
510 
511         propertyStart("members");
512         arrayStart();
513         for (size_t i = 0; i < s->members->dim; i++)
514         {
515             (*s->members)[i]->accept(this);
516         }
517         arrayEnd();
518 
519         objectEnd();
520     }
521 
522     void visit(Import *s)
523     {
524         if (s->id == Id::object)
525             return;
526 
527         objectStart();
528 
529         propertyStart("name");
530         stringStart();
531         if (s->packages && s->packages->dim)
532         {
533             for (size_t i = 0; i < s->packages->dim; i++)
534             {
535                 Identifier *pid = (*s->packages)[i];
536                 stringPart(pid->toChars());
537                 buf->writeByte('.');
538             }
539         }
540         stringPart(s->id->toChars());
541         stringEnd();
542         comma();
543 
544         property("kind", s->kind());
545         property("comment", (const char *)s->comment);
546         property("line", "char", &s->loc);
547         if (s->prot().kind != PROTpublic)
548             property("protection", protectionToChars(s->prot().kind));
549         if (s->aliasId)
550             property("alias", s->aliasId->toChars());
551 
552         bool hasRenamed = false;
553         bool hasSelective = false;
554         for (size_t i = 0; i < s->aliases.dim; i++)
555         {
556             // avoid empty "renamed" and "selective" sections
557             if (hasRenamed && hasSelective)
558                 break;
559             else if (s->aliases[i])
560                 hasRenamed = true;
561             else
562                 hasSelective = true;
563         }
564 
565         if (hasRenamed)
566         {
567             // import foo : alias1 = target1;
568             propertyStart("renamed");
569             objectStart();
570             for (size_t i = 0; i < s->aliases.dim; i++)
571             {
572                 Identifier *name = s->names[i];
573                 Identifier *alias = s->aliases[i];
574                 if (alias) property(alias->toChars(), name->toChars());
575             }
576             objectEnd();
577         }
578 
579         if (hasSelective)
580         {
581             // import foo : target1;
582             propertyStart("selective");
583             arrayStart();
584             for (size_t i = 0; i < s->names.dim; i++)
585             {
586                 Identifier *name = s->names[i];
587                 if (!s->aliases[i]) item(name->toChars());
588             }
589             arrayEnd();
590         }
591 
592         objectEnd();
593     }
594 
595     void visit(AttribDeclaration *d)
596     {
597         Dsymbols *ds = d->include(NULL, NULL);
598 
599         if (ds)
600         {
601             for (size_t i = 0; i < ds->dim; i++)
602             {
603                 Dsymbol *s = (*ds)[i];
604                 s->accept(this);
605             }
606         }
607     }
608 
609     void visit(ConditionalDeclaration *d)
610     {
611         if (d->condition->inc)
612         {
613             visit((AttribDeclaration *)d);
614         }
615     }
616 
617     void visit(TypeInfoDeclaration *) {}
618     void visit(PostBlitDeclaration *) {}
619 
620     void visit(Declaration *d)
621     {
622         objectStart();
623 
624         //property("unknown", "declaration");
625 
626         jsonProperties(d);
627 
628         objectEnd();
629     }
630 
631     void visit(AggregateDeclaration *d)
632     {
633         objectStart();
634 
635         jsonProperties(d);
636 
637         ClassDeclaration *cd = d->isClassDeclaration();
638         if (cd)
639         {
640             if (cd->baseClass && cd->baseClass->ident != Id::Object)
641             {
642                 property("base", cd->baseClass->toPrettyChars(true));
643             }
644             if (cd->interfaces.length)
645             {
646                 propertyStart("interfaces");
647                 arrayStart();
648                 for (size_t i = 0; i < cd->interfaces.length; i++)
649                 {
650                     BaseClass *b = cd->interfaces.ptr[i];
651                     item(b->sym->toPrettyChars(true));
652                 }
653                 arrayEnd();
654             }
655         }
656 
657         if (d->members)
658         {
659             propertyStart("members");
660             arrayStart();
661             for (size_t i = 0; i < d->members->dim; i++)
662             {
663                 Dsymbol *s = (*d->members)[i];
664                 s->accept(this);
665             }
666             arrayEnd();
667         }
668 
669         objectEnd();
670     }
671 
672     void visit(FuncDeclaration *d)
673     {
674         objectStart();
675 
676         jsonProperties(d);
677 
678         TypeFunction *tf = (TypeFunction *)d->type;
679         if (tf && tf->ty == Tfunction)
680             property("parameters", tf->parameters);
681 
682         property("endline", "endchar", &d->endloc);
683 
684         if (d->foverrides.dim)
685         {
686             propertyStart("overrides");
687             arrayStart();
688             for (size_t i = 0; i < d->foverrides.dim; i++)
689             {
690                 FuncDeclaration *fd = d->foverrides[i];
691                 item(fd->toPrettyChars());
692             }
693             arrayEnd();
694         }
695 
696         if (d->fdrequire)
697         {
698             propertyStart("in");
699             d->fdrequire->accept(this);
700         }
701 
702         if (d->fdensure)
703         {
704             propertyStart("out");
705             d->fdensure->accept(this);
706         }
707 
708         objectEnd();
709     }
710 
711     void visit(TemplateDeclaration *d)
712     {
713         objectStart();
714 
715         // TemplateDeclaration::kind returns the kind of its Aggregate onemember, if it is one
716         property("kind", "template");
717 
718         jsonProperties(d);
719 
720         propertyStart("parameters");
721         arrayStart();
722         for (size_t i = 0; i < d->parameters->dim; i++)
723         {
724             TemplateParameter *s = (*d->parameters)[i];
725             objectStart();
726 
727             property("name", s->ident->toChars());
728 
729             TemplateTypeParameter *type = s->isTemplateTypeParameter();
730             if (type)
731             {
732                 if (s->isTemplateThisParameter())
733                     property("kind", "this");
734                 else
735                     property("kind", "type");
736                 property("type", "deco", type->specType);
737 
738                 property("default", "defaultDeco", type->defaultType);
739             }
740 
741             TemplateValueParameter *value = s->isTemplateValueParameter();
742             if (value)
743             {
744                 property("kind", "value");
745 
746                 property("type", "deco", value->valType);
747 
748                 if (value->specValue)
749                     property("specValue", value->specValue->toChars());
750 
751                 if (value->defaultValue)
752                     property("defaultValue", value->defaultValue->toChars());
753             }
754 
755             TemplateAliasParameter *alias = s->isTemplateAliasParameter();
756             if (alias)
757             {
758                 property("kind", "alias");
759 
760                 property("type", "deco", alias->specType);
761 
762                 if (alias->specAlias)
763                     property("specAlias", alias->specAlias->toChars());
764 
765                 if (alias->defaultAlias)
766                     property("defaultAlias", alias->defaultAlias->toChars());
767             }
768 
769             TemplateTupleParameter *tuple = s->isTemplateTupleParameter();
770             if (tuple)
771             {
772                 property("kind", "tuple");
773             }
774 
775             objectEnd();
776         }
777         arrayEnd();
778 
779         Expression *expression = d->constraint;
780         if (expression)
781         {
782             property("constraint", expression->toChars());
783         }
784 
785         propertyStart("members");
786         arrayStart();
787         for (size_t i = 0; i < d->members->dim; i++)
788         {
789             Dsymbol *s = (*d->members)[i];
790             s->accept(this);
791         }
792         arrayEnd();
793 
794         objectEnd();
795     }
796 
797     void visit(EnumDeclaration *d)
798     {
799         if (d->isAnonymous())
800         {
801             if (d->members)
802             {
803                 for (size_t i = 0; i < d->members->dim; i++)
804                 {
805                     Dsymbol *s = (*d->members)[i];
806                     s->accept(this);
807                 }
808             }
809             return;
810         }
811 
812         objectStart();
813 
814         jsonProperties(d);
815 
816         property("base", "baseDeco", d->memtype);
817 
818         if (d->members)
819         {
820             propertyStart("members");
821             arrayStart();
822             for (size_t i = 0; i < d->members->dim; i++)
823             {
824                 Dsymbol *s = (*d->members)[i];
825                 s->accept(this);
826             }
827             arrayEnd();
828         }
829 
830         objectEnd();
831     }
832 
833     void visit(EnumMember *s)
834     {
835         objectStart();
836 
837         jsonProperties((Dsymbol*)s);
838 
839         property("type", "deco", s->origType);
840 
841         objectEnd();
842     }
843 
844     void visit(VarDeclaration *d)
845     {
846         objectStart();
847 
848         jsonProperties(d);
849 
850         if (d->_init)
851             property("init", d->_init->toChars());
852 
853         if (d->isField())
854             property("offset", d->offset);
855 
856         if (d->alignment && d->alignment != STRUCTALIGN_DEFAULT)
857             property("align", d->alignment);
858 
859         objectEnd();
860     }
861 
862     void visit(TemplateMixin *d)
863     {
864         objectStart();
865 
866         jsonProperties(d);
867 
868         objectEnd();
869     }
870 };
871 
872 
873 void json_generate(OutBuffer *buf, Modules *modules)
874 {
875     ToJsonVisitor json(buf);
876 
877     json.arrayStart();
878     for (size_t i = 0; i < modules->dim; i++)
879     {
880         Module *m = (*modules)[i];
881         if (global.params.verbose)
882             message("json gen %s", m->toChars());
883         m->accept(&json);
884     }
885     json.arrayEnd();
886     json.removeComma();
887 }
888