yum-mirror/slang

Making it easier to work with shaders

git clone https://git.yummers.dev/yum-mirror/slang

Ellie Hermaszewskaformatf65d756bf

master
9.0 KiB349 linesraw
1#include "slang-command-line-args.h"
2
3#include "../core/slang-process-util.h"
4#include "../core/slang-string-escape-util.h"
5#include "../core/slang-string-util.h"
6#include "../core/slang-type-text-util.h"
7#include "slang-core-diagnostics.h"
8
9namespace Slang
10{
11
12void CommandLineArgs::setArgs(const char* const* args, size_t argCount)
13{
14    m_args.clear();
15
16    SourceManager* sourceManager = m_context->getSourceManager();
17
18    const SourceLoc startLoc = sourceManager->getNextRangeStart();
19
20    StringBuilder buf;
21
22    auto escapeHandler = Process::getEscapeHandler();
23
24    for (size_t i = 0; i < argCount; ++i)
25    {
26        const Index offset = buf.getLength();
27
28        const char* srcArg = args[i];
29
30        Arg dstArg;
31        dstArg.loc = startLoc + offset;
32        dstArg.value = srcArg;
33
34        m_args.add(dstArg);
35
36        // Write the string escaped if necessary
37        StringEscapeUtil::appendMaybeQuoted(escapeHandler, dstArg.value.getUnownedSlice(), buf);
38
39        // Put a space between the args
40        buf << " ";
41    }
42
43    SourceFile* sourceFile =
44        sourceManager->createSourceFileWithString(PathInfo::makeUnknown(), buf.produceString());
45    SourceView* sourceView =
46        sourceManager->createSourceView(sourceFile, nullptr, SourceLoc::fromRaw(0));
47
48    SLANG_UNUSED(sourceView);
49    SLANG_ASSERT(sourceView->getRange().begin == startLoc);
50}
51
52bool CommandLineArgs::hasArgs(const char* const* args, Index count) const
53{
54    if (m_args.getCount() != count)
55    {
56        return false;
57    }
58
59    for (Index i = 0; i < count; ++i)
60    {
61        if (m_args[i].value != args[i])
62        {
63            return false;
64        }
65    }
66
67    return true;
68}
69
70String CommandLineArgs::serialize()
71{
72    StringBuilder sb;
73    for (auto& arg : m_args)
74        sb << arg.value << "\n";
75    return sb.produceString();
76}
77
78void CommandLineArgs::deserialize(String content)
79{
80    List<UnownedStringSlice> slices;
81    StringUtil::split(content.getUnownedSlice(), '\n', slices);
82    for (auto arg : slices)
83    {
84        Arg v;
85        v.value = arg;
86        v.loc = SourceLoc();
87        m_args.add(v);
88    }
89}
90
91/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
92
93                         CommandLineReader
94
95!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
96
97String CommandLineReader::getPreviousValue() const
98{
99    SLANG_ASSERT(m_index > 0);
100    if (m_index > 0)
101    {
102        const auto& prevArg = (*m_args)[m_index - 1];
103        return prevArg.value;
104    }
105    else
106    {
107        return String();
108    }
109}
110
111SlangResult CommandLineReader::expectArg(String& outArg)
112{
113    if (hasArg())
114    {
115        outArg = m_args->m_args[m_index++].value;
116        return SLANG_OK;
117    }
118    else
119    {
120        m_sink->diagnose(peekLoc(), MiscDiagnostics::expectedArgumentForOption, getPreviousValue());
121        return SLANG_FAIL;
122    }
123}
124
125SlangResult CommandLineReader::expectArg(CommandLineArg& outArg)
126{
127    if (hasArg())
128    {
129        outArg = peekArg();
130        advance();
131        return SLANG_OK;
132    }
133    else
134    {
135        m_sink->diagnose(peekLoc(), MiscDiagnostics::expectedArgumentForOption, getPreviousValue());
136        return SLANG_FAIL;
137    }
138}
139
140/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
141
142                         DownstreamArgs
143
144!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
145
146DownstreamArgs::DownstreamArgs(CommandLineContext* context)
147    : m_context(context)
148{
149    // Add all of the possible names we allow for downstream tools
150    {
151        for (Index i = SLANG_PASS_THROUGH_NONE + 1; i < SLANG_PASS_THROUGH_COUNT_OF; ++i)
152        {
153            addName(TypeTextUtil::getPassThroughName(SlangPassThrough(i)));
154        }
155
156        // Generic downstream tool
157        addName("downstream");
158        // Generic downstream linker
159        addName("linker");
160    }
161}
162
163
164Index DownstreamArgs::addName(const String& name)
165{
166    Index index = findName(name);
167    if (index < 0)
168    {
169        index = m_entries.getCount();
170        m_entries.add(Entry{name, CommandLineArgs(m_context)});
171    }
172    return index;
173}
174
175Index DownstreamArgs::_findOrAddName(
176    SourceLoc loc,
177    const UnownedStringSlice& name,
178    Flags flags,
179    DiagnosticSink* sink)
180{
181    if (name.getLength() <= 0)
182    {
183        if (sink)
184        {
185            sink->diagnose(loc, MiscDiagnostics::downstreamToolNameNotDefined);
186        }
187        return -1;
188    }
189
190    if (flags & Flag::AllowNewNames)
191    {
192        return addName(name);
193    }
194
195    Index index = findName(name);
196    if (index >= 0)
197    {
198        return index;
199    }
200
201    if (sink)
202    {
203        StringBuilder names;
204
205        names << "[ ";
206        for (Index i = 0; i < m_entries.getCount(); ++i)
207        {
208            if (i)
209            {
210                names << ", ";
211            }
212            names << m_entries[i].name;
213        }
214        names << " ]";
215
216        sink->diagnose(loc, MiscDiagnostics::downstreamNameNotKnown, names);
217    }
218    return -1;
219}
220
221CommandLineArgs& DownstreamArgs::getArgsByName(const char* name)
222{
223    const Index index = findName(name);
224    SLANG_ASSERT(index >= 0);
225    return m_entries[index].args;
226}
227
228const CommandLineArgs& DownstreamArgs::getArgsByName(const char* name) const
229{
230    const Index index = findName(name);
231    SLANG_ASSERT(index >= 0);
232    return m_entries[index].args;
233}
234
235SlangResult DownstreamArgs::stripDownstreamArgs(
236    CommandLineArgs& ioArgs,
237    Flags flags,
238    DiagnosticSink* sink)
239{
240    CommandLineReader reader(&ioArgs, sink);
241
242    while (reader.hasArg())
243    {
244        const CommandLineArg& arg = reader.peekArg();
245
246        if (arg.value.startsWith("-X"))
247        {
248            if (arg.value.endsWith("..."))
249            {
250                const UnownedStringSlice name =
251                    arg.value.getUnownedSlice().subString(2, arg.value.getLength() - 5);
252                const Index nameIndex = _findOrAddName(arg.loc, name, flags, sink);
253                if (nameIndex < 0)
254                {
255                    return SLANG_FAIL;
256                }
257
258                Index depth = 1;
259                const Index startIndex = reader.getIndex();
260
261                Int index = startIndex + 1;
262                const Int count = ioArgs.m_args.getCount();
263
264                for (; index < count; ++index)
265                {
266                    const auto& curArg = ioArgs.m_args[index];
267
268                    if (curArg.value == "-X.")
269                    {
270                        depth--;
271                        // If we are at end of scope we are done
272                        if (depth <= 0)
273                        {
274                            break;
275                        }
276                    }
277                    else if (curArg.value.startsWith("-X") && curArg.value.endsWith("..."))
278                    {
279                        depth++;
280                    }
281                }
282
283                // We don't care if its 1, as we allow the main scope to be left open
284                if (depth > 1)
285                {
286                    sink->diagnose(arg.loc, MiscDiagnostics::unbalancedDownstreamArguments);
287                    return SLANG_FAIL;
288                }
289
290                // We are either at end of scope or at end of list
291                SLANG_ASSERT(depth <= 0 || index >= count);
292
293                // Add all of these args
294                CommandLineArgs& args = getArgsAt(nameIndex);
295
296                // Copy the values in the range
297                args.m_args.addRange(
298                    ioArgs.m_args.getBuffer() + startIndex + 1,
299                    index - (startIndex + 1));
300
301                // If we aren't at the end, we must be pointing to -X., so skip that
302                index += Index(index < count);
303                // Remove the range. The readers position, needs to be fixed though
304                ioArgs.m_args.removeRange(startIndex, index - startIndex);
305
306                // The reader should be at startIndex, and so doesn't need fixing
307                SLANG_ASSERT(reader.getIndex() == startIndex);
308            }
309            else if (arg.value == "-X.")
310            {
311                sink->diagnose(arg.loc, MiscDiagnostics::closeOfUnopenDownstreamArgs);
312                return SLANG_FAIL;
313            }
314            else
315            {
316                const Index startIndex = reader.getIndex();
317
318                // Extract the name
319                UnownedStringSlice name = arg.value.getUnownedSlice().tail(2);
320                const Index nameIndex = _findOrAddName(arg.loc, name, flags, sink);
321                if (nameIndex < 0)
322                {
323                    return SLANG_FAIL;
324                }
325
326                reader.advance();
327
328                CommandLineArg nextArg;
329                SLANG_RETURN_ON_FAIL(reader.expectArg(nextArg));
330
331                getArgsAt(nameIndex).add(nextArg);
332
333                // Rewind to the start index
334                reader.setIndex(startIndex);
335                // Remove the args
336                ioArgs.m_args.removeRange(startIndex, 2);
337            }
338        }
339        else
340        {
341            // Advance and leave
342            reader.advance();
343        }
344    }
345
346    return SLANG_OK;
347}
348
349} // namespace Slang