1
/**
2
 * Code for generating .json descriptions of the module when passing the `-X` flag to dmd.
3
 *
4
 * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
5
 * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
6
 * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7
 * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/json.d, _json.d)
8
 * Documentation:  https://dlang.org/phobos/dmd_json.html
9
 * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/json.d
10
 */
11

12
module dmd.json;
13

14
import core.stdc.stdio;
15
import core.stdc.string;
16
import dmd.aggregate;
17
import dmd.arraytypes;
18
import dmd.attrib;
19
import dmd.cond;
20
import dmd.dclass;
21
import dmd.declaration;
22
import dmd.denum;
23
import dmd.dimport;
24
import dmd.dmodule;
25
import dmd.dsymbol;
26
import dmd.dtemplate;
27
import dmd.errors;
28
import dmd.expression;
29
import dmd.func;
30
import dmd.globals;
31
import dmd.hdrgen;
32
import dmd.id;
33
import dmd.identifier;
34
import dmd.mtype;
35
import dmd.root.outbuffer;
36
import dmd.root.rootobject;
37
import dmd.root.string;
38
import dmd.visitor;
39

40
version(Windows) {
41
    extern (C) char* getcwd(char* buffer, size_t maxlen);
42
} else {
43
    import core.sys.posix.unistd : getcwd;
44
}
45

