1
/**
2
 * Describes a back-end compiler and implements compiler-specific actions.
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/compiler.d, _compiler.d)
8
 * Documentation:  https://dlang.org/phobos/dmd_compiler.html
9
 * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/compiler.d
10
 */
11

12
module dmd.compiler;
13

14
import dmd.astcodegen;
15
import dmd.arraytypes;
16
import dmd.dmodule;
17
import dmd.dscope;
18
import dmd.dsymbolsem;
19
import dmd.errors;
20
import dmd.expression;
21
import dmd.globals;
22
import dmd.id;
23
import dmd.identifier;
24
import dmd.mtype;
25
import dmd.parse;
26
import dmd.root.array;
27
import dmd.root.ctfloat;
28
import dmd.semantic2;
29
import dmd.semantic3;
30
import dmd.tokens;
31
import dmd.statement;
32

33
extern (C++) __gshared
34
{
35
    /// Module in which the D main is
36
    Module rootHasMain = null;
37

38
    bool includeImports = false;
39
    // array of module patterns used to include/exclude imported modules
40
    Array!(const(char)*) includeModulePatterns;
41
    Modules compiledImports;
42
}
43

44

45
/**
46
 * A data structure that describes a back-end compiler and implements
47
 * compiler-specific actions.
48
 */
49
extern (C++) struct Compiler
50
{
51
    /******************************
52
     * Encode the given expression, which is assumed to be an rvalue literal
53
     * as another type for use in CTFE.
54
     * This corresponds roughly to the idiom *(Type *)&e.
55
     */
56
    extern (C++) static Expression paintAsType(UnionExp* pue, Expression e, Type type)
57
    {
58
        union U
59
        {
60
            d_int32 int32value;
61
            d_int64 int64value;
62
            float float32value;
63
            double float64value;
64
        }
65 1
        U u = void;
66

67 1
        assert(e.type.size() == type.size());
68

69 1
        switch (e.type.ty)
70
        {
71 1
        case Tint32:
72 1
        case Tuns32:
73 1
            u.int32value = cast(d_int32) e.toInteger();
74 1
            break;
75 0
        case Tint64:
76 0
        case Tuns64:
77 0
            u.int64value = cast(d_int64) e.toInteger();
78 0
            break;
79 1
        case Tfloat32:
80 1
            u.float32value = cast(float) e.toReal();
81 1
            break;
82 1
        case Tfloat64:
83 1
            u.float64value = cast(double) e.toReal();
84 1
            break;
85 0
        case Tfloat80:
86 0
            assert(e.type.size() == 8); // 64-bit target `real`
87 0
            goto case Tfloat64;
88 0
        default:
89 0
            assert(0, "Unsupported source type");
90
        }
91

92 1
        real_t r = void;
93 1
        switch (type.ty)
94
        {
95 1
        case Tint32:
96 1
        case Tuns32:
97 1
            emplaceExp!(IntegerExp)(pue, e.loc, u.int32value, type);
98 1
            break;
99

100 1
        case Tint64:
101 1
        case Tuns64:
102 1
            emplaceExp!(IntegerExp)(pue, e.loc, u.int64value, type);
103 1
            break;
104

105 1
        case Tfloat32:
106 1
            r = u.float32value;
107 1
            emplaceExp!(RealExp)(pue, e.loc, r, type);
108 1
            break;
109

110 0
        case Tfloat64:
111 0
            r = u.float64value;
112 0
            emplaceExp!(RealExp)(pue, e.loc, r, type);
113 0
            break;
114

115 0
        case Tfloat80:
116 0
            assert(type.size() == 8); // 64-bit target `real`
117 0
            goto case Tfloat64;
118

119 0
        default:
120 0
            assert(0, "Unsupported target type");
121
        }
122 1
        return pue.exp();
123
    }
124

125
    /******************************
126
     * For the given module, perform any post parsing analysis.
127
     * Certain compiler backends (ie: GDC) have special placeholder
128
     * modules whose source are empty, but code gets injected
129
     * immediately after loading.
130
     */
131
    extern (C++) static void onParseModule(Module m)
132
    {
133
    }
134

135
    /**
136
     * A callback function that is called once an imported module is
137
     * parsed. If the callback returns true, then it tells the
138
     * frontend that the driver intends on compiling the import.
139
     */
140
    extern(C++) static bool onImport(Module m)
141
    {
142 1
        if (includeImports)
143
        {
144 1
            Identifiers empty;
145 1
            if (includeImportedModuleCheck(ModuleComponentRange(
146 1
                (m.md && m.md.packages) ? m.md.packages : &empty, m.ident, m.isPackageFile)))
147
            {
148 1
                if (global.params.verbose)
149 0
                    message("compileimport (%s)", m.srcfile.toChars);
150 1
                compiledImports.push(m);
151 1
                return true; // this import will be compiled
152
            }
153
        }
154 1
        return false; // this import will not be compiled
155
    }
156

157
    version (CallbackAPI)
158
    {
159
        alias OnStatementSemanticStart = void function(Statement, Scope*);
160
        alias OnStatementSemanticDone = void function(Statement, Scope*);
161

162
        /**
163
         * Used to insert functionality before the start of the
164
         * semantic analysis of a statement when importing DMD as a library
165
         */
166
        __gshared OnStatementSemanticStart onStatementSemanticStart
167
                    = function void(Statement s, Scope *sc) {};
168

169
        /**
170
         * Used to insert functionality after the end of the
171
         * semantic analysis of a statement when importing DMD as a library
172
         */
173
        __gshared OnStatementSemanticDone onStatementSemanticDone
174
                    = function void(Statement s, Scope *sc) {};
175
    }
176
}
177

