GCC Code Coverage Report


Directory: src/
File: src/frontend/ns2.cpp
Date: 2025-10-15 09:43:47
Exec Total Coverage
Lines: 171 193 88.6%
Functions: 26 29 89.7%
Branches: 38 46 82.6%

Line Branch Exec Source
1 #include <gyoji-frontend/ns2.hpp>
2 #include <gyoji-misc/jstring.hpp>
3
4 const std::string Gyoji::frontend::namespaces::NS2Context::NAMESPACE_DELIMITER("::");
5
6 using namespace Gyoji::frontend::namespaces;
7
8
9 ///////////////////////////////////////////////////
10 // NS2Entity
11 ///////////////////////////////////////////////////
12 7004 NS2Entity::NS2Entity(
13 std::string _name,
14 EntityType _type,
15 NS2Entity* _parent,
16 const Gyoji::context::SourceReference & _source_ref
17 7004 )
18 7004 : name(_name)
19 7004 , type(_type)
20 7004 , parent(_parent)
21 7004 , source_ref(_source_ref)
22 7004 {}
23
24 7004 NS2Entity::~NS2Entity()
25 7004 {}
26
27 const std::string &
28 10022 NS2Entity::get_name() const
29 10022 { return name;}
30
31 std::string
32 6988 NS2Entity::get_fully_qualified_name() const
33 {
34 6988 std::string ret_string;
35
2/2
✓ Branch 0 taken 528 times.
✓ Branch 1 taken 6460 times.
6988 if (parent == nullptr) {
36 // If our parent is null, we are the root
37 // namespace, so our name is empty.
38 1056 return std::string("");
39 }
40
2/2
✓ Branch 0 taken 1426 times.
✓ Branch 1 taken 5034 times.
6460 if (parent->parent != nullptr) {
41 // If our parent is not the root, we can ask for its name also.
42 1426 return parent->get_fully_qualified_name() + NS2Context::NAMESPACE_DELIMITER + get_name();
43 }
44 else {
45 5034 return get_name();
46 }
47 6988 }
48
49
50 const NS2Entity::EntityType &
51 22346 NS2Entity::get_type() const
52 22346 { return type; }
53
54 const Gyoji::context::SourceReference &
55 NS2Entity::get_source_ref() const
56 { return source_ref; }
57
58 NS2Entity*
59 2730 NS2Entity::add_identifier(
60 std::string _name,
61 const Gyoji::context::SourceReference & _source_ref
62 )
63 {
64 2730 const auto & it = elements.find(_name);
65
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 2730 times.
2730 if (it != elements.end()) {
66 fprintf(stderr, "Identifier already defined in namespace %s\n", _name.c_str());
67 return nullptr;
68 }
69
70 2730 Gyoji::owned<NS2Entity> entity = std::make_unique<NS2Entity>(_name, NS2Entity::ENTITY_TYPE_IDENTIFIER, this, _source_ref);
71 2730 NS2Entity *ret = entity.get();
72 2730 elements.insert(std::pair(_name, std::move(entity)));
73 2730 return ret;
74 2730 }
75
76 NS2Entity*
77 3728 NS2Entity::add_type(
78 std::string _name,
79 const Gyoji::context::SourceReference & _source_ref
80 )
81 {
82 3728 const auto & it = elements.find(_name);
83
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 3728 times.
3728 if (it != elements.end()) {
84 fprintf(stderr, "Identifier already defined in namespace %s\n", _name.c_str());
85 return nullptr;
86 }
87
88 3728 Gyoji::owned<NS2Entity> entity = std::make_unique<NS2Entity>(_name, NS2Entity::ENTITY_TYPE_TYPE, this, _source_ref);
89 3728 NS2Entity *ret = entity.get();
90 3728 elements.insert(std::pair(_name, std::move(entity)));
91 3728 return ret;
92 3728 }
93
94 NS2Entity*
95 138 NS2Entity::add_class(
96 std::string _name,
97 const Gyoji::context::SourceReference & _source_ref
98 )
99 {
100 138 const auto & it = elements.find(_name);
101
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 138 times.
138 if (it != elements.end()) {
102 fprintf(stderr, "Identifier already defined in namespace %s\n", _name.c_str());
103 return nullptr;
104 }
105 138 Gyoji::owned<NS2Entity> entity = std::make_unique<NS2Entity>(_name, NS2Entity::ENTITY_TYPE_CLASS, this, _source_ref);
106 138 NS2Entity *ret = entity.get();
107 138 elements.insert(std::pair(_name, std::move(entity)));
108 138 return ret;
109 138 }
110
111 NS2Entity*
112 118 NS2Entity::add_namespace(
113 std::string _namespace,
114 const Gyoji::context::SourceReference & _source_ref
115 )
116 {
117 118 Gyoji::owned<NS2Entity> entity = std::make_unique<NS2Entity>(_namespace, NS2Entity::ENTITY_TYPE_NAMESPACE, this, _source_ref);
118 118 NS2Entity *ret = entity.get();
119 118 elements.insert(std::pair(_namespace, std::move(entity)));
120 236 return ret;
121 118 }
122
123 NS2Entity *
124 27580 NS2Entity::get_entity(std::string _name) const
125 {
126 27580 const auto & it = elements.find(_name);
127
2/2
✓ Branch 2 taken 17506 times.
✓ Branch 3 taken 10074 times.
27580 if (it == elements.end()) {
128 17506 return nullptr;
129 }
130 10074 return it->second.get();
131 }
132
133 NS2Entity*
134 NS2Entity::add_entity(std::string _name, Gyoji::owned<NS2Entity> _entity)
135 {
136 NS2Entity *ret = _entity.get();
137 elements.insert(std::pair(_name, std::move(_entity)));
138 return ret;
139 }
140
141 NS2Entity *
142 532 NS2Entity::get_parent() const
143 532 { return parent; }
144
145 void
146 104 NS2Entity::dump(int indent) const
147 {
148 208 std::string pad(indent*8, ' ');
149 208 std::string pad2((indent+1)*8, ' ');
150 208 std::string start = pad + std::string("{");
151 104 std::string end = pad + std::string("}");
152 104 fprintf(stderr, "%s\n", start.c_str());
153
2/2
✓ Branch 5 taken 860 times.
✓ Branch 6 taken 104 times.
964 for (const auto & el : elements) {
154 860 std::string name = el.first;
155 860 const NS2Entity *entity = el.second.get();
156
157 860 std::string typestr;
158
4/6
✓ Branch 1 taken 172 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 632 times.
✓ Branch 4 taken 30 times.
✓ Branch 5 taken 26 times.
✗ Branch 6 not taken.
860 switch (entity->get_type()) {
159 172 case NS2Entity::ENTITY_TYPE_IDENTIFIER:
160 172 typestr = " identifier";
161 172 break;
162 case NS2Entity::ENTITY_TYPE_LABEL:
163 typestr = " label";
164 break;
165 632 case NS2Entity::ENTITY_TYPE_TYPE:
166 632 typestr = " type";
167 632 break;
168 30 case NS2Entity::ENTITY_TYPE_CLASS:
169 30 typestr = " class";
170 30 break;
171 26 case NS2Entity::ENTITY_TYPE_NAMESPACE:
172 26 typestr = " namespace";
173 26 break;
174 }
175 1720 std::string entity_desc = pad2 + name + typestr;
176 860 fprintf(stderr, "%s\n", entity_desc.c_str());
177
4/4
✓ Branch 1 taken 830 times.
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 56 times.
✓ Branch 4 taken 804 times.
1690 if (entity->get_type() == NS2Entity::ENTITY_TYPE_CLASS ||
178
2/2
✓ Branch 1 taken 26 times.
✓ Branch 2 taken 804 times.
830 entity->get_type() == NS2Entity::ENTITY_TYPE_NAMESPACE) {
179 56 entity->dump(indent+1);
180 }
181 860 }
182 104 fprintf(stderr, "%s\n", end.c_str());
183 104 }
184
185 ///////////////////////////////////////////////////
186 // NS2Context
187 ///////////////////////////////////////////////////
188 1260 NS2SearchPaths::NS2SearchPaths()
189 1260 {}
190
191 1260 NS2SearchPaths::~NS2SearchPaths()
192 1260 {}
193
194 void
195 46 NS2SearchPaths::add_using(std::string name, NS2Entity *alias)
196 {
197 46 aliases.push_back(std::pair(name, alias));
198 46 alias_map.insert(std::pair(name, alias));
199 46 }
200
201 NS2Entity *
202 NS2SearchPaths::get_name(std::string name)
203 {
204 const auto & it = alias_map.find(name);
205 if (it == alias_map.end()) {
206 return nullptr;
207 }
208 return it->second;
209 }
210
211 const std::vector<std::pair<std::string, NS2Entity*>> &
212 16708 NS2SearchPaths::get_aliases() const
213 16708 { return aliases; }
214
215 ///////////////////////////////////////////////////
216 // NS2Context
217 ///////////////////////////////////////////////////
218
219 static std::string internal_filename("builtin");
220 static const Gyoji::context::SourceReference zero_source_ref(internal_filename, 1, 0, 0);
221
222 290 NS2Context::NS2Context()
223 290 : root(std::make_unique<NS2Entity>(
224 "root",
225 580 NS2Entity::ENTITY_TYPE_NAMESPACE,
226 290 nullptr,
227 zero_source_ref
228 )
229 290 )
230 {
231 290 Gyoji::owned<NS2SearchPaths> search_paths = std::make_unique<NS2SearchPaths>();
232 290 stack.push_back(std::pair(root.get(), std::move(search_paths)));
233
234 580 root->add_type("i8", zero_source_ref);
235 580 root->add_type("i16", zero_source_ref);
236 580 root->add_type("i32", zero_source_ref);
237 580 root->add_type("i64", zero_source_ref);
238
239 580 root->add_type("u8", zero_source_ref);
240 580 root->add_type("u16", zero_source_ref);
241 580 root->add_type("u32", zero_source_ref);
242 580 root->add_type("u64", zero_source_ref);
243
244 580 root->add_type("f32", zero_source_ref);
245 580 root->add_type("f64", zero_source_ref);
246
247 580 root->add_type("void", zero_source_ref);
248 580 root->add_type("bool", zero_source_ref);
249 290 }
250
251 290 NS2Context::~NS2Context()
252 290 {}
253
254 // We're going to search for an entity in
255 // the current namespace context.
256 //void
257 //NS2Context::find_entity(std::string _name)
258 //{
259 //}
260 //
261 // We are going to define a type or identifier
262 // in the current namespace. This would be like 'class Foo' or 'typedef u8 bar'.
263 //NS2Context::new_entity();
264
265 // We are now adding a namespace to the list of
266 // namespaces we want to search.
267 void
268 46 NS2Context::namespace_using(std::string name, NS2Entity* alias)
269 {
270 46 const auto & b = stack.back();
271 46 b.second->add_using(name, alias);
272 46 }
273
274 NS2Entity*
275 27244 NS2Context::namespace_find_in(NS2Entity* current, std::string _name) const
276 {
277 27244 std::vector<std::string> name_components = Gyoji::misc::string_split(_name, NAMESPACE_DELIMITER);
278 // This is the point where we might insert
279 // our aliases to search for them under different
280 // names.
281 27244 return namespace_find_in(current, name_components);
282 27244 }
283
284 NS2Entity *
285 27244 NS2Context::namespace_find_in(NS2Entity* current, std::vector<std::string> names) const
286 {
287 27244 NS2Entity *entity_found = nullptr;
288
289 //dump();
290
291 // First, look in the current namespace
292 // for the first component of the name.
293 27244 size_t i = 0;
294 while (true) {
295 27462 entity_found = current->get_entity(names.at(i));
296
2/2
✓ Branch 1 taken 27074 times.
✓ Branch 2 taken 388 times.
27462 if (i == names.size()-1) {
297 27074 break;
298 }
299
2/2
✓ Branch 0 taken 170 times.
✓ Branch 1 taken 218 times.
388 if (entity_found == nullptr) {
300 170 break;
301 }
302 // We have another parent to search, so try that.
303 218 current = entity_found;
304 218 i++;
305 }
306 27244 return entity_found;
307 }
308
309 NS2Entity*
310 17368 NS2Context::namespace_find(std::string name) const
311 {
312 // Iterate the stack in reverse order,
313 // searching at each level.
314
2/2
✓ Branch 1 taken 26520 times.
✓ Branch 2 taken 7512 times.
34032 for (size_t i = 0; i < stack.size(); i++) {
315 26520 const auto & it = stack.at(stack.size() - 1 - i);
316 // First, check to see if we can find it in the namespace
317 // we're currently operating on.
318 26520 NS2Entity *found = namespace_find_in(it.first, name);
319
2/2
✓ Branch 0 taken 9812 times.
✓ Branch 1 taken 16708 times.
26520 if (found != nullptr) {
320 9812 return found;
321 }
322
323 // Now, try finding the thing in
324 // any relevant alias namespaces from 'using' clauses.
325
2/2
✓ Branch 7 taken 724 times.
✓ Branch 8 taken 16664 times.
17388 for (const auto & alias : it.second->get_aliases()) {
326 724 std::string aliasname;
327
2/2
✓ Branch 1 taken 190 times.
✓ Branch 2 taken 534 times.
724 if (alias.first.size() > 0) {
328 380 aliasname = Gyoji::misc::string_replace_start(name, alias.first + NS2Context::NAMESPACE_DELIMITER, "");
329 }
330 else {
331 534 aliasname = name;
332 }
333 724 found = namespace_find_in(alias.second, aliasname);
334
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 680 times.
724 if (found != nullptr) {
335 44 return found;
336 }
337
2/2
✓ Branch 1 taken 680 times.
✓ Branch 2 taken 44 times.
724 }
338 }
339 7512 return nullptr;
340 }
341
342 NS2Entity *
343 3234 NS2Context::get_current() const
344 3234 { return stack.back().first; }
345
346 // Enter the given namespace
347 // so that new declarations will
348 // appear in this namespace
349 void
350 970 NS2Context::namespace_push(NS2Entity *ns)
351 {
352 // We are now in the context of this
353 // namespace with our own search path.
354 970 Gyoji::owned<NS2SearchPaths> search_paths = std::make_unique<NS2SearchPaths>();
355 970 stack.push_back(
356 1940 std::pair(
357 ns,
358 970 std::move(search_paths)
359 )
360 );
361 970 }
362
363 void
364 970 NS2Context::namespace_pop()
365 {
366 // Assertion to protect us from popping the end of
367 // the stack.
368
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 970 times.
970 if (stack.size() == 1) {
369 char *p = (char*)0;
370 *p = 0x02;
371 }
372 970 stack.pop_back();
373 970 }
374
375 void
376 48 NS2Context::dump() const
377 {
378 48 root->dump(0);
379 48 }
380
381
382
383 // Scenario:
384 // namespace foo::bar {
385 //
386 // In this scenario, we create foo and bar as namespaces
387 // inside the current namespace.
388 // We also push the namespace resolution context to resolve
389 // first from this new namespace 'bar' and then
390 // from the parents of that namespace.
391 // Any 'using namespace' statements add to the current resolution
392 // context.
393
394 // Scenario:
395 // }
396 //
397 // In this scenario, we pop the namespace 'bar' we just pushed
398 // and we also pop the 'using' statements. Future declarations
399 // will go back into the root namespace. Lookups will happen
400 // in the context of whatever 'using' were in effect before
401 // the push. Qualified resolutions will happen relative to
402 // the current namespace or 'root' if not found there.
403
404 // Scenario:
405 // void foo();
406 //
407 // We look for an existing declaration of 'foo' in the current namespace.
408 // If it already exists, we throw an error.
409
410 // Scenario:
411 // void foo() {
412 //
413 // 1) We look for an existing declaration 'foo' in the
414 // current namespace resolution context. If found, we resolve
415 // 'foo' to that name. If more than one found, we
416 // throw an error. If none found, we declare in current namespace.
417 //
418 // Scenario
419 // class Foo {
420 // void foo();
421 // }
422 //
423 // We define 'Foo' as a class in the current namespace.
424 // We enter that namespace context.
425 // We define 'foo' inside the 'Foo' namespace.
426
427 // Scenario:
428 // Foo::foo();
429 // We look for 'Foo' in the current namespace
430 // resolution context. If found as a NS, if it is a
431 // namespace, we look for 'Foo::foo()' declared
432 // inside it. If found as a class, we look for 'foo'
433 // declared inside it.
434
435