46
private extern (C++) final class ToJsonVisitor : Visitor
47
{
48
    alias visit = Visitor.visit;
49
public:
50
    OutBuffer* buf;
51
    int indentLevel;
52
    const(char)[] filename;
53

54 1
    extern (D) this(OutBuffer* buf)
55
    {
56 1
        this.buf = buf;
57
    }
58

59

60
    void indent()
61
    {
62 1
        if (buf.length >= 1 && (*buf)[buf.length - 1] == '\n')
63 1
            for (int i = 0; i < indentLevel; i++)
64 1
                buf.writeByte(' ');
65
    }
66

67
    void removeComma()
68
    {
69 1
        if (buf.length >= 2 && (*buf)[buf.length - 2] == ',' && ((*buf)[buf.length - 1] == '\n' || (*buf)[buf.length - 1] == ' '))
70 1
            buf.setsize(buf.length - 2);
71
    }
72

73
    void comma()
74
    {
75 1
        if (indentLevel > 0)
76 1
            buf.writestring(",\n");
77
    }
78

79
    void stringStart()
80
    {
81 1
        buf.writeByte('\"');
82
    }
83

84
    void stringEnd()
85
    {
86 1
        buf.writeByte('\"');
87
    }
88

89
    extern(D) void stringPart(const char[] s)
90
    {
91 1
        foreach (char c; s)
92
        {
93 1
            switch (c)
94
            {
95 0
            case '\n':
96 0
                buf.writestring("\\n");
97 0
                break;
98 0
            case '\r':
99 0
                buf.writestring("\\r");
100 0
                break;
101 0
            case '\t':
102 0
                buf.writestring("\\t");
103 0
                break;
104 0
            case '\"':
105 0
                buf.writestring("\\\"");
106 0
                break;
107 0
            case '\\':
108 0
                buf.writestring("\\\\");
109 0
                break;
110 0
            case '\b':
111 0
                buf.writestring("\\b");
112 0
                break;
113 0
            case '\f':
114 0
                buf.writestring("\\f");
115 0
                break;
116 1
            default:
117 1
                if (c < 0x20)
118 1
                    buf.printf("\\u%04x", c);
119
                else
120
                {
121
                    // Note that UTF-8 chars pass through here just fine
122 1
                    buf.writeByte(c);
123
                }
124 1
                break;
125
            }
126
        }
127
    }
128

129
    // Json value functions
130
    /*********************************
131
     * Encode string into buf, and wrap it in double quotes.
132
     */
133
    extern(D) void value(const char[] s)
134
    {
135 1
        stringStart();
136 1
        stringPart(s);
137 1
        stringEnd();
138
    }
139

140
    void value(int value)
141
    {
142 1
        if (value < 0)
143
        {
144 0
            buf.writeByte('-');
145 0
            value = -value;
146
        }
147 1
        buf.print(value);
148
    }
149

150
    void valueBool(bool value)
151
    {
152 1
        buf.writestring(value ? "true" : "false");
153
    }
154

155
    /*********************************
156
     * Item is an intented value and a comma, for use in arrays
157
     */
158
    extern(D) void item(const char[] s)
159
    {
160 1
        indent();
161 1
        value(s);
162 1
        comma();
163
    }
164

165
    void item(int i)
166
    {
167 0
        indent();
168 0
        value(i);
169 0
        comma();
170
    }
171

172
    void itemBool(const bool b)
173
    {
174 0
        indent();
175 0
        valueBool(b);
176 0
        comma();
177
    }
178

179
    // Json array functions
180
    void arrayStart()
181
    {
182 1
        indent();
183 1
        buf.writestring("[\n");
184 1
        indentLevel++;
185
    }
186

187
    void arrayEnd()
188
    {
189 1
        indentLevel--;
190 1
        removeComma();
191 1
        if (buf.length >= 2 && (*buf)[buf.length - 2] == '[' && (*buf)[buf.length - 1] == '\n')
192 1
            buf.setsize(buf.length - 1);
193 1
        else if (!(buf.length >= 1 && (*buf)[buf.length - 1] == '['))
194
        {
195 1
            buf.writestring("\n");
196 1
            indent();
197
        }
198 1
        buf.writestring("]");
199 1
        comma();
200
    }
201

202
    // Json object functions
203
    void objectStart()
204
    {
205 1
        indent();
206 1
        buf.writestring("{\n");
207 1
        indentLevel++;
208
    }
209

210
    void objectEnd()
211
    {
212 1
        indentLevel--;
213 1
        removeComma();
214 1
        if (buf.length >= 2 && (*buf)[buf.length - 2] == '{' && (*buf)[buf.length - 1] == '\n')
215 1
            buf.setsize(buf.length - 1);
216
        else
217
        {
218 1
            buf.writestring("\n");
219 1
            indent();
220
        }
221 1
        buf.writestring("}");
222 1
        comma();
223
    }
224

225
    // Json object property functions
226
    extern(D) void propertyStart(const char[] name)
227
    {
228 1
        indent();
229 1
        value(name);
230 1
        buf.writestring(" : ");
231
    }
232

233
    /**
234
    Write the given string object property only if `s` is not null.
235

236
    Params:
237
     name = the name of the object property
238
     s = the string value of the object property
239
    */
240
    extern(D) void property(const char[] name, const char[] s)
241
    {
242 1
        if (s is null)
243 1
            return;
244 1
        propertyStart(name);
245 1
        value(s);
246 1
        comma();
247
    }
248

249
    /**
250
    Write the given string object property.
251

252
    Params:
253
     name = the name of the object property
254
     s = the string value of the object property
255
    */
256
    extern(D) void requiredProperty(const char[] name, const char[] s)
257
    {
258 1
        propertyStart(name);
259 1
        if (s is null)
260 1
            buf.writestring("null");
261
        else
262 1
            value(s);
263 1
        comma();
264
    }
265

266
    extern(D) void property(const char[] name, int i)
267
    {
268 1
        propertyStart(name);
269 1
        value(i);
270 1
        comma();
271
    }
272

273
    extern(D) void propertyBool(const char[] name, const bool b)
274
    {
275 1
        propertyStart(name);
276 1
        valueBool(b);
277 1
        comma();
278
    }
279

280
    extern(D) void property(const char[] name, TRUST trust)
281
    {
282 0
        final switch (trust)
283
        {
284 0
        case TRUST.default_:
285
            // Should not be printed
286
            //property(name, "default");
287 0
            break;
288 0
        case TRUST.system:  return property(name, "system");
289 0
        case TRUST.trusted: return property(name, "trusted");
290 0
        case TRUST.safe:    return property(name, "safe");
291
        }
292
    }
293

294
    extern(D) void property(const char[] name, PURE purity)
295
    {
296 0
        final switch (purity)
297
        {
298 0
        case PURE.impure:
299
            // Should not be printed
300
            //property(name, "impure");
301 0
            break;
302 0
        case PURE.weak:     return property(name, "weak");
303 0
        case PURE.const_:   return property(name, "const");
304 0
        case PURE.strong:   return property(name, "strong");
305 0
        case PURE.fwdref:   return property(name, "fwdref");
306
        }
307
    }
308

309
    extern(D) void property(const char[] name, const LINK linkage)
310
    {
311 1
        final switch (linkage)
312
        {
313 1
        case LINK.default_:
314
            // Should not be printed
315
            //property(name, "default");
316 1
            break;
317 1
        case LINK.d:
318
            // Should not be printed
319
            //property(name, "d");
320 1
            break;
321 0
        case LINK.system:
322
            // Should not be printed
323
            //property(name, "system");
324 0
            break;
325 1
        case LINK.c:        return property(name, "c");
326 1
        case LINK.cpp:      return property(name, "cpp");
327 1
        case LINK.windows:  return property(name, "windows");
328 1
        case LINK.pascal:   return property(name, "pascal");
329 1
        case LINK.objc:     return property(name, "objc");
330
        }
331
    }
332

333
    extern(D) void propertyStorageClass(const char[] name, StorageClass stc)
334
    {
335 1
        stc &= STCStorageClass;
336 1
        if (stc)
337
        {
338 1
            propertyStart(name);
339 1
            arrayStart();
340 1
            while (stc)
341
            {
342 1
                auto p = stcToString(stc);
343 1
                assert(p.length);
344 1
                item(p);
345
            }
346 1
            arrayEnd();
347
        }
348
    }
349

350
    extern(D) void property(const char[] linename, const char[] charname, const ref Loc loc)
351
    {
352 1
        if (loc.isValid())
353
        {
354 1
            if (auto filename = loc.filename.toDString)
355
            {
356 1
                if (filename != this.filename)
357
                {
358 1
                    this.filename = filename;
359 1
                    property("file", filename);
360
                }
361
            }
362 1
            if (loc.linnum)
363
            {
364 1
                property(linename, loc.linnum);
365 1
                if (loc.charnum)
366 1
                    property(charname, loc.charnum);
367
            }
368
        }
369
    }
370

371
    extern(D) void property(const char[] name, Type type)
372
    {
373 0
        if (type)
374
        {
375 0
            property(name, type.toString());
376
        }
377
    }
378

379
    extern(D) void property(const char[] name, const char[] deconame, Type type)
380
    {
381 1
        if (type)
382
        {
383 1
            if (type.deco)
384 1
                property(deconame, type.deco.toDString);
385
            else
386 1
                property(name, type.toString());
387
        }
388
    }
389

390
    extern(D) void property(const char[] name, Parameters* parameters)
391
    {
392 1
        if (parameters is null || parameters.dim == 0)
393 1
            return;
394 1
        propertyStart(name);
395 1
        arrayStart();
396 1
        if (parameters)
397
        {
398 1
            for (size_t i = 0; i < parameters.dim; i++)
399
            {
400 1
                Parameter p = (*parameters)[i];
401 1
                objectStart();
402 1
                if (p.ident)
403 1
                    property("name", p.ident.toString());
404 1
                property("type", "deco", p.type);
405 1
                propertyStorageClass("storageClass", p.storageClass);
406 1
                if (p.defaultArg)
407 1
                    property("default", p.defaultArg.toString());
408 1
                objectEnd();
409
            }
410
        }
411 1
        arrayEnd();
412
    }
413

414
    /* ========================================================================== */
415
    void jsonProperties(Dsymbol s)
416
    {
417 1
        if (s.isModule())
418 0
            return;
419 1
        if (!s.isTemplateDeclaration()) // TemplateDeclaration::kind() acts weird sometimes
420
        {
421 1
            property("name", s.toString());
422 1
            property("kind", s.kind.toDString);
423
        }
424 1
        if (s.prot().kind != Prot.Kind.public_) // TODO: How about package(names)?
425 1
            property("protection", protectionToString(s.prot().kind));
426 1
        if (EnumMember em = s.isEnumMember())
427
        {
428 1
            if (em.origValue)
429 1
                property("value", em.origValue.toString());
430
        }
431 1
        property("comment", s.comment.toDString);
432 1
        property("line", "char", s.loc);
433
    }
434

435
    void jsonProperties(Declaration d)
436
    {
437 1
        if (d.storage_class & STC.local)
438 1
            return;
439 1
        jsonProperties(cast(Dsymbol)d);
440 1
        propertyStorageClass("storageClass", d.storage_class);
441 1
        property("linkage", d.linkage);
442 1
        property("type", "deco", d.type);
443
        // Emit originalType if it differs from type
444 1
        if (d.type != d.originalType && d.originalType)
445
        {
446 1
            auto ostr = d.originalType.toString();
447 1
            if (d.type)
448
            {
449 1
                auto tstr = d.type.toString();
450 1
                if (ostr != tstr)
451
                {
452
                    //printf("tstr = %s, ostr = %s\n", tstr, ostr);
453 1
                    property("originalType", ostr);
454
                }
455
            }
456
            else
457 1
                property("originalType", ostr);
458
        }
459
    }
460

461
    void jsonProperties(TemplateDeclaration td)
462
    {
463 1
        jsonProperties(cast(Dsymbol)td);
464 1
        if (td.onemember && td.onemember.isCtorDeclaration())
465 1
            property("name", "this"); // __ctor -> this
466
        else
467 1
            property("name", td.ident.toString()); // Foo(T) -> Foo
468
    }
469

470
    /* ========================================================================== */
471
    override void visit(Dsymbol s)
472
    {
473
    }
474

475
    override void visit(Module s)
476
    {
477 1
        objectStart();
478 1
        if (s.md)
479 1
            property("name", s.md.toString());
480 1
        property("kind", s.kind.toDString);
481 1
        filename = s.srcfile.toString();
482 1
        property("file", filename);
483 1
        property("comment", s.comment.toDString);
484 1
        propertyStart("members");
485 1
        arrayStart();
486 1
        for (size_t i = 0; i < s.members.dim; i++)
487
        {
488 1
            (*s.members)[i].accept(this);
489
        }
490 1
        arrayEnd();
491 1
        objectEnd();
492
    }
493

494
    override void visit(Import s)
495
    {
496 1
        if (s.id == Id.object)
497 1
            return;
498 1
        objectStart();
499 1
        propertyStart("name");
500 1
        stringStart();
501 1
        if (s.packages && s.packages.dim)
502
        {
503 1
            for (size_t i = 0; i < s.packages.dim; i++)
504
            {
505 1
                const pid = (*s.packages)[i];
506 1
                stringPart(pid.toString());
507 1
                buf.writeByte('.');
508
            }
509
        }
510 1
        stringPart(s.id.toString());
511 1
        stringEnd();
512 1
        comma();
513 1
        property("kind", s.kind.toDString);
514 1
        property("comment", s.comment.toDString);
515 1
        property("line", "char", s.loc);
516 1
        if (s.prot().kind != Prot.Kind.public_)
517 1
            property("protection", protectionToString(s.prot().kind));
518 1
        if (s.aliasId)
519 0
            property("alias", s.aliasId.toString());
520 1
        bool hasRenamed = false;
521 1
        bool hasSelective = false;
522 1
        for (size_t i = 0; i < s.aliases.dim; i++)
523
        {
524
            // avoid empty "renamed" and "selective" sections
525 1
            if (hasRenamed && hasSelective)
526 0
                break;
527 1
            else if (s.aliases[i])
528 1
                hasRenamed = true;
529
            else
530 1
                hasSelective = true;
531
        }
532 1
        if (hasRenamed)
533
        {
534
            // import foo : alias1 = target1;
535 1
            propertyStart("renamed");
536 1
            objectStart();
537 1
            for (size_t i = 0; i < s.aliases.dim; i++)
538
            {
539 1
                const name = s.names[i];
540 1
                const _alias = s.aliases[i];
541 1
                if (_alias)
542 1
                    property(_alias.toString(), name.toString());
543
            }
544 1
            objectEnd();
545
        }
546 1
        if (hasSelective)
547
        {
548
            // import foo : target1;
549 1
            propertyStart("selective");
550 1
            arrayStart();
551 1
            foreach (i, name; s.names)
552
            {
553 1
                if (!s.aliases[i])
554 1
                    item(name.toString());
555
            }
556 1
            arrayEnd();
557
        }
558 1
        objectEnd();
559
    }
560

561
    override void visit(AttribDeclaration d)
562
    {
563 1
        Dsymbols* ds = d.include(null);
564 1
        if (ds)
565
        {
566 1
            for (size_t i = 0; i < ds.dim; i++)
567
            {
568 1
                Dsymbol s = (*ds)[i];
569 1
                s.accept(this);
570
            }
571
        }
572
    }
573

574
    override void visit(ConditionalDeclaration d)
575
    {
576 1
        if (d.condition.inc != Include.notComputed)
577
        {
578 1
            visit(cast(AttribDeclaration)d);
579 1
            return; // Don't visit the if/else bodies again below
580
        }
581 1
        Dsymbols* ds = d.decl ? d.decl : d.elsedecl;
582 1
        for (size_t i = 0; i < ds.dim; i++)
583
        {
584 1
            Dsymbol s = (*ds)[i];
585 1
            s.accept(this);
586
        }
587
    }
588

589
    override void visit(TypeInfoDeclaration d)
590
    {
591
    }
592

593
    override void visit(PostBlitDeclaration d)
594
    {
595
    }
596

597
    override void visit(Declaration d)
598
    {
599 1
        objectStart();
600
        //property("unknown", "declaration");
601 1
        jsonProperties(d);
602 1
        objectEnd();
603
    }
604

605
    override void visit(AggregateDeclaration d)
606
    {
607 1
        objectStart();
608 1
        jsonProperties(d);
609 1
        ClassDeclaration cd = d.isClassDeclaration();
610 1
        if (cd)
611
        {
612 1
            if (cd.baseClass && cd.baseClass.ident != Id.Object)
613
            {
614 1
                property("base", cd.baseClass.toPrettyChars(true).toDString);
615
            }
616 1
            if (cd.interfaces.length)
617
            {
618 1
                propertyStart("interfaces");
619 1
                arrayStart();
620 1
                foreach (b; cd.interfaces)
621
                {
622 1
                    item(b.sym.toPrettyChars(true).toDString);
623
                }
624 1
                arrayEnd();
625
            }
626
        }
627 1
        if (d.members)
628
        {
629 1
            propertyStart("members");
630 1
            arrayStart();
631 1
            for (size_t i = 0; i < d.members.dim; i++)
632
            {
633 1
                Dsymbol s = (*d.members)[i];
634 1
                s.accept(this);
635
            }
636 1
            arrayEnd();
637
        }
638 1
        objectEnd();
639
    }
640

641
    override void visit(FuncDeclaration d)
642
    {
643 1
        objectStart();
644 1
        jsonProperties(d);
645 1
        TypeFunction tf = cast(TypeFunction)d.type;
646 1
        if (tf && tf.ty == Tfunction)
647 1
            property("parameters", tf.parameterList.parameters);
648 1
        property("endline", "endchar", d.endloc);
649 1
        if (d.foverrides.dim)
650
        {
651 1
            propertyStart("overrides");
652 1
            arrayStart();
653 1
            for (size_t i = 0; i < d.foverrides.dim; i++)
654
            {
655 1
                FuncDeclaration fd = d.foverrides[i];
656 1
                item(fd.toPrettyChars().toDString);
657
            }
658 1
            arrayEnd();
659
        }
660 1
        if (d.fdrequire)
661
        {
662 0
            propertyStart("in");
663 0
            d.fdrequire.accept(this);
664
        }
665 1
        if (d.fdensure)
666
        {
667 0
            propertyStart("out");
668 0
            d.fdensure.accept(this);
669
        }
670 1
        objectEnd();
671
    }
672

673
    override void visit(TemplateDeclaration d)
674
    {
675 1
        objectStart();
676
        // TemplateDeclaration::kind returns the kind of its Aggregate onemember, if it is one
677 1
        property("kind", "template");
678 1
        jsonProperties(d);
679 1
        propertyStart("parameters");
680 1
        arrayStart();
681 1
        for (size_t i = 0; i < d.parameters.dim; i++)
682
        {
683 1
            TemplateParameter s = (*d.parameters)[i];
684 1
            objectStart();
685 1
            property("name", s.ident.toString());
686

687 1
            if (auto type = s.isTemplateTypeParameter())
688
            {
689 1
                if (s.isTemplateThisParameter())
690 0
                    property("kind", "this");
691
                else
692 1
                    property("kind", "type");
693 1
                property("type", "deco", type.specType);
694 1
                property("default", "defaultDeco", type.defaultType);
695
            }
696

697 1
            if (auto value = s.isTemplateValueParameter())
698
            {
699 1
                property("kind", "value");
700 1
                property("type", "deco", value.valType);
701 1
                if (value.specValue)
702 0
                    property("specValue", value.specValue.toString());
703 1
                if (value.defaultValue)
704 0
                    property("defaultValue", value.defaultValue.toString());
705
            }
706

707 1
            if (auto _alias = s.isTemplateAliasParameter())
708
            {
709 1
                property("kind", "alias");
710 1
                property("type", "deco", _alias.specType);
711 1
                if (_alias.specAlias)
712 0
                    property("specAlias", _alias.specAlias.toString());
713 1
                if (_alias.defaultAlias)
714 0
                    property("defaultAlias", _alias.defaultAlias.toString());
715
            }
716

717 1
            if (auto tuple = s.isTemplateTupleParameter())
718
            {
719 1
                property("kind", "tuple");
720
            }
721

722 1
            objectEnd();
723
        }
724 1
        arrayEnd();
725 1
        Expression expression = d.constraint;
726 1
        if (expression)
727
        {
728 1
            property("constraint", expression.toString());
729
        }
730 1
        propertyStart("members");
731 1
        arrayStart();
732 1
        for (size_t i = 0; i < d.members.dim; i++)
733
        {
734 1
            Dsymbol s = (*d.members)[i];
735 1
            s.accept(this);
736
        }
737 1
        arrayEnd();
738 1
        objectEnd();
739
    }
740

741
    override void visit(EnumDeclaration d)
742
    {
743 1
        if (d.isAnonymous())
744
        {
745 0
            if (d.members)
746
            {
747 0
                for (size_t i = 0; i < d.members.dim; i++)
748
                {
749 0
                    Dsymbol s = (*d.members)[i];
750 0
                    s.accept(this);
751
                }
752
            }
753 0
            return;
754
        }
755 1
        objectStart();
756 1
        jsonProperties(d);
757 1
        property("base", "baseDeco", d.memtype);
758 1
        if (d.members)
759
        {
760 1
            propertyStart("members");
761 1
            arrayStart();
762 1
            for (size_t i = 0; i < d.members.dim; i++)
763
            {
764 1
                Dsymbol s = (*d.members)[i];
765 1
                s.accept(this);
766
            }
767 1
            arrayEnd();
768
        }
769 1
        objectEnd();
770
    }
771

772
    override void visit(EnumMember s)
773
    {
774 1
        objectStart();
775 1
        jsonProperties(cast(Dsymbol)s);
776 1
        property("type", "deco", s.origType);
777 1
        objectEnd();
778
    }
779

780
    override void visit(VarDeclaration d)
781
    {
782 1
        if (d.storage_class & STC.local)
783 1
            return;
784 1
        objectStart();
785 1
        jsonProperties(d);
786 1
        if (d._init)
787 1
            property("init", d._init.toString());
788 1
        if (d.isField())
789 1
            property("offset", d.offset);
790 1
        if (d.alignment && d.alignment != STRUCTALIGN_DEFAULT)
791 0
            property("align", d.alignment);
792 1
        objectEnd();
793
    }
794

795
    override void visit(TemplateMixin d)
796
    {
797 1
        objectStart();
798 1
        jsonProperties(d);
799 1
        objectEnd();
800
    }
801

802
    /**
803
    Generate an array of module objects that represent the syntax of each
804
    "root module".
805

806
    Params:
807
     modules = array of the "root modules"
808
    */
809
    private void generateModules(Modules* modules)
810
    {
811 1
        arrayStart();
812 1
        if (modules)
813
        {
814 1
            foreach (m; *modules)
815
            {
816 1
                if (global.params.verbose)
817 0
                    message("json gen %s", m.toChars());
818 1
                m.accept(this);
819
            }
820
        }
821 1
        arrayEnd();
822
    }
823

824
    /**
825
    Generate the "compilerInfo" object which contains information about the compiler
826
    such as the filename, version, supported features, etc.
827
    */
828
    private void generateCompilerInfo()
829
    {
830 1
        objectStart();
831 1
        requiredProperty("vendor", global.vendor);
832 1
        requiredProperty("version", global._version);
833 1
        property("__VERSION__", global.versionNumber());
834 1
        requiredProperty("interface", determineCompilerInterface());
835 1
        property("size_t", size_t.sizeof);
836 1
        propertyStart("platforms");
837 1
        arrayStart();
838 1
        if (global.params.isWindows)
839
        {
840 0
            item("windows");
841
        }
842
        else
843
        {
844 1
            item("posix");
845 1
            if (global.params.isLinux)
846 1
                item("linux");
847 0
            else if (global.params.isOSX)
848 0
                item("osx");
849 0
            else if (global.params.isFreeBSD)
850
            {
851 0
                item("freebsd");
852 0
                item("bsd");
853
            }
854 0
            else if (global.params.isOpenBSD)
855
            {
856 0
                item("openbsd");
857 0
                item("bsd");
858
            }
859 0
            else if (global.params.isSolaris)
860
            {
861 0
                item("solaris");
862 0
                item("bsd");
863
            }
864
        }
865 1
        arrayEnd();
866

867 1
        propertyStart("architectures");
868 1
        arrayStart();
869 1
        if (global.params.is64bit)
870 1
            item("x86_64");
871
        else
872
            version(X86) item("x86");
873 1
        arrayEnd();
874

875 1
        propertyStart("predefinedVersions");
876 1
        arrayStart();
877 1
        if (global.versionids)
878
        {
879 1
            foreach (const versionid; *global.versionids)
880
            {
881 1
                item(versionid.toString());
882
            }
883
        }
884 1
        arrayEnd();
885

886 1
        propertyStart("supportedFeatures");
887
        {
888 1
            objectStart();
889 1
            scope(exit) objectEnd();
890 1
            propertyBool("includeImports", true);
891
        }
892 1
        objectEnd();
893
    }
894

895
    /**
896
    Generate the "buildInfo" object which contains information specific to the
897
    current build such as CWD, importPaths, configFile, etc.
898
    */
899
    private void generateBuildInfo()
900
    {
901 1
        objectStart();
902 1
        requiredProperty("cwd", getcwd(null, 0).toDString);
903 1
        requiredProperty("argv0", global.params.argv0);
904 1
        requiredProperty("config", global.inifilename);
905 1
        requiredProperty("libName", global.params.libname);
906

907 1
        propertyStart("importPaths");
908 1
        arrayStart();
909 1
        if (global.params.imppath)
910
        {
911 1
            foreach (importPath; *global.params.imppath)
912
            {
913 1
                item(importPath.toDString);
914
            }
915
        }
916 1
        arrayEnd();
917

918 1
        propertyStart("objectFiles");
919 1
        arrayStart();
920 1
        foreach (objfile; global.params.objfiles)
921
        {
922 1
            item(objfile.toDString);
923
        }
924 1
        arrayEnd();
925

926 1
        propertyStart("libraryFiles");
927 1
        arrayStart();
928 1
        foreach (lib; global.params.libfiles)
929
        {
930 0
            item(lib.toDString);
931
        }
932 1
        arrayEnd();
933

934 1
        propertyStart("ddocFiles");
935 1
        arrayStart();
936 1
        foreach (ddocFile; global.params.ddocfiles)
937
        {
938 0
            item(ddocFile.toDString);
939
        }
940 1
        arrayEnd();
941

942 1
        requiredProperty("mapFile", global.params.mapfile);
943 1
        requiredProperty("resourceFile", global.params.resfile);
944 1
        requiredProperty("defFile", global.params.deffile);
945

946 1
        objectEnd();
947
    }
948

949
    /**
950
    Generate the "semantics" object which contains a 'modules' field representing
951
    semantic information about all the modules used in the compilation such as
952
    module name, isRoot, contentImportedFiles, etc.
953
    */
954
    private void generateSemantics()
955
    {
956 1
        objectStart();
957 1
        propertyStart("modules");
958 1
        arrayStart();
959 1
        foreach (m; Module.amodules)
960
        {
961 1
            objectStart();
962 1
            requiredProperty("name", m.md ? m.md.toString() : null);
963 1
            requiredProperty("file", m.srcfile.toString());
964 1
            propertyBool("isRoot", m.isRoot());
965 1
            if(m.contentImportedFiles.dim > 0)
966
            {
967 0
                propertyStart("contentImports");
968 0
                arrayStart();
969 0
                foreach (file; m.contentImportedFiles)
970
                {
971 0
                    item(file.toDString);
972
                }
973 0
                arrayEnd();
974
            }
975 1
            objectEnd();
976
        }
977 1
        arrayEnd();
978 1
        objectEnd();
979
    }
980
}
981

