GCC Code Coverage Report


Directory: src/
File: src/frontend/parse-result.cpp
Date: 2025-10-24 11:14:59
Exec Total Coverage
Lines: 68 182 37.4%
Functions: 13 21 61.9%
Branches: 16 46 34.8%

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