178
/******************************
179
 * Private helpers for Compiler::onImport.
180
 */
181
// A range of component identifiers for a module
182
private struct ModuleComponentRange
183
{
184
    Identifiers* packages;
185
    Identifier name;
186
    bool isPackageFile;
187
    size_t index;
188 1
    @property auto totalLength() const { return packages.dim + 1 + (isPackageFile ? 1 : 0); }
189

190 1
    @property auto empty() { return index >= totalLength(); }
191
    @property auto front() const
192
    {
193 1
        if (index < packages.dim)
194 1
            return (*packages)[index];
195 1
        if (index == packages.dim)
196 1
            return name;
197
        else
198 1
            return Identifier.idPool("package");
199
    }
200 1
    void popFront() { index++; }
201
}
202

203
/*
204
 * Determines if the given module should be included in the compilation.
205
 * Returns:
206
 *  True if the given module should be included in the compilation.
207
 */
208
private bool includeImportedModuleCheck(ModuleComponentRange components)
209 1
    in { assert(includeImports); }
210
do
211
{
212 1
    createMatchNodes();
213 1
    size_t nodeIndex = 0;
214 1
    while (nodeIndex < matchNodes.dim)
215
    {
216
        //printf("matcher ");printMatcher(nodeIndex);printf("\n");
217 1
        auto info = matchNodes[nodeIndex++];
218 1
        if (info.depth <= components.totalLength())
219
        {
220 1
            size_t nodeOffset = 0;
221 1
            for (auto range = components;;range.popFront())
222
            {
223 1
                if (range.empty || nodeOffset >= info.depth)
224
                {
225
                    // MATCH
226 1
                    return !info.isExclude;
227
                }
228 1
                if (!(range.front is matchNodes[nodeIndex + nodeOffset].id))
229
                {
230 1
                    break;
231
                }
232 1
                nodeOffset++;
233
            }
234
        }
235 1
        nodeIndex += info.depth;
236
    }
237 1
    assert(nodeIndex == matchNodes.dim, "code bug");
238 1
    return includeByDefault;
239
}
240

241
// Matching module names is done with an array of matcher nodes.
242
// The nodes are sorted by "component depth" from largest to smallest
243
// so that the first match is always the longest (best) match.
244
private struct MatcherNode
245
{
246
    union
247
    {
248
        struct
249
        {
250
            ushort depth;
251
            bool isExclude;
252
        }
253
        Identifier id;
254
    }
255 1
    this(Identifier id) { this.id = id; }
256 1
    this(bool isExclude, ushort depth)
257
    {
258 1
        this.depth = depth;
259 1
        this.isExclude = isExclude;
260
    }
261
}
262

263
/*
264
 * $(D includeByDefault) determines whether to include/exclude modules when they don't
265
 * match any pattern. This setting changes depending on if the user provided any "inclusive" module
266
 * patterns. When a single "inclusive" module pattern is given, it likely means the user only
267
 * intends to include modules they've "included", however, if no module patterns are given or they
268
 * are all "exclusive", then it is likely they intend to include everything except modules
269
 * that have been excluded. i.e.
270
 * ---
271
 * -i=-foo // include everything except modules that match "foo*"
272
 * -i=foo  // only include modules that match "foo*" (exclude everything else)
273
 * ---
274
 * Note that this default behavior can be overriden using the '.' module pattern. i.e.
275
 * ---
276
 * -i=-foo,-.  // this excludes everything
277
 * -i=foo,.    // this includes everything except the default exclusions (-std,-core,-etc.-object)
278
 * ---
279
*/
280
private __gshared bool includeByDefault = true;
281
private __gshared Array!MatcherNode matchNodes;
282

283
/*
284
 * Creates the global list of match nodes used to match module names
285
 * given strings provided by the -i commmand line option.
286
 */