982
extern (C++) void json_generate(OutBuffer* buf, Modules* modules)
983
{
984 1
    scope ToJsonVisitor json = new ToJsonVisitor(buf);
985
    // write trailing newline
986 1
    scope(exit) buf.writeByte('\n');
987

988 1
    if (global.params.jsonFieldFlags == 0)
989
    {
990
        // Generate the original format, which is just an array
991
        // of modules representing their syntax.
992 1
        json.generateModules(modules);
993 1
        json.removeComma();
994
    }
995
    else
996
    {
997
        // Generate the new format which is an object where each
998
        // output option is its own field.
999

1000 1
        json.objectStart();
1001 1
        if (global.params.jsonFieldFlags & JsonFieldFlags.compilerInfo)
1002
        {
1003 1
            json.propertyStart("compilerInfo");
1004 1
            json.generateCompilerInfo();
1005
        }
1006 1
        if (global.params.jsonFieldFlags & JsonFieldFlags.buildInfo)
1007
        {
1008 1
            json.propertyStart("buildInfo");
1009 1
            json.generateBuildInfo();
1010
        }
1011 1
        if (global.params.jsonFieldFlags & JsonFieldFlags.modules)
1012
        {
1013 1
            json.propertyStart("modules");
1014 1
            json.generateModules(modules);
1015
        }
1016 1
        if (global.params.jsonFieldFlags & JsonFieldFlags.semantics)
1017
        {
1018 1
            json.propertyStart("semantics");
1019 1
            json.generateSemantics();
1020
        }
1021 1
        json.objectEnd();
1022
    }
1023
}
1024

