yum-mirror/slang

Making it easier to work with shaders

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

Lauro OyenMove c++ parsing code from slang-cpp-extractor to static library (#5675)eaa8dcfcc

master
14.5 KiB700 linesraw
1#include "node.h"
2
3#include "core/slang-string-escape-util.h"
4#include "core/slang-string-util.h"
5#include "file-util.h"
6
7namespace CppParse
8{
9
10// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Node Impl
11// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
12
13SLANG_FORCE_INLINE static void _indent(Index indentCount, StringBuilder& out)
14{
15    FileUtil::indent(indentCount, out);
16}
17
18void Node::dumpMarkup(int indentCount, StringBuilder& out)
19{
20    if (m_markup.getLength() <= 0)
21    {
22        return;
23    }
24
25    List<UnownedStringSlice> lines;
26    StringUtil::calcLines(m_markup.getUnownedSlice(), lines);
27
28    // Remove empty lines from the end
29    while (lines.getCount())
30    {
31        auto lastLine = lines.getLast();
32        if (lastLine.trim().getLength() == 0)
33        {
34            lines.removeLast();
35            continue;
36        }
37        break;
38    }
39
40    if (lines.getCount() == 0)
41    {
42        return;
43    }
44
45    for (auto line : lines)
46    {
47        _indent(indentCount, out);
48        out << "// " << line << "\n";
49    }
50}
51
52ScopeNode* Node::getRootScope()
53{
54    if (m_parentScope)
55    {
56        ScopeNode* scope = m_parentScope;
57        while (scope->m_parentScope)
58        {
59            scope = scope->m_parentScope;
60        }
61        return scope;
62    }
63    else
64    {
65        return as<ScopeNode>(this);
66    }
67}
68
69void Node::calcScopeDepthFirst(List<Node*>& outNodes)
70{
71    outNodes.add(this);
72}
73
74void Node::calcAbsoluteName(StringBuilder& outName) const
75{
76    List<Node*> path;
77    calcScopePath(const_cast<Node*>(this), path);
78
79    // 1 so we skip the global scope
80    for (Index i = 1; i < path.getCount(); ++i)
81    {
82        Node* node = path[i];
83
84        if (i > 1)
85        {
86            outName << "::";
87        }
88
89        if (node->m_kind == Kind::AnonymousNamespace)
90        {
91            outName << "{Anonymous}";
92        }
93        else
94        {
95            outName << node->m_name.getContent();
96        }
97    }
98}
99
100/* static */ void Node::calcScopePath(Node* node, List<Node*>& outPath)
101{
102    outPath.clear();
103
104    while (node)
105    {
106        outPath.add(node);
107        node = node->m_parentScope;
108    }
109
110    // reverse the order, so we go from root to the node
111    outPath.reverse();
112}
113
114/* static */ void Node::filterImpl(Filter inFilter, List<Node*>& ioNodes)
115{
116    // Filter out all the unreflected nodes
117    Index count = ioNodes.getCount();
118    for (Index j = 0; j < count;)
119    {
120        Node* node = ioNodes[j];
121
122        if (!inFilter(node))
123        {
124            ioNodes.removeAt(j);
125            count--;
126        }
127        else
128        {
129            j++;
130        }
131    }
132}
133
134/* static */ Node* Node::lookupNameInScope(ScopeNode* scope, const UnownedStringSlice& name)
135{
136    // TODO(JS): Doesn't handle 'using namespace'.
137
138    // Must be unqualified name
139    SLANG_ASSERT(name.indexOf(UnownedStringSlice::fromLiteral("::")) < 0);
140
141    Node* childNode = scope->findChild(name);
142    if (childNode)
143    {
144        return childNode;
145    }
146
147    // If we have an anonymous namespace in this scope, try looking up in there..
148    if (scope->m_anonymousNamespace)
149    {
150        Node* childNode = scope->m_anonymousNamespace->findChild(name);
151        if (childNode)
152        {
153            return childNode;
154        }
155    }
156
157    // I could have an enum (that's not an enum class)
158    for (Node* node : scope->m_children)
159    {
160        EnumNode* enumNode = as<EnumNode>(node);
161        if (enumNode && enumNode->m_kind == Node::Kind::Enum)
162        {
163            Node** nodePtr = enumNode->m_childMap.tryGetValue(name);
164            if (nodePtr)
165            {
166                return *nodePtr;
167            }
168        }
169    }
170
171    return nullptr;
172}
173
174/* static */ Node* Node::lookupFromScope(
175    ScopeNode* scope,
176    const UnownedStringSlice* parts,
177    Index partsCount)
178{
179    SLANG_ASSERT(partsCount > 0);
180    if (partsCount == 1)
181    {
182        return lookupNameInScope(scope, parts[0]);
183    }
184
185    for (Index i = 0; i < partsCount; ++i)
186    {
187        const UnownedStringSlice& part = parts[i];
188
189        Node* node = lookupNameInScope(scope, part);
190        if (node == nullptr)
191        {
192            return node;
193        }
194        // If at end, then we are done
195        if (i == partsCount - 1)
196        {
197            return node;
198        }
199
200        // If there are more elements, then node must be some kind of scope,
201        // if we are going to find it
202        scope = as<ScopeNode>(node);
203        if (scope == nullptr)
204        {
205            break;
206        }
207    }
208
209    return nullptr;
210}
211
212/* static */ void Node::splitPath(
213    const UnownedStringSlice& inPath,
214    List<UnownedStringSlice>& outParts)
215{
216    if (inPath.indexOf(UnownedStringSlice::fromLiteral("::")) >= 0)
217    {
218        StringUtil::split(inPath, UnownedStringSlice::fromLiteral("::"), outParts);
219        // Remove any whitespace
220        for (auto& part : outParts)
221        {
222            part = part.trim();
223        }
224    }
225    else
226    {
227        outParts.clear();
228        outParts.add(inPath.trim());
229    }
230}
231
232/* static */ Node* Node::lookupFromScope(ScopeNode* scope, const UnownedStringSlice& inPath)
233{
234    if (inPath.indexOf(UnownedStringSlice::fromLiteral("::")) >= 0)
235    {
236        List<UnownedStringSlice> parts;
237        splitPath(inPath, parts);
238
239        return lookupFromScope(scope, parts.getBuffer(), parts.getCount());
240    }
241    else
242    {
243        return lookupNameInScope(scope, inPath);
244    }
245}
246
247/* static */ Node* Node::lookup(ScopeNode* scope, const UnownedStringSlice& inPath)
248{
249    if (inPath.indexOf(UnownedStringSlice::fromLiteral("::")) >= 0)
250    {
251        List<UnownedStringSlice> parts;
252        splitPath(inPath, parts);
253
254        if (parts[0].getLength() == 0)
255        {
256            // It's a lookup from global scope
257            ScopeNode* rootScope = scope->getRootScope();
258            return lookupFromScope(rootScope, parts.getBuffer() + 1, parts.getCount() + 1);
259        }
260
261        // Okay lets try a lookup from each scope up to the global scope
262        while (scope)
263        {
264            Node* node = lookupFromScope(scope, parts.getBuffer(), parts.getCount());
265            if (node)
266            {
267                return node;
268            }
269
270            scope = scope->m_parentScope;
271        }
272    }
273    else
274    {
275        while (scope)
276        {
277            // Lookup in this scope
278            Node* node = lookupNameInScope(scope, inPath);
279            if (node)
280            {
281                return node;
282            }
283
284            // Try parent scope
285            scope = scope->m_parentScope;
286        }
287    }
288
289    return nullptr;
290}
291
292// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ScopeNode !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
293
294ScopeNode* ScopeNode::getAnonymousNamespace()
295{
296    if (!m_anonymousNamespace)
297    {
298        m_anonymousNamespace = new ScopeNode(Kind::AnonymousNamespace);
299        m_anonymousNamespace->m_parentScope = this;
300        m_children.add(m_anonymousNamespace);
301    }
302
303    return m_anonymousNamespace;
304}
305
306void ScopeNode::addChildIgnoringName(Node* child)
307{
308    SLANG_ASSERT(child->m_parentScope == nullptr);
309    // Can't add anonymous namespace this way - should be added via getAnonymousNamespace
310    SLANG_ASSERT(child->m_kind != Kind::AnonymousNamespace);
311
312    child->m_parentScope = this;
313    m_children.add(child);
314}
315
316void ScopeNode::addChild(Node* child)
317{
318    addChildIgnoringName(child);
319
320    if (child->m_name.hasContent())
321    {
322        m_childMap.add(child->m_name.getContent(), child);
323    }
324}
325
326Node* ScopeNode::findChild(const UnownedStringSlice& name) const
327{
328    Node* const* nodePtr = m_childMap.tryGetValue(name);
329    if (nodePtr)
330    {
331        return *nodePtr;
332    }
333    return nullptr;
334}
335
336void ScopeNode::calcScopeDepthFirst(List<Node*>& outNodes)
337{
338    outNodes.add(this);
339    for (Node* child : m_children)
340    {
341        child->calcScopeDepthFirst(outNodes);
342    }
343}
344
345void ScopeNode::dump(int indentCount, StringBuilder& out)
346{
347    dumpMarkup(indentCount, out);
348
349    _indent(indentCount, out);
350
351    switch (m_kind)
352    {
353    case Kind::AnonymousNamespace:
354        {
355            out << "namespace {\n";
356        }
357    case Kind::Namespace:
358        {
359            if (m_name.hasContent())
360            {
361                out << "namespace " << m_name.getContent() << " {\n";
362            }
363            else
364            {
365                out << "{\n";
366            }
367            break;
368        }
369    }
370
371    for (Node* child : m_children)
372    {
373        child->dump(indentCount + 1, out);
374    }
375
376    _indent(indentCount, out);
377    out << "}\n";
378}
379
380/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! EnumCaseNode !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
381
382/* Returns true if needs space between the tokens.
383It determines this based on the locs, and if they contain something between them.
384*/
385static bool _needsSpace(const Token& prevTok, const Token& tok)
386{
387    auto prevLoc = prevTok.getLoc();
388    auto loc = tok.getLoc();
389
390    auto prevContent = prevTok.getContent();
391
392    if (prevLoc + prevContent.getLength() == loc)
393    {
394        return false;
395    }
396
397    return true;
398}
399
400
401static void _dumpTokens(const Token* toks, Index count, StringBuilder& out)
402{
403    if (count > 0)
404    {
405        out << toks[0].getContent();
406
407        for (Index i = 1; i < count; ++i)
408        {
409            const auto& prevToken = toks[i - 1];
410            const auto& token = toks[i];
411
412            if (_needsSpace(prevToken, token))
413            {
414                out << " ";
415            }
416
417            out << token.getContent();
418        }
419    }
420}
421
422static void _dumpTokens(const List<Token>& toks, StringBuilder& out)
423{
424    _dumpTokens(toks.getBuffer(), toks.getCount(), out);
425}
426
427
428void EnumCaseNode::dump(int indent, StringBuilder& out)
429{
430    if (isReflected())
431    {
432        dumpMarkup(indent, out);
433
434        _indent(indent, out);
435        out << m_name.getContent();
436
437        if (m_valueTokens.getCount())
438        {
439            out << " = ";
440            _dumpTokens(m_valueTokens, out);
441        }
442
443        out << ",\n";
444    }
445}
446
447/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! EnumNode !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
448
449void TypeDefNode::dump(int indent, StringBuilder& out)
450{
451    if (isReflected())
452    {
453        dumpMarkup(indent, out);
454
455        _indent(indent, out);
456
457        out << "typedef ";
458        _dumpTokens(m_targetTypeTokens, out);
459        out << " " << m_name.getContent() << ";\n";
460    }
461}
462
463/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! EnumNode !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
464
465void EnumNode::dump(int indent, StringBuilder& out)
466{
467    if (!isReflected())
468    {
469        return;
470    }
471
472    dumpMarkup(indent, out);
473
474    _indent(indent, out);
475
476    out << "enum ";
477
478    if (m_kind == Kind::EnumClass)
479    {
480        out << "class ";
481    }
482
483    if (m_name.type != TokenType::Invalid)
484    {
485        out << m_name.getContent();
486    }
487
488    if (m_backingTokens.getCount() > 0)
489    {
490        out << " : ";
491        _dumpTokens(m_backingTokens, out);
492    }
493
494    out << "\n";
495    _indent(indent, out);
496    out << "{\n";
497
498    for (Node* child : m_children)
499    {
500        child->dump(indent + 1, out);
501    }
502
503    _indent(indent, out);
504    out << "}\n";
505}
506
507/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! CallableNode !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
508
509void CallableNode::dump(int indent, StringBuilder& out)
510{
511    if (!isReflected())
512    {
513        return;
514    }
515
516    dumpMarkup(indent, out);
517
518    _indent(indent, out);
519
520    if (m_isStatic)
521    {
522        out << "static ";
523    }
524    if (m_isVirtual)
525    {
526        out << "virtual ";
527    }
528
529    out << m_returnType << " ";
530    out << m_name.getContent() << "(";
531
532    const Index count = m_params.getCount();
533    for (Index i = 0; i < count; ++i)
534    {
535        if (i > 0)
536        {
537            out << ", ";
538        }
539
540        const auto& param = m_params[i];
541        out << param.m_type;
542        if (param.m_name.type == TokenType::Identifier)
543        {
544            out << " " << param.m_name.getContent();
545        }
546    }
547
548    out << ")";
549
550    if (m_isPure)
551    {
552        out << " = 0";
553    }
554
555    out << "\n";
556}
557
558/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! FieldNode !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
559
560void FieldNode::dump(int indent, StringBuilder& out)
561{
562    if (!isReflected())
563    {
564        return;
565    }
566
567    dumpMarkup(indent, out);
568
569    _indent(indent, out);
570
571    if (m_isStatic)
572    {
573        out << "static ";
574    }
575
576    out << m_fieldType << " " << m_name.getContent() << "\n";
577}
578
579/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ClassLikeNode !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
580
581/// Add a node that is derived from this
582void ClassLikeNode::addDerived(ClassLikeNode* derived)
583{
584    SLANG_ASSERT(derived->m_superNode == nullptr);
585    derived->m_superNode = this;
586    m_derivedTypes.add(derived);
587}
588
589void ClassLikeNode::calcDerivedDepthFirst(List<ClassLikeNode*>& outNodes)
590{
591    outNodes.add(this);
592    for (ClassLikeNode* derivedType : m_derivedTypes)
593    {
594        derivedType->calcDerivedDepthFirst(outNodes);
595    }
596}
597
598void ClassLikeNode::dumpDerived(int indentCount, StringBuilder& out)
599{
600    if (isClassLike() && isReflected() && m_name.hasContent())
601    {
602        _indent(indentCount, out);
603        out << m_name.getContent() << "\n";
604    }
605
606    for (ClassLikeNode* derivedType : m_derivedTypes)
607    {
608        derivedType->dumpDerived(indentCount + 1, out);
609    }
610}
611
612Index ClassLikeNode::calcDerivedDepth() const
613{
614    const ClassLikeNode* node = this;
615    Index count = 0;
616
617    while (node)
618    {
619        count++;
620        node = node->m_superNode;
621    }
622
623    return count;
624}
625
626ClassLikeNode* ClassLikeNode::findLastDerived()
627{
628    for (Index i = m_derivedTypes.getCount() - 1; i >= 0; --i)
629    {
630        ClassLikeNode* derivedType = m_derivedTypes[i];
631        ClassLikeNode* found = derivedType->findLastDerived();
632        if (found)
633        {
634            return found;
635        }
636    }
637    return this;
638}
639
640bool ClassLikeNode::hasReflectedDerivedType() const
641{
642    for (ClassLikeNode* type : m_derivedTypes)
643    {
644        if (type->isReflected())
645        {
646            return true;
647        }
648    }
649    return false;
650}
651
652void ClassLikeNode::getReflectedDerivedTypes(List<ClassLikeNode*>& out) const
653{
654    out.clear();
655    for (ClassLikeNode* type : m_derivedTypes)
656    {
657        if (type->isReflected())
658        {
659            out.add(type);
660        }
661    }
662}
663
664void ClassLikeNode::dump(int indentCount, StringBuilder& out)
665{
666    dumpMarkup(indentCount, out);
667
668    _indent(indentCount, out);
669
670    const char* typeName = (m_kind == Kind::StructType) ? "struct" : "class";
671
672    out << typeName << " ";
673
674    if (!isReflected())
675    {
676        out << " (";
677    }
678    out << m_name.getContent();
679    if (!isReflected())
680    {
681        out << ") ";
682    }
683
684    if (m_super.hasContent())
685    {
686        out << " : " << m_super.getContent();
687    }
688
689    out << " {\n";
690
691    for (Node* child : m_children)
692    {
693        child->dump(indentCount + 1, out);
694    }
695
696    _indent(indentCount, out);
697    out << "}\n";
698}
699
700} // namespace CppParse