GCC Code Coverage Report


Directory: src/
File: src/frontend/parse-result.cpp
Date: 2025-10-15 09:43:47
Exec Total Coverage
Lines: 59 182 32.4%
Functions: 13 21 61.9%
Branches: 11 46 23.9%

Line Branch Exec Source
1 #include <gyoji-frontend.hpp>
2 #include <gyoji.l.hpp>
3 #include <gyoji.y.hpp>
4 #include <gyoji-misc/jstring.hpp>
5
6 using namespace Gyoji::context;
7 using namespace Gyoji::frontend;
8 using namespace Gyoji::frontend::namespaces;
9 using namespace Gyoji::frontend::tree;
10
11 242 ParseResult::ParseResult(
12 Gyoji::context::CompilerContext & _compiler_context,
13 Gyoji::owned<NS2Context> _ns2_context
14 242 )
15 242 : compiler_context(_compiler_context)
16 242 , ns2_context(std::move(_ns2_context))
17 242 , translation_unit(nullptr)
18 242 {}
19 242 ParseResult::~ParseResult()
20 242 {}
21
22 const NS2Context &
23 48 ParseResult::get_ns2_context() const
24 {
25 48 return *ns2_context;
26 }
27
28 Errors &
29 6 ParseResult::get_errors() const
30 {
31 6 return compiler_context.get_errors();
32 }
33
34 const TranslationUnit &
35 200 ParseResult::get_translation_unit() const
36 {
37 200 return *translation_unit;
38 }
39 bool
40 48 ParseResult::has_translation_unit() const
41 48 { return translation_unit.get() != nullptr; }
42
43 bool
44 194 ParseResult::has_errors() const
45 {
46 194 return compiler_context.get_errors().size() != 0;
47 }
48
49 const TokenStream &
50 48 ParseResult::get_token_stream() const
51 {
52 48 return compiler_context.get_token_stream();
53 }
54 const Gyoji::context::CompilerContext &
55 ParseResult::get_compiler_context() const
56 { return compiler_context; }
57
58 void
59 240 ParseResult::set_translation_unit(Gyoji::owned<TranslationUnit> _translation_unit)
60 {
61 240 translation_unit = std::move(_translation_unit);
62 240 }
63
64 void
65 ParseResult::symbol_define(std::string _symbol, const SourceReference &src_ref)
66 {
67 Symbol symbol(_symbol, src_ref);
68 symbol_table.insert(std::pair(_symbol, symbol));
69 }
70
71 const Symbol *
72 ParseResult::symbol_get(std::string name) const
73 {
74 const auto & symbol = symbol_table.find(name);
75 if (symbol == symbol_table.end()) {
76 return nullptr;
77 }
78 return &symbol->second;
79 }
80
81
82 void
83 ParseResult::symbol_table_dump()
84 {
85 for (const auto & symbol : symbol_table) {
86 fprintf(stderr, "Symbol table %s\n", symbol.first.c_str());
87 }
88 }
89
90 const Symbol *
91 ParseResult::symbol_get_or_create(std::string symbol_name, const SourceReference & src_ref)
92 {
93 const Symbol *found = symbol_get(symbol_name);
94 if (found) return found;
95
96 symbol_define(symbol_name, src_ref);
97 return symbol_get(symbol_name);
98
99 }
100
101 NS2Entity *
102 5860 ParseResult::identifier_get_or_create(
103 std::string name,
104 bool allow_placement_in_namespace,
105 const SourceReference & _source_ref
106 )
107 {
108 // Check to see if we already have this as an identifier.
109 // If so, just go with it.
110 5860 NS2Entity *entity = ns2_context->namespace_find(name);
111
2/2
✓ Branch 0 taken 3130 times.
✓ Branch 1 taken 2730 times.
5860 if (entity != nullptr) {
112
1/2
✓ Branch 1 taken 3130 times.
✗ Branch 2 not taken.
3130 if (entity->get_type() == NS2Entity::ENTITY_TYPE_IDENTIFIER) {
113 3130 return entity;
114 }
115 auto error = std::make_unique<Gyoji::context::Error>(std::string("Identifier ") + name + std::string(" is ambiguous"));
116 error->add_message(_source_ref,
117 std::string("Identifier ") + name + std::string(" was declared as a different type of identifier."));
118 error->add_message(entity->get_source_ref(),
119 std::string("First declared here"));
120 compiler_context.get_errors().add_error(std::move(error));
121 return nullptr;
122 }
123
124 // Is this a simple name? If so, go ahead and define
125 // it in the current namespace.
126 2730 std::vector<std::string> name_components = Gyoji::misc::string_split(name, NS2Context::NAMESPACE_DELIMITER);
127
1/2
✓ Branch 1 taken 2730 times.
✗ Branch 2 not taken.
2730 if (name_components.size() == 1) {
128 2730 entity = ns2_context->get_current()->add_identifier(
129 name,
130 _source_ref
131 );
132 2730 return entity;
133 }
134 // Next, try to identify the namespace
135 // it's declared in, then try to define
136 // it inside that namespace (if we're allowed it).
137
138 #if 0
139 if (!allow_placement_in_namespace) {
140 auto error = std::make_unique<Gyoji::context::Error>(std::string("Invalid identifier ") + name + std::string("."));
141 error->add_message(_source_ref, std::string("Identifier must be a simple identifier ") + name + std::string(" and must not contain '::'."));
142 compiler_context.get_errors().add_error(std::move(error));
143 return nullptr;
144 }
145 else {
146 #endif
147 std::string simple_name = name_components.at(name_components.size()-1);
148 name_components.pop_back();
149 std::string namespace_part = Gyoji::misc::join(name_components, NS2Context::NAMESPACE_DELIMITER);
150
151 NS2Entity *namespace_entity = ns2_context->namespace_find(namespace_part);
152 if (namespace_entity == nullptr) {
153 auto error = std::make_unique<Gyoji::context::Error>(std::string("Invalid identifier") + name + std::string("."));
154 error->add_message(_source_ref, std::string("") + namespace_part + std::string(" is not a class or namespace."));
155 compiler_context.get_errors().add_error(std::move(error));
156 return nullptr;
157 }
158 if (namespace_entity->get_type() == NS2Entity::ENTITY_TYPE_NAMESPACE ||
159 namespace_entity->get_type() == NS2Entity::ENTITY_TYPE_CLASS) {
160 fprintf(stderr, "Namespace was found and is a namespace or class\n");
161 return namespace_entity->add_identifier(simple_name, _source_ref);
162 }
163 else {
164 fprintf(stderr, "Namespace was found but was not suitable to hold our child\n");
165 auto error = std::make_unique<Gyoji::context::Error>(std::string("Invalid identifier") + name + std::string("."));
166 error->add_message(_source_ref, std::string("Identifier must ") + name + std::string(" must be placed inside a namespace or class."));
167 error->add_message(namespace_entity->get_source_ref(), std::string("Namespace is ") + namespace_part + std::string(" is not a namespace or class"));
168 compiler_context.get_errors().add_error(std::move(error));
169 return nullptr;
170 }
171 #if 0
172 }
173 #endif
174 2730 }
175
176 NS2Entity *
177 118 ParseResult::namespace_get_or_create(
178 std::string name,
179 const Gyoji::context::SourceReference & _source_ref
180 )
181 {
182 // The _name might be a composite name, so we need to split it and handle
183 // each component separately as its own namespace.
184 118 std::vector<std::string> name_components = Gyoji::misc::string_split(name, NS2Context::NAMESPACE_DELIMITER);
185
186 // For each component, first try to find it
187 // as an entity or namespace name.
188 118 NS2Entity *current = ns2_context->get_current();
189
2/2
✓ Branch 5 taken 118 times.
✓ Branch 6 taken 118 times.
236 for (const std::string & name : name_components) {
190 // So what can happen is we have an enitity that is like a class
191 // that is an entity but also a namespace of the same name
192 // containing other things. But if that happens, we can't define
193 // it this way through a 'namespace' statement, so it's correct
194 // to discard it this way.
195
196 118 NS2Entity *entity = current->get_entity(name);
197
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 118 times.
118 if (entity != nullptr) {
198 if (entity->get_type() != NS2Entity::ENTITY_TYPE_NAMESPACE) {
199 auto error = std::make_unique<Gyoji::context::Error>(std::string("Invalid identifier") + name + std::string("."));
200 error->add_message(_source_ref, std::string("Namespace ") + name + std::string(" must be placed inside another namespace or at the root."));
201 error->add_message(entity->get_source_ref(), std::string("Identifier ") + name + std::string(" is not a namespace"));
202 compiler_context.get_errors().add_error(std::move(error));
203 return nullptr;
204 }
205 current = entity;
206 }
207 else {
208 118 NS2Entity* newcurrent = current->add_namespace(name, _source_ref);
209 118 current = newcurrent;
210 }
211 }
212 118 return current;
213
214 118 }
215
216 NS2Entity*
217 248 ParseResult::type_get_or_create(
218 std::string name,
219 const Gyoji::context::SourceReference & _source_ref
220 )
221 {
222 // Check to see if we already have this as an identifier.
223 // If so, just go with it.
224 248 NS2Entity *entity = ns2_context->namespace_find(name);
225
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 248 times.
248 if (entity != nullptr) {
226 if (entity->get_type() == NS2Entity::ENTITY_TYPE_TYPE) {
227 return entity;
228 }
229 auto error = std::make_unique<Gyoji::context::Error>(std::string("Type name ") + name + std::string(" is ambiguous"));
230 error->add_message(_source_ref,
231 std::string("Identifier ") + name + std::string(" was declared as a different type of identifier."));
232 error->add_message(entity->get_source_ref(),
233 std::string("First declared here"));
234 compiler_context.get_errors().add_error(std::move(error));
235 return nullptr;
236 }
237
238 248 std::vector<std::string> name_components = Gyoji::misc::string_split(name, NS2Context::NAMESPACE_DELIMITER);
239
1/2
✓ Branch 1 taken 248 times.
✗ Branch 2 not taken.
248 if (name_components.size() == 1) {
240 248 entity = ns2_context->get_current()->add_type(
241 name,
242 _source_ref
243 );
244 248 return entity;
245 }
246
247 std::string simple_name = name_components.at(name_components.size()-1);
248 name_components.pop_back();
249 std::string namespace_part = Gyoji::misc::join(name_components, NS2Context::NAMESPACE_DELIMITER);
250
251 NS2Entity *namespace_entity = ns2_context->namespace_find(namespace_part);
252 if (namespace_entity == nullptr) {
253 auto error = std::make_unique<Gyoji::context::Error>(std::string("Invalid identifier") + name + std::string("."));
254 error->add_message(_source_ref, std::string("") + namespace_part + std::string(" is not a class or namespace."));
255 compiler_context.get_errors().add_error(std::move(error));
256 return nullptr;
257 }
258 if (namespace_entity->get_type() == NS2Entity::ENTITY_TYPE_NAMESPACE) {
259 return namespace_entity->add_class(simple_name, _source_ref);
260 }
261 else {
262 auto error = std::make_unique<Gyoji::context::Error>(std::string("Invalid identifier") + name + std::string("."));
263 error->add_message(_source_ref, std::string("Identifier must ") + name + std::string(" must be placed inside a namespace."));
264 error->add_message(namespace_entity->get_source_ref(), std::string("Namespace is ") + namespace_part + std::string(" is not a namespace"));
265 compiler_context.get_errors().add_error(std::move(error));
266 return nullptr;
267 }
268 248 }
269
270 NS2Entity*
271 138 ParseResult::class_get_or_create(
272 std::string name,
273 const Gyoji::context::SourceReference & _source_ref
274 )
275 {
276 // Check to see if we already have this as an identifier.
277 // If so, just go with it.
278 138 NS2Entity *entity = ns2_context->namespace_find(name);
279
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 138 times.
138 if (entity != nullptr) {
280 if (entity->get_type() == NS2Entity::ENTITY_TYPE_CLASS) {
281 return entity;
282 }
283 auto error = std::make_unique<Gyoji::context::Error>(std::string("Class name ") + name + std::string(" is ambiguous"));
284 error->add_message(_source_ref,
285 std::string("Identifier ") + name + std::string(" was declared as a different type of identifier."));
286 error->add_message(entity->get_source_ref(),
287 std::string("First declared here"));
288 compiler_context.get_errors().add_error(std::move(error));
289 return nullptr;
290 }
291
292 138 std::vector<std::string> name_components = Gyoji::misc::string_split(name, NS2Context::NAMESPACE_DELIMITER);
293
1/2
✓ Branch 1 taken 138 times.
✗ Branch 2 not taken.
138 if (name_components.size() == 1) {
294 138 entity = ns2_context->get_current()->add_class(
295 name,
296 _source_ref
297 );
298 138 return entity;
299 }
300
301 std::string simple_name = name_components.at(name_components.size()-1);
302 name_components.pop_back();
303 std::string namespace_part = Gyoji::misc::join(name_components, NS2Context::NAMESPACE_DELIMITER);
304
305 NS2Entity *namespace_entity = ns2_context->namespace_find(namespace_part);
306 if (namespace_entity == nullptr) {
307 auto error = std::make_unique<Gyoji::context::Error>(std::string("Invalid identifier") + name + std::string("."));
308 error->add_message(_source_ref, std::string("") + namespace_part + std::string(" is not a class or namespace."));
309 compiler_context.get_errors().add_error(std::move(error));
310 return nullptr;
311 }
312 if (namespace_entity->get_type() == NS2Entity::ENTITY_TYPE_NAMESPACE) {
313 return namespace_entity->add_class(simple_name, _source_ref);
314 }
315 else {
316 auto error = std::make_unique<Gyoji::context::Error>(std::string("Invalid identifier") + name + std::string("."));
317 error->add_message(_source_ref, std::string("Identifier must ") + name + std::string(" must be placed inside a namespace."));
318 error->add_message(namespace_entity->get_source_ref(), std::string("Namespace is ") + namespace_part + std::string(" is not a namespace"));
319 compiler_context.get_errors().add_error(std::move(error));
320 return nullptr;
321 }
322 138 }
323
324
325 ///////////////////////////////////////////////////
326 // Symbol
327 ///////////////////////////////////////////////////
328
329 Symbol::Symbol(std::string _name, const SourceReference & _src_ref)
330 : name(_name)
331 , src_ref(_src_ref)
332 {}
333 Symbol::~Symbol()
334 {}
335 Symbol::Symbol(const Symbol & _other)
336 : name(_other.name)
337 , src_ref(_other.src_ref)
338 {}
339