1025
/**
1026
A string listing the name of each JSON field. Useful for errors messages.
1027
*/
1028
enum jsonFieldNames = () {
1029
    string s;
1030
    string prefix = "";
1031
    foreach (idx, enumName; __traits(allMembers, JsonFieldFlags))
1032
    {
1033
        static if (idx > 0)
1034
        {
1035
            s ~= prefix ~ "`" ~ enumName ~ "`";
1036
            prefix = ", ";
1037
        }
1038
    }
1039
    return s;
1040
}();
1041

1042
/**
1043
Parse the given `fieldName` and return its corresponding JsonFieldFlags value.
1044

1045
Params:
1046
 fieldName = the field name to parse
1047

1048
Returns: JsonFieldFlags.none on error, otherwise the JsonFieldFlags value
1049
         corresponding to the given fieldName.
1050
*/
1051
extern (C++) JsonFieldFlags tryParseJsonField(const(char)* fieldName)
1052
{
1053 1
    auto fieldNameString = fieldName.toDString();
1054
    foreach (idx, enumName; __traits(allMembers, JsonFieldFlags))
1055
    {
1056
        static if (idx > 0)
1057
        {
1058 1
            if (fieldNameString == enumName)
1059 1
                return __traits(getMember, JsonFieldFlags, enumName);
1060
        }
1061
    }
1062 1
    return JsonFieldFlags.none;
1063
}
1064

1065
/**
1066
Determines and returns the compiler interface which is one of `dmd`, `ldc`,
1067
`gdc` or `sdc`. Returns `null` if no interface can be determined.
1068
*/
1069
private extern(D) string determineCompilerInterface()
1070
{
1071 1
    if (global.vendor == "Digital Mars D")
1072 1
        return "dmd";
1073 0
    if (global.vendor == "LDC")
1074 0
        return "ldc";
1075 0
    if (global.vendor == "GNU D")
1076 0
        return "gdc";
1077 0
    if (global.vendor == "SDC")
1078 0
        return "sdc";
1079 0
    return null;
1080
}

Read our documentation on viewing source code .

Loading