summaryrefslogtreecommitdiffstats
path: root/source/compiler-core/slang-include-system.cpp
blob: 1b768d506d54a23c519d17128dc4f79e8efdccfa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
// slang-include-system.cpp
#include "slang-include-system.h"

#include "../core/slang-io.h"
#include "../core/slang-string-util.h"

#include "../core/slang-file-system.h"

#include "slang-slice-allocator.h"
#include "slang-artifact-impl.h"
#include "slang-artifact-representation-impl.h"

namespace Slang
{

IncludeSystem::IncludeSystem(SearchDirectoryList* searchDirectories, ISlangFileSystemExt* fileSystemExt, SourceManager* sourceManager) :
    m_searchDirectories(searchDirectories),
    m_fileSystemExt(fileSystemExt),
    m_sourceManager(sourceManager)
{
}

SlangResult IncludeSystem::findFile(SlangPathType fromPathType, const String& fromPath, const String& path, PathInfo& outPathInfo)
{
    String combinedPath;

    if (fromPath.getLength() == 0 || Path::isAbsolute(path))
    {
        // If the path is absolute or the fromPath is empty, the combined path is just the path
        combinedPath = path;
    }
    else
    {
        // Get relative path
        ComPtr<ISlangBlob> combinedPathBlob;
        SLANG_RETURN_ON_FAIL(m_fileSystemExt->calcCombinedPath(fromPathType, fromPath.begin(), path.begin(), combinedPathBlob.writeRef()));
        combinedPath = StringUtil::getString(combinedPathBlob);
        if (combinedPath.getLength() <= 0)
        {
            return SLANG_FAIL;
        }
    }

    // This checks the path exists
    SlangPathType pathType;
    SLANG_RETURN_ON_FAIL(m_fileSystemExt->getPathType(combinedPath.begin(), &pathType));
    if (pathType != SLANG_PATH_TYPE_FILE)
    {
        return SLANG_E_NOT_FOUND;
    }

    // Get the uniqueIdentity
    ComPtr<ISlangBlob> uniqueIdentityBlob;
    SLANG_RETURN_ON_FAIL(m_fileSystemExt->getFileUniqueIdentity(combinedPath.begin(), uniqueIdentityBlob.writeRef()));

    // If the rel path exists -> a uniqueIdentity MUST exists too
    String uniqueIdentity(StringUtil::getString(uniqueIdentityBlob));
    if (uniqueIdentity.getLength() <= 0)
    {
        // Unique identity can't be empty
        return SLANG_FAIL;
    }

    outPathInfo = PathInfo::makeNormal(combinedPath, uniqueIdentity);
    return SLANG_OK;
}

String IncludeSystem::simplifyPath(const String& path)
{
    ComPtr<ISlangBlob> simplifiedPath;
    if (SLANG_FAILED(m_fileSystemExt->getPath(PathKind::Simplified, path.getBuffer(), simplifiedPath.writeRef())))
    {
        return path;
    }
    return StringUtil::getString(simplifiedPath);
}

SlangResult IncludeSystem::findFile(String const& pathToInclude, String const& pathIncludedFrom, PathInfo& outPathInfo)
{
    outPathInfo.type = PathInfo::Type::Unknown;

    // If it's absolute we only have to try and find if it's there - no need to look at search paths
    if (Path::isAbsolute(pathToInclude))
    {
        // We pass in "" as the from path, so ensure no from path is taken into account
        // and to allow easy identification that this is in effect absolute
        return findFile(SLANG_PATH_TYPE_DIRECTORY, UnownedStringSlice::fromLiteral(""), pathToInclude, outPathInfo);
    }

    // Try just relative to current path
    {
        SlangResult res = findFile(SLANG_PATH_TYPE_FILE, pathIncludedFrom, pathToInclude, outPathInfo);
        // It either succeeded or wasn't found, anything else is a failure passed back
        if (SLANG_SUCCEEDED(res) || res != SLANG_E_NOT_FOUND)
        {
            return res;
        }
    }

    // Search all the searchDirectories
    for (auto sd = m_searchDirectories; sd; sd = sd->parent)
    {
        for (auto& dir : sd->searchDirectories)
        {
            SlangResult res = findFile(SLANG_PATH_TYPE_DIRECTORY, dir.path, pathToInclude, outPathInfo);
            if (SLANG_SUCCEEDED(res) || res != SLANG_E_NOT_FOUND)
            {
                return res;
            }
        }
    }

    return SLANG_E_NOT_FOUND;
}

SlangResult IncludeSystem::loadFile(const PathInfo& pathInfo, ComPtr<ISlangBlob>& outBlob, SourceFile*& outSourceFile)
{
    if (m_sourceManager)
    {
        // See if this an already loaded source file
        outSourceFile = m_sourceManager->findSourceFileRecursively(pathInfo.uniqueIdentity);

        // If not create a new one, and add to the list of known source files
        if (!outSourceFile)
        {
            ComPtr<ISlangBlob> foundSourceBlob;
            if (SLANG_FAILED(m_fileSystemExt->loadFile(pathInfo.foundPath.getBuffer(), foundSourceBlob.writeRef())))
            {
                return SLANG_E_CANNOT_OPEN;
            }

            outSourceFile = m_sourceManager->createSourceFileWithBlob(pathInfo, foundSourceBlob);
            m_sourceManager->addSourceFile(pathInfo.uniqueIdentity, outSourceFile);

            outBlob = foundSourceBlob;
            return SLANG_OK;
        }
        else
        {
            if (outSourceFile->getContentBlob())
            {
                outBlob = outSourceFile->getContentBlob();
                return SLANG_OK;
            }

            ComPtr<ISlangBlob> foundSourceBlob;
            if (SLANG_FAILED(m_fileSystemExt->loadFile(pathInfo.foundPath.getBuffer(), foundSourceBlob.writeRef())))
            {
                return SLANG_E_CANNOT_OPEN;
            }

            outSourceFile->setContents(foundSourceBlob);

            outBlob = foundSourceBlob;
            return SLANG_OK;
        }
    }
    else
    {
        // If we don't have the source manager, just load
        outSourceFile = nullptr;
        return m_fileSystemExt->loadFile(pathInfo.foundPath.getBuffer(), outBlob.writeRef());
    }
}

SlangResult IncludeSystem::findAndLoadFile(const String& pathToInclude, const String& pathIncludedFrom, PathInfo& outPathInfo, ComPtr<ISlangBlob>& outBlob)
{
    SLANG_RETURN_ON_FAIL(findFile(pathToInclude, pathIncludedFrom, outPathInfo));
    SLANG_RETURN_ON_FAIL(loadFile(outPathInfo, outBlob));
    return SLANG_OK;
}

} // namespace Slang