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 |