287
private void createMatchNodes()
288
{
289
    static size_t findSortedIndexToAddForDepth(size_t depth)
290
    {
291 1
        size_t index = 0;
292 1
        while (index < matchNodes.dim)
293
        {
294 1
            auto info = matchNodes[index];
295 1
            if (depth > info.depth)
296 1
                break;
297 1
            index += 1 + info.depth;
298
        }
299 1
        return index;
300
    }
301

302 1
    if (matchNodes.dim == 0)
303
    {
304 1
        foreach (modulePattern; includeModulePatterns)
305
        {
306 1
            auto depth = parseModulePatternDepth(modulePattern);
307 1
            auto entryIndex = findSortedIndexToAddForDepth(depth);
308 1
            matchNodes.split(entryIndex, depth + 1);
309 1
            parseModulePattern(modulePattern, &matchNodes[entryIndex], depth);
310
            // if at least 1 "include pattern" is given, then it is assumed the
311
            // user only wants to include modules that were explicitly given, which
312
            // changes the default behavior from inclusion to exclusion.
313 1
            if (includeByDefault && !matchNodes[entryIndex].isExclude)
314
            {
315
                //printf("Matcher: found 'include pattern', switching default behavior to exclusion\n");
316 1
                includeByDefault = false;
317
            }
318
        }
319

320
        // Add the default 1 depth matchers
321 1
        MatcherNode[8] defaultDepth1MatchNodes = [
322
            MatcherNode(true, 1), MatcherNode(Id.std),
323
            MatcherNode(true, 1), MatcherNode(Id.core),
324
            MatcherNode(true, 1), MatcherNode(Id.etc),
325
            MatcherNode(true, 1), MatcherNode(Id.object),
326
        ];
327
        {
328 1
            auto index = findSortedIndexToAddForDepth(1);
329 1
            matchNodes.split(index, defaultDepth1MatchNodes.length);
330 1
            auto slice = matchNodes[];
331 1
            slice[index .. index + defaultDepth1MatchNodes.length] = defaultDepth1MatchNodes[];
332
        }
333
    }
334
}
335

336
/*
337
 * Determines the depth of the given module pattern.
338
 * Params:
339
 *  modulePattern = The module pattern to determine the depth of.
340
 * Returns:
341
 *  The component depth of the given module pattern.
342
 */
343
private ushort parseModulePatternDepth(const(char)* modulePattern)
344
{
345 1
    if (modulePattern[0] == '-')
346 1
        modulePattern++;
347

348
    // handle special case
349 1
    if (modulePattern[0] == '.' && modulePattern[1] == '\0')
350 1
        return 0;
351

352 1
    ushort depth = 1;
353 1
    for (;; modulePattern++)
354
    {
355 1
        auto c = *modulePattern;
356 1
        if (c == '.')
357 1
            depth++;
358 1
        if (c == '\0')
359 1
            return depth;
360
    }
361
}
362
unittest
363
{
364
    assert(".".parseModulePatternDepth == 0);
365
    assert("-.".parseModulePatternDepth == 0);
366
    assert("abc".parseModulePatternDepth == 1);
367
    assert("-abc".parseModulePatternDepth == 1);
368
    assert("abc.foo".parseModulePatternDepth == 2);
369
    assert("-abc.foo".parseModulePatternDepth == 2);
370
}
371

372
/*
373
 * Parses a 'module pattern', which is the "include import" components
374
 * given on the command line, i.e. "-i=<module_pattern>,<module_pattern>,...".
375
 * Params:
376
 *  modulePattern = The module pattern to parse.
377
 *  dst = the data structure to save the parsed module pattern to.
378
 *  depth = the depth of the module pattern previously retrieved from $(D parseModulePatternDepth).
379
 */
380
private void parseModulePattern(const(char)* modulePattern, MatcherNode* dst, ushort depth)
381
{
382 1
    bool isExclude = false;
383 1
    if (modulePattern[0] == '-')
384
    {
385 1
        isExclude = true;
386 1
        modulePattern++;
387
    }
388

389 1
    *dst = MatcherNode(isExclude, depth);
390 1
    dst++;
391

392
    // Create and add identifiers for each component in the modulePattern
393 1
    if (depth > 0)
394
    {
395 1
        auto idStart = modulePattern;
396 1
        auto lastNode = dst + depth - 1;
397 1
        for (; dst < lastNode; dst++)
398
        {
399 1
            for (;; modulePattern++)
400
            {
401 1
                if (*modulePattern == '.')
402
                {
403 1
                    assert(modulePattern > idStart, "empty module pattern");
404 1
                    *dst = MatcherNode(Identifier.idPool(idStart, cast(uint)(modulePattern - idStart)));
405 1
                    modulePattern++;
406 1
                    idStart = modulePattern;
407 1
                    break;
408
                }
409
            }
410
        }
411 1
        for (;; modulePattern++)
412
        {
413 1
            if (*modulePattern == '\0')
414
            {
415 1
                assert(modulePattern > idStart, "empty module pattern");
416 1
                *lastNode = MatcherNode(Identifier.idPool(idStart, cast(uint)(modulePattern - idStart)));
417 1
                break;
418
            }
419
        }
420
    }
421
}

Read our documentation on viewing source code .

Loading