TextMateLib 1.0
Modern C++ implementation of the TextMate syntax highlighting engine
Loading...
Searching...
No Matches
grammarDependencies.cpp
1#include "grammarDependencies.h"
2#include "registry.h"
3#include <iostream>
4#include <set>
5
6namespace tml {
7
8// Helper to collect external references from rules
9static void collectExternalReferencesInRules(
10 const std::vector<IRawRule*>& rules,
11 IRawGrammar* baseGrammar,
12 IRawGrammar* selfGrammar,
13 std::vector<AbsoluteRuleReference>& result,
14 std::set<IRawRule*>& visitedRules
15);
16
17// Helper to collect references in a single rule
18static void collectExternalReferencesInRule(
19 IRawRule* rule,
20 IRawGrammar* baseGrammar,
21 IRawGrammar* selfGrammar,
22 std::vector<AbsoluteRuleReference>& result,
23 std::set<IRawRule*>& visitedRules
24) {
25 if (!rule || visitedRules.find(rule) != visitedRules.end()) {
26 return;
27 }
28 visitedRules.insert(rule);
29
30 // Check if rule has an include first
31 if (rule->include && !rule->include->empty()) {
32 IncludeReference ref = parseInclude(*rule->include);
33
34 if (ref.kind == IncludeReferenceKind::TopLevelReference) {
35 // External grammar reference like "source.c"
36 if (ref.scopeName != selfGrammar->scopeName && ref.scopeName != baseGrammar->scopeName) {
37 result.push_back(AbsoluteRuleReference(ref.scopeName, ""));
38 }
39 } else if (ref.kind == IncludeReferenceKind::TopLevelRepositoryReference) {
40 // External grammar repository reference like "source.c#ruleName"
41 if (ref.scopeName != selfGrammar->scopeName && ref.scopeName != baseGrammar->scopeName) {
42 result.push_back(AbsoluteRuleReference(ref.scopeName, ref.ruleName));
43 }
44 } else if (ref.kind == IncludeReferenceKind::RelativeReference) {
45 // Local repository reference like "#ruleName" - need to look it up and scan it
46 if (selfGrammar->repository) {
47 IRawRule* referencedRule = selfGrammar->repository->getRule(ref.ruleName);
48 if (referencedRule) {
49 collectExternalReferencesInRule(referencedRule, baseGrammar, selfGrammar, result, visitedRules);
50 }
51 }
52 }
53 }
54
55 // Recursively check if rule has patterns (IMPORTANT: this finds includes in nested rules)
56 if (rule->patterns && !rule->patterns->empty()) {
57 collectExternalReferencesInRules(*rule->patterns, baseGrammar, selfGrammar, result, visitedRules);
58 }
59}
60
61static void collectExternalReferencesInRules(
62 const std::vector<IRawRule*>& rules,
63 IRawGrammar* baseGrammar,
64 IRawGrammar* selfGrammar,
65 std::vector<AbsoluteRuleReference>& result,
66 std::set<IRawRule*>& visitedRules
67) {
68 for (IRawRule* rule : rules) {
69 collectExternalReferencesInRule(rule, baseGrammar, selfGrammar, result, visitedRules);
70 }
71}
72
73IncludeReference parseInclude(const std::string& include) {
74 if (include == "$base" || include == "$self") {
75 return IncludeReference(
76 include == "$base" ? IncludeReferenceKind::Base : IncludeReferenceKind::Self
77 );
78 }
79
80 if (include[0] == '#') {
81 // Relative reference: #ruleName
82 return IncludeReference(
83 IncludeReferenceKind::RelativeReference,
84 "",
85 include.substr(1)
86 );
87 }
88
89 size_t sharpIndex = include.find('#');
90 if (sharpIndex != std::string::npos) {
91 // Top level repository reference: scopeName#ruleName
92 return IncludeReference(
93 IncludeReferenceKind::TopLevelRepositoryReference,
94 include.substr(0, sharpIndex),
95 include.substr(sharpIndex + 1)
96 );
97 }
98
99 // Top level reference: scopeName
100 return IncludeReference(
101 IncludeReferenceKind::TopLevelReference,
102 include,
103 ""
104 );
105}
106
107ScopeDependencyProcessor::ScopeDependencyProcessor(SyncRegistry* repo, const std::string& initialScopeName)
108 : _repo(repo), _initialScopeName(initialScopeName) {
109 _seenScopes.insert(initialScopeName);
110 Q.push(AbsoluteRuleReference(initialScopeName, ""));
111}
112
113void ScopeDependencyProcessor::processQueue() {
114 // Process all items in the queue and collect their external dependencies
115 std::queue<AbsoluteRuleReference> currentQ;
116 currentQ.swap(Q);
117
118
119 std::vector<AbsoluteRuleReference> externalRefs;
120 std::set<IRawRule*> visitedRules;
121
122 while (!currentQ.empty()) {
123 AbsoluteRuleReference ref = currentQ.front();
124 currentQ.pop();
125
126 // Look up the grammar for this reference
127 IRawGrammar* grammar = _repo->lookup(ref.scopeName);
128 if (!grammar) {
129 continue;
130 }
131
132
133 // Collect external references from this grammar's patterns
134 if (grammar->patterns && !grammar->patterns->empty()) {
135 collectExternalReferencesInRules(*grammar->patterns, grammar, grammar, externalRefs, visitedRules);
136 }
137
138 // Also scan injections if present
139 if (grammar->injections) {
140 for (const auto& injection : *grammar->injections) {
141 if (injection.second->patterns) {
142 collectExternalReferencesInRules(*injection.second->patterns, grammar, grammar, externalRefs, visitedRules);
143 }
144 }
145 }
146 }
147
148
149 // Add new external references to the queue if not seen before
150 for (const AbsoluteRuleReference& extRef : externalRefs) {
151 std::string key = extRef.scopeName;
152 if (!extRef.ruleName.empty()) {
153 key += "#" + extRef.ruleName;
154 }
155
156
157 if (_seenScopes.find(key) == _seenScopes.end()) {
158 _seenScopes.insert(key);
159 Q.push(extRef);
160 } else {
161 }
162 }
163
164}
165
166} // namespace tml