| 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/type-lowering.hpp> | ||
| 16 | #include <variant> | ||
| 17 | #include <stdio.h> | ||
| 18 | #include <gyoji-misc/jstring.hpp> | ||
| 19 | |||
| 20 | using namespace Gyoji::mir; | ||
| 21 | using namespace Gyoji::context; | ||
| 22 | using namespace Gyoji::frontend::tree; | ||
| 23 | using namespace Gyoji::frontend::lowering; | ||
| 24 | using namespace Gyoji::frontend::namespaces; | ||
| 25 | |||
| 26 | 30 | TypeLowering::TypeLowering( | |
| 27 | Gyoji::context::CompilerContext & _compiler_context, | ||
| 28 | const Gyoji::frontend::tree::TranslationUnit & _translation_unit, | ||
| 29 | 30 | Gyoji::mir::MIR & _mir) | |
| 30 | 30 | : mir(_mir) | |
| 31 | 30 | , compiler_context(_compiler_context) | |
| 32 | 30 | , translation_unit(_translation_unit) | |
| 33 | 30 | {} | |
| 34 | 30 | TypeLowering::~TypeLowering() | |
| 35 | 30 | {} | |
| 36 | |||
| 37 | 30 | void TypeLowering::lower() | |
| 38 | { | ||
| 39 | // To resolve the types, we need only iterate the | ||
| 40 | // input parse tree and pull out any type declarations, | ||
| 41 | // resolving them down to their primitive types. | ||
| 42 | 30 | extract_types(translation_unit.get_statements()); | |
| 43 | 30 | } | |
| 44 | |||
| 45 | void | ||
| 46 | 8 | TypeLowering::extract_from_class_declaration(const ClassDeclaration & declaration) | |
| 47 | { | ||
| 48 | Gyoji::owned<Type> type = std::make_unique<Type>( | ||
| 49 | 8 | declaration.get_fully_qualified_name(), | |
| 50 | 16 | Type::TYPE_COMPOSITE, | |
| 51 | 8 | false, | |
| 52 | 16 | declaration.get_name_source_ref()); | |
| 53 | 8 | mir.get_types().define_type(std::move(type)); | |
| 54 | 8 | } | |
| 55 | |||
| 56 | Type * | ||
| 57 | 336 | TypeLowering::get_or_create(std::string pointer_name, Type::TypeType type_type, bool complete, const SourceReference & source_ref) | |
| 58 | { | ||
| 59 | 336 | Type *pointer_type = mir.get_types().get_type(pointer_name); | |
| 60 |
2/2✓ Branch 0 taken 214 times.
✓ Branch 1 taken 122 times.
|
336 | if (pointer_type != nullptr) { |
| 61 | 214 | return pointer_type; | |
| 62 | } | ||
| 63 | else { | ||
| 64 | 122 | Gyoji::owned<Type> pointer_type_created = std::make_unique<Type>(pointer_name, type_type, complete, source_ref); | |
| 65 | 122 | pointer_type = pointer_type_created.get(); | |
| 66 | 122 | mir.get_types().define_type(std::move(pointer_type_created)); | |
| 67 | 122 | return pointer_type; | |
| 68 | 122 | } | |
| 69 | } | ||
| 70 | |||
| 71 | const Type* | ||
| 72 | 2046 | TypeLowering::extract_from_type_specifier_simple(const TypeSpecifierSimple & type_specifier) | |
| 73 | { | ||
| 74 | 2046 | const auto & type_name = type_specifier.get_type_name(); | |
| 75 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2046 times.
|
2046 | if (type_name.is_expression()) { |
| 76 | ✗ | auto error = std::make_unique<Gyoji::context::Error>("Could not resolve type"); | |
| 77 | ✗ | error->add_message(type_name.get_name_source_ref(), "Specifying types from expressions is not yet supported."); | |
| 78 | ✗ | compiler_context.get_errors().add_error(std::move(error)); | |
| 79 | ✗ | return nullptr; | |
| 80 | ✗ | } | |
| 81 | 2046 | std::string name = type_name.get_name(); | |
| 82 | 2046 | const Type *type = mir.get_types().get_type(name); | |
| 83 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2046 times.
|
2046 | if (type == nullptr) { |
| 84 | ✗ | compiler_context | |
| 85 | ✗ | .get_errors() | |
| 86 | ✗ | .add_simple_error(type_name.get_name_source_ref(), | |
| 87 | "Could not find type", | ||
| 88 | ✗ | std::string("Could not resolve type ") + name | |
| 89 | ); | ||
| 90 | ✗ | return nullptr; | |
| 91 | } | ||
| 92 | 2046 | return type; | |
| 93 | 2046 | } | |
| 94 | |||
| 95 | const Type* | ||
| 96 | ✗ | TypeLowering::extract_from_type_specifier_template(const TypeSpecifierTemplate & type_specifier) | |
| 97 | { | ||
| 98 | ✗ | compiler_context | |
| 99 | ✗ | .get_errors() | |
| 100 | ✗ | .add_simple_error(type_specifier.get_source_ref(), | |
| 101 | "Could not find type", | ||
| 102 | "Template types are not supported yet." | ||
| 103 | ); | ||
| 104 | ✗ | return nullptr; | |
| 105 | } | ||
| 106 | |||
| 107 | const Type* | ||
| 108 | 4 | TypeLowering::extract_from_type_specifier_function_pointer(const TypeSpecifierFunctionPointer & type_specifier) | |
| 109 | { | ||
| 110 | 4 | const Type *return_type = extract_from_type_specifier(type_specifier.get_return_type()); | |
| 111 | |||
| 112 | 4 | std::vector<std::string> arg_list; | |
| 113 | 4 | std::vector<Argument> fptr_arguments; | |
| 114 | |||
| 115 |
2/2✓ Branch 7 taken 16 times.
✓ Branch 8 taken 4 times.
|
20 | for (const auto & type_specifier : type_specifier.get_args().get_arguments()) { |
| 116 | 16 | const Type *argument_type = extract_from_type_specifier(*type_specifier); | |
| 117 | 16 | Argument arg(argument_type, type_specifier->get_source_ref()); | |
| 118 | 16 | fptr_arguments.push_back(arg); | |
| 119 | 16 | arg_list.push_back(argument_type->get_name()); | |
| 120 | 16 | } | |
| 121 | |||
| 122 | // bool is_unsafe = method_unsafe_modifier.is_unsafe(); | ||
| 123 | 4 | bool is_unsafe = false; | |
| 124 | 4 | std::string arg_string = Gyoji::misc::join(arg_list, ","); | |
| 125 |
3/6✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 4 times.
|
12 | std::string unsafe_str = is_unsafe ? std::string("unsafe") : std::string(""); |
| 126 | 28 | std::string pointer_name = return_type->get_name() + std::string("(") + unsafe_str + std::string("*)") + std::string("(") + arg_string + std::string(")"); | |
| 127 | 4 | Type *fptr_type = get_or_create(pointer_name, Type::TYPE_FUNCTION_POINTER, false, type_specifier.get_source_ref()); | |
| 128 | |||
| 129 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
|
4 | if (!fptr_type->is_complete()) { |
| 130 | ✗ | fptr_type->complete_function_pointer_definition( | |
| 131 | return_type, | ||
| 132 | fptr_arguments, | ||
| 133 | is_unsafe, | ||
| 134 | type_specifier.get_source_ref() | ||
| 135 | ); | ||
| 136 | } | ||
| 137 | |||
| 138 | 8 | return fptr_type; | |
| 139 | 4 | } | |
| 140 | |||
| 141 | const Type* | ||
| 142 | 128 | TypeLowering::extract_from_type_specifier_pointer_to(const TypeSpecifierPointerTo & type_specifier) | |
| 143 | { | ||
| 144 | 128 | const Type *pointer_target = extract_from_type_specifier(type_specifier.get_type_specifier()); | |
| 145 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 128 times.
|
128 | if (pointer_target == nullptr) { |
| 146 | ✗ | compiler_context | |
| 147 | ✗ | .get_errors() | |
| 148 | ✗ | .add_simple_error(type_specifier.get_source_ref(), | |
| 149 | "Could not find type", | ||
| 150 | "Could not resolve target of pointer" | ||
| 151 | ); | ||
| 152 | ✗ | return nullptr; | |
| 153 | } | ||
| 154 | 128 | const Type *pointer_type = mir.get_types().get_pointer_to(pointer_target, type_specifier.get_source_ref()); | |
| 155 | 128 | return pointer_type; | |
| 156 | } | ||
| 157 | |||
| 158 | const Type* | ||
| 159 | 8 | TypeLowering::extract_from_type_specifier_reference_to(const TypeSpecifierReferenceTo & type_specifier) | |
| 160 | { | ||
| 161 | 8 | const Type *pointer_target = extract_from_type_specifier(type_specifier.get_type_specifier()); | |
| 162 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
8 | if (pointer_target == nullptr) { |
| 163 | ✗ | compiler_context | |
| 164 | ✗ | .get_errors() | |
| 165 | ✗ | .add_simple_error(type_specifier.get_source_ref(), | |
| 166 | "Could not find type", | ||
| 167 | "Could not resolve target of reference" | ||
| 168 | ); | ||
| 169 | ✗ | return nullptr; | |
| 170 | } | ||
| 171 | 8 | const Type *pointer_type = mir.get_types().get_reference_to(pointer_target, type_specifier.get_source_ref()); | |
| 172 | 8 | return pointer_type; | |
| 173 | } | ||
| 174 | |||
| 175 | const Type* | ||
| 176 | ✗ | TypeLowering::extract_from_type_specifier_array(const TypeSpecifierArray & type_specifier) | |
| 177 | { | ||
| 178 | ✗ | const Type *pointer_target = extract_from_type_specifier(type_specifier.get_type_specifier()); | |
| 179 | ✗ | if (pointer_target == nullptr) { | |
| 180 | ✗ | compiler_context | |
| 181 | ✗ | .get_errors() | |
| 182 | ✗ | .add_simple_error(type_specifier.get_literal_int_token().get_source_ref(), | |
| 183 | "Could not parse type of array elements.", | ||
| 184 | "Array element type could not be parsed." | ||
| 185 | ); | ||
| 186 | ✗ | return nullptr; | |
| 187 | } | ||
| 188 | |||
| 189 | Gyoji::frontend::integers::ParseLiteralIntResult parse_result; | ||
| 190 | ✗ | bool parsed = parse_literal_int(compiler_context, mir.get_types(), type_specifier.get_literal_int_token(), parse_result); | |
| 191 | ✗ | if (!parsed || parse_result.parsed_type == nullptr) { | |
| 192 | ✗ | compiler_context | |
| 193 | ✗ | .get_errors() | |
| 194 | ✗ | .add_simple_error(type_specifier.get_literal_int_token().get_source_ref(), | |
| 195 | "Array size invalid", | ||
| 196 | "Could not parse array size." | ||
| 197 | ); | ||
| 198 | ✗ | return nullptr; | |
| 199 | } | ||
| 200 | ✗ | if (parse_result.parsed_type->get_type() != Type::TYPE_PRIMITIVE_u32) { | |
| 201 | ✗ | compiler_context | |
| 202 | ✗ | .get_errors() | |
| 203 | ✗ | .add_simple_error(type_specifier.get_literal_int_token().get_source_ref(), | |
| 204 | "Array size invalid", | ||
| 205 | "Array size must be an unsigned 32-bit integer (u32) constant. Sizes may not be computed at runtime." | ||
| 206 | ); | ||
| 207 | } | ||
| 208 | |||
| 209 | ✗ | const Type *array_type = mir.get_types().get_array_of(pointer_target, parse_result.u32_value, type_specifier.get_source_ref()); | |
| 210 | ✗ | return array_type; | |
| 211 | } | ||
| 212 | |||
| 213 | const Type * | ||
| 214 | 2186 | TypeLowering::extract_from_type_specifier(const TypeSpecifier & type_specifier) | |
| 215 | { | ||
| 216 | 2186 | const auto & type_specifier_type = type_specifier.get_type(); | |
| 217 |
2/2✓ Branch 1 taken 2046 times.
✓ Branch 2 taken 140 times.
|
2186 | if (std::holds_alternative<Gyoji::owned<TypeSpecifierSimple>>(type_specifier_type)) { |
| 218 | 2046 | const auto & type_specifier = std::get<Gyoji::owned<TypeSpecifierSimple>>(type_specifier_type); | |
| 219 | 2046 | return extract_from_type_specifier_simple(*type_specifier); | |
| 220 | } | ||
| 221 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 140 times.
|
140 | else if (std::holds_alternative<Gyoji::owned<TypeSpecifierTemplate>>(type_specifier_type)) { |
| 222 | ✗ | const auto & type_specifier = std::get<Gyoji::owned<TypeSpecifierTemplate>>(type_specifier_type); | |
| 223 | ✗ | return extract_from_type_specifier_template(*type_specifier); | |
| 224 | } | ||
| 225 |
2/2✓ Branch 1 taken 4 times.
✓ Branch 2 taken 136 times.
|
140 | else if (std::holds_alternative<Gyoji::owned<TypeSpecifierFunctionPointer>>(type_specifier_type)) { |
| 226 | 4 | const auto & type_specifier = std::get<Gyoji::owned<TypeSpecifierFunctionPointer>>(type_specifier_type); | |
| 227 | 4 | return extract_from_type_specifier_function_pointer(*type_specifier); | |
| 228 | } | ||
| 229 |
2/2✓ Branch 1 taken 128 times.
✓ Branch 2 taken 8 times.
|
136 | else if (std::holds_alternative<Gyoji::owned<TypeSpecifierPointerTo>>(type_specifier_type)) { |
| 230 | 128 | const auto & type_specifier = std::get<Gyoji::owned<TypeSpecifierPointerTo>>(type_specifier_type); | |
| 231 | 128 | return extract_from_type_specifier_pointer_to(*type_specifier); | |
| 232 | } | ||
| 233 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | else if (std::holds_alternative<Gyoji::owned<TypeSpecifierReferenceTo>>(type_specifier_type)) { |
| 234 | 8 | const auto & type_specifier = std::get<Gyoji::owned<TypeSpecifierReferenceTo>>(type_specifier_type); | |
| 235 | 8 | return extract_from_type_specifier_reference_to(*type_specifier); | |
| 236 | |||
| 237 | } | ||
| 238 | ✗ | else if (std::holds_alternative<Gyoji::owned<TypeSpecifierArray>>(type_specifier_type)) { | |
| 239 | ✗ | const auto & type_specifier = std::get<Gyoji::owned<TypeSpecifierArray>>(type_specifier_type); | |
| 240 | ✗ | return extract_from_type_specifier_array(*type_specifier); | |
| 241 | |||
| 242 | } | ||
| 243 | |||
| 244 | ✗ | compiler_context | |
| 245 | ✗ | .get_errors() | |
| 246 | ✗ | .add_simple_error(type_specifier.get_source_ref(), | |
| 247 | "Compiler bug! Please report this message(2)", | ||
| 248 | "Unknown TypeSpecifier type in variant (compiler bug)" | ||
| 249 | ); | ||
| 250 | |||
| 251 | ✗ | return nullptr; | |
| 252 | } | ||
| 253 | |||
| 254 | void | ||
| 255 | 8 | TypeLowering::extract_from_class_method_types( | |
| 256 | Type &class_type, | ||
| 257 | std::map<std::string, TypeMethod> & methods, | ||
| 258 | std::string simple_name, | ||
| 259 | std::string fully_qualified_name, | ||
| 260 | Gyoji::mir::Symbol::SymbolType type, | ||
| 261 | const Gyoji::frontend::tree::UnsafeModifier & method_unsafe_modifier, | ||
| 262 | const Type *method_return_type, | ||
| 263 | const Gyoji::frontend::tree::FunctionDefinitionArgList & function_definition_arg_list, | ||
| 264 | const Gyoji::context::SourceReference & source_ref | ||
| 265 | ) | ||
| 266 | { | ||
| 267 | 8 | std::vector<std::string> arg_list; | |
| 268 | 8 | std::vector<Argument> fptr_arguments; | |
| 269 | // First, pass the 'this' pointer | ||
| 270 | // to the function. | ||
| 271 |
4/4✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 2 times.
|
8 | if (type == Gyoji::mir::Symbol::SYMBOL_MEMBER_METHOD || |
| 272 | type == Gyoji::mir::Symbol::SYMBOL_MEMBER_DESTRUCTOR) { | ||
| 273 | 6 | const Type * this_type = mir.get_types().get_pointer_to(&class_type, class_type.get_defined_source_ref()); | |
| 274 | 6 | Argument arg_this(this_type, source_ref); | |
| 275 | |||
| 276 | 6 | fptr_arguments.push_back(arg_this); | |
| 277 | 6 | arg_list.push_back(this_type->get_name()); | |
| 278 | 6 | } | |
| 279 | |||
| 280 | const std::vector<Gyoji::owned<FunctionDefinitionArg>> & function_definition_args = | ||
| 281 | 8 | function_definition_arg_list.get_arguments(); | |
| 282 |
2/2✓ Branch 5 taken 6 times.
✓ Branch 6 taken 8 times.
|
14 | for (const auto & function_definition_arg : function_definition_args) { |
| 283 | 6 | const Type *argument_type = extract_from_type_specifier(function_definition_arg->get_type_specifier()); | |
| 284 | 6 | Argument arg(argument_type, function_definition_arg->get_source_ref()); | |
| 285 | 6 | fptr_arguments.push_back(arg); | |
| 286 | 6 | arg_list.push_back(argument_type->get_name()); | |
| 287 | 6 | } | |
| 288 | |||
| 289 | TypeMethod method( | ||
| 290 | simple_name, | ||
| 291 | source_ref, | ||
| 292 | &class_type, | ||
| 293 | method_return_type, | ||
| 294 | fptr_arguments | ||
| 295 | 8 | ); | |
| 296 | |||
| 297 | 8 | fprintf(stderr, "Defining method %s\n", simple_name.c_str()); | |
| 298 | 8 | methods.insert(std::pair(simple_name, method)); | |
| 299 | |||
| 300 | 8 | bool is_unsafe = method_unsafe_modifier.is_unsafe(); | |
| 301 | 8 | std::string arg_string = Gyoji::misc::join(arg_list, ","); | |
| 302 |
3/6✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 8 times.
|
24 | std::string unsafe_str = is_unsafe ? std::string("unsafe") : std::string(""); |
| 303 | 56 | std::string pointer_name = method_return_type->get_name() + std::string("(") + unsafe_str + std::string("*)") + std::string("(") + arg_string + std::string(")"); | |
| 304 | 8 | Type *fptr_type = get_or_create(pointer_name, Type::TYPE_FUNCTION_POINTER, false, source_ref); | |
| 305 | |||
| 306 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | if (!fptr_type->is_complete()) { |
| 307 | 8 | fptr_type->complete_function_pointer_definition( | |
| 308 | method_return_type, | ||
| 309 | fptr_arguments, | ||
| 310 | is_unsafe, | ||
| 311 | source_ref | ||
| 312 | ); | ||
| 313 | } | ||
| 314 | 8 | fprintf(stderr, "Defining symbol %s\n", fully_qualified_name.c_str()); | |
| 315 | |||
| 316 | 8 | mir.get_symbols().define_symbol( | |
| 317 | fully_qualified_name, | ||
| 318 | type, | ||
| 319 | fptr_type | ||
| 320 | ); | ||
| 321 | 8 | } | |
| 322 | |||
| 323 | |||
| 324 | void | ||
| 325 | 18 | TypeLowering::extract_from_class_members(Type & class_type, const ClassDefinition & class_definition) | |
| 326 | { | ||
| 327 | 18 | std::vector<TypeMember> members; | |
| 328 | 18 | std::map<std::string, const TypeMember*> members_by_name; | |
| 329 | 18 | std::map<std::string, TypeMethod> methods; | |
| 330 | |||
| 331 | 18 | const auto & class_members = class_definition.get_members(); | |
| 332 | 18 | size_t member_id = 0; | |
| 333 |
2/2✓ Branch 5 taken 52 times.
✓ Branch 6 taken 18 times.
|
70 | for (const auto & class_member : class_members) { |
| 334 | 52 | const auto & class_member_type = class_member->get_member(); | |
| 335 |
2/2✓ Branch 1 taken 44 times.
✓ Branch 2 taken 8 times.
|
52 | if (std::holds_alternative<Gyoji::owned<ClassMemberDeclarationVariable>>(class_member_type)) { |
| 336 | 44 | const auto & member_variable = std::get<Gyoji::owned<ClassMemberDeclarationVariable>>(class_member_type); | |
| 337 | |||
| 338 |
1/2✗ Branch 3 not taken.
✓ Branch 4 taken 44 times.
|
44 | if (member_variable->get_unsafe_modifier().is_unsafe()) { |
| 339 | ✗ | compiler_context | |
| 340 | ✗ | .get_errors() | |
| 341 | ✗ | .add_simple_error(member_variable->get_type_specifier().get_source_ref(), | |
| 342 | "Member variables cannot be declared inherently unsafe.", | ||
| 343 | ✗ | std::string("Member variable ") + member_variable->get_name() + std::string(" cannot be declared unsafe. This would not have any valid meaning.") | |
| 344 | ); | ||
| 345 | } | ||
| 346 | 44 | const Type *member_type = extract_from_type_specifier(member_variable->get_type_specifier()); | |
| 347 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 44 times.
|
44 | if (member_type == nullptr) { |
| 348 | ✗ | compiler_context | |
| 349 | ✗ | .get_errors() | |
| 350 | ✗ | .add_simple_error(member_variable->get_type_specifier().get_source_ref(), | |
| 351 | "Could not find type", | ||
| 352 | ✗ | std::string("Could not extract type of member variable ") + member_variable->get_name() | |
| 353 | ); | ||
| 354 | } | ||
| 355 | else { | ||
| 356 | 44 | const auto existing_member_it = members_by_name.find(member_variable->get_name()); | |
| 357 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 44 times.
|
44 | if (existing_member_it != members_by_name.end()) { |
| 358 | ✗ | std::unique_ptr<Gyoji::context::Error> error = std::make_unique<Gyoji::context::Error>("Duplicate member variable in class."); | |
| 359 | ✗ | error->add_message(member_variable->get_name_source_ref(), | |
| 360 | ✗ | std::string("Member variable ") + | |
| 361 | ✗ | member_variable->get_name() + | |
| 362 | ✗ | std::string(" in class ") + | |
| 363 | ✗ | class_definition.get_name() + | |
| 364 | ✗ | std::string(" was already defined")); | |
| 365 | ✗ | error->add_message(existing_member_it->second->get_source_ref(), | |
| 366 | "Originally defined here."); | ||
| 367 | ✗ | compiler_context | |
| 368 | ✗ | .get_errors() | |
| 369 | ✗ | .add_error(std::move(error)); | |
| 370 | ✗ | } | |
| 371 | else { | ||
| 372 | 44 | TypeMember add_member(member_variable->get_name(), member_id, member_type, member_variable->get_name_source_ref()); | |
| 373 | 44 | members.push_back(add_member); | |
| 374 | 44 | members_by_name.insert(std::pair(member_variable->get_name(), &members.back())); | |
| 375 | 44 | member_id++; | |
| 376 | 44 | } | |
| 377 | } | ||
| 378 | } | ||
| 379 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 6 times.
|
8 | else if (std::holds_alternative<Gyoji::owned<ClassMemberDeclarationMethodStatic>>(class_member_type)) { |
| 380 | 2 | const auto & member_method = std::get<Gyoji::owned<ClassMemberDeclarationMethodStatic>>(class_member_type); | |
| 381 | 2 | const Type * method_return_type = extract_from_type_specifier(member_method->get_type_specifier()); | |
| 382 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (method_return_type == nullptr) { |
| 383 | ✗ | fprintf(stderr, "Compiler bug! static method is missing a return type. This should not be possible at the semantics layer.\n"); | |
| 384 | ✗ | exit(1); | |
| 385 | } | ||
| 386 | |||
| 387 | 2 | std::string simple_name = member_method->get_identifier().get_name(); | |
| 388 | 2 | std::string fully_qualified_name = member_method->get_identifier().get_fully_qualified_name(); | |
| 389 | |||
| 390 | 2 | extract_from_class_method_types( | |
| 391 | class_type, | ||
| 392 | methods, | ||
| 393 | simple_name, | ||
| 394 | fully_qualified_name, | ||
| 395 | Gyoji::mir::Symbol::SYMBOL_STATIC_FUNCTION, | ||
| 396 | member_method->get_unsafe_modifier(), | ||
| 397 | method_return_type, | ||
| 398 | member_method->get_arguments(), | ||
| 399 | 2 | member_method->get_source_ref() | |
| 400 | ); | ||
| 401 | 2 | } | |
| 402 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 4 times.
|
6 | else if (std::holds_alternative<Gyoji::owned<ClassMemberDeclarationMethod>>(class_member_type)) { |
| 403 | 2 | const auto & member_method = std::get<Gyoji::owned<ClassMemberDeclarationMethod>>(class_member_type); | |
| 404 | |||
| 405 | // Regular methods have return types. Destructors always return void. | ||
| 406 | 2 | const Type * method_return_type = extract_from_type_specifier(member_method->get_type_specifier()); | |
| 407 | |||
| 408 | 2 | std::string simple_name = member_method->get_identifier().get_name(); | |
| 409 | 2 | std::string fully_qualified_name = member_method->get_identifier().get_fully_qualified_name(); | |
| 410 | |||
| 411 | 2 | extract_from_class_method_types( | |
| 412 | class_type, | ||
| 413 | methods, | ||
| 414 | simple_name, | ||
| 415 | fully_qualified_name, | ||
| 416 | Gyoji::mir::Symbol::SYMBOL_MEMBER_METHOD, | ||
| 417 | member_method->get_unsafe_modifier(), | ||
| 418 | method_return_type, | ||
| 419 | member_method->get_arguments(), | ||
| 420 | 2 | member_method->get_source_ref() | |
| 421 | ); | ||
| 422 | 2 | } | |
| 423 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | else if (std::holds_alternative<Gyoji::owned<ClassMemberDeclarationDestructor>>(class_member_type)) { |
| 424 | 4 | const auto & member_method = std::get<Gyoji::owned<ClassMemberDeclarationDestructor>>(class_member_type); | |
| 425 | |||
| 426 |
1/2✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
|
4 | if (member_method->get_arguments().get_arguments().size() != 0) { |
| 427 | ✗ | compiler_context | |
| 428 | ✗ | .get_errors() | |
| 429 | ✗ | .add_simple_error( | |
| 430 | ✗ | member_method->get_source_ref(), | |
| 431 | "Destructors may not have arguments", | ||
| 432 | ✗ | std::string("Destructors may not have funciton arguments.") | |
| 433 | ); | ||
| 434 | ✗ | continue; | |
| 435 | } | ||
| 436 | |||
| 437 | // Regular methods have return types. Destructors always return void. | ||
| 438 | 8 | const Type * method_return_type = mir.get_types().get_type("void"); | |
| 439 | |||
| 440 | 12 | std::string simple_name = std::string("~") + class_type.get_simple_name(); | |
| 441 | 4 | std::string fully_qualified_name = class_type.get_name() + std::string("::") + simple_name; | |
| 442 | 4 | fprintf(stderr, "Extracting destructor %s %s\n", simple_name.c_str(), fully_qualified_name.c_str()); | |
| 443 | |||
| 444 | 4 | extract_from_class_method_types( | |
| 445 | class_type, | ||
| 446 | methods, | ||
| 447 | simple_name, | ||
| 448 | fully_qualified_name, | ||
| 449 | Gyoji::mir::Symbol::SYMBOL_MEMBER_DESTRUCTOR, | ||
| 450 | member_method->get_unsafe_modifier(), | ||
| 451 | method_return_type, | ||
| 452 | member_method->get_arguments(), | ||
| 453 | 4 | member_method->get_source_ref() | |
| 454 | ); | ||
| 455 | 4 | } | |
| 456 | } | ||
| 457 | |||
| 458 | 18 | class_type.complete_composite_definition( | |
| 459 | members, | ||
| 460 | methods, | ||
| 461 | class_definition.get_name_source_ref()); | ||
| 462 | 18 | } | |
| 463 | |||
| 464 | void | ||
| 465 | 18 | TypeLowering::extract_from_class_definition(const ClassDefinition & definition) | |
| 466 | { | ||
| 467 | 18 | const auto it = mir.get_types().get_types().find(definition.get_fully_qualified_name()); | |
| 468 | |||
| 469 |
2/2✓ Branch 4 taken 12 times.
✓ Branch 5 taken 6 times.
|
18 | if (it == mir.get_types().get_types().end()) { |
| 470 | // Case 1: No forward declaration exists, fill in the definition | ||
| 471 | // from the class. | ||
| 472 | Gyoji::owned<Type> type = std::make_unique<Type>( | ||
| 473 | 24 | definition.get_fully_qualified_name(), | |
| 474 | 12 | definition.get_name(), | |
| 475 | 24 | Type::TYPE_COMPOSITE, | |
| 476 | 12 | true, | |
| 477 | 24 | definition.get_name_source_ref()); | |
| 478 | 12 | Type & class_type = *type.get(); | |
| 479 | 12 | mir.get_types().define_type(std::move(type)); | |
| 480 | 12 | extract_from_class_members(class_type, definition); | |
| 481 | 12 | } | |
| 482 | else { | ||
| 483 | 6 | auto & type = *it->second; | |
| 484 | // Case 2: Class is forward declared, but is incomplete, so fill in the declaration. | ||
| 485 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | if (!type.is_complete()) { |
| 486 | 6 | extract_from_class_members(type, definition); | |
| 487 | } | ||
| 488 | else { | ||
| 489 | // Case 3: Class is declared and complete, but does not match our current definition, | ||
| 490 | // so this is a duplicate. Raise an error to avoid ambiguity. | ||
| 491 | ✗ | std::unique_ptr<Gyoji::context::Error> error = std::make_unique<Gyoji::context::Error>(std::string("Duplicate class definition: ") + definition.get_fully_qualified_name()); | |
| 492 | ✗ | error->add_message(type.get_defined_source_ref(), | |
| 493 | "Originally defined here" | ||
| 494 | ); | ||
| 495 | ✗ | error->add_message(definition.get_name_source_ref(), | |
| 496 | "Re-declared here" | ||
| 497 | ); | ||
| 498 | ✗ | compiler_context | |
| 499 | ✗ | .get_errors() | |
| 500 | ✗ | .add_error(std::move(error)); | |
| 501 | ✗ | } | |
| 502 | |||
| 503 | } | ||
| 504 | 18 | } | |
| 505 | |||
| 506 | void | ||
| 507 | ✗ | TypeLowering::extract_from_enum_definition(const EnumDefinition & enum_definition) | |
| 508 | { | ||
| 509 | ✗ | const auto it = mir.get_types().get_types().find(enum_definition.get_name()); | |
| 510 | ✗ | if (it == mir.get_types().get_types().end()) { | |
| 511 | // No definition exists, create it. | ||
| 512 | ✗ | Gyoji::owned<Type> type = std::make_unique<Type>(enum_definition.get_name(), Type::TYPE_ENUM, true, enum_definition.get_name_source_ref()); | |
| 513 | ✗ | mir.get_types().define_type(std::move(type)); | |
| 514 | |||
| 515 | ✗ | for (const auto & ev : enum_definition.get_value_list().get_values()) { | |
| 516 | ✗ | fprintf(stderr, "Value is %s\n", ev->get_name().c_str()); | |
| 517 | } | ||
| 518 | // mir.get_symbols().define_symbol( | ||
| 519 | // fully_qualified_function_name, | ||
| 520 | // pointer_type | ||
| 521 | // ); | ||
| 522 | ✗ | } | |
| 523 | else { | ||
| 524 | // This is a duplicate, reference the original definition. | ||
| 525 | // Case 3: Class is declared and complete, but does not match our current definition, | ||
| 526 | // so this is a duplicate. Raise an error to avoid ambiguity. | ||
| 527 | ✗ | auto & type = *it->second; | |
| 528 | ✗ | std::unique_ptr<Gyoji::context::Error> error = std::make_unique<Gyoji::context::Error>(std::string("Duplicate enum definition: ") + enum_definition.get_name()); | |
| 529 | ✗ | error->add_message(type.get_defined_source_ref(), | |
| 530 | "Originally defined here" | ||
| 531 | ); | ||
| 532 | ✗ | error->add_message(enum_definition.get_name_source_ref(), | |
| 533 | "Re-declared here" | ||
| 534 | ); | ||
| 535 | ✗ | compiler_context | |
| 536 | ✗ | .get_errors() | |
| 537 | ✗ | .add_error(std::move(error)); | |
| 538 | ✗ | } | |
| 539 | ✗ | } | |
| 540 | |||
| 541 | void | ||
| 542 | 6 | TypeLowering::extract_from_type_definition(const TypeDefinition & type_definition) | |
| 543 | { | ||
| 544 | 6 | const auto it = mir.get_types().get_types().find(type_definition.get_name()); | |
| 545 |
1/2✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
|
6 | if (it == mir.get_types().get_types().end()) { |
| 546 | // No definition exists, create it. | ||
| 547 | 6 | const Type *defined_type = extract_from_type_specifier(type_definition.get_type_specifier()); | |
| 548 | |||
| 549 | // We effectively make a new type as a copy of the old one. | ||
| 550 | // This may seem redundant, but it's done | ||
| 551 | // so that we can later modify the type by "instantiating" | ||
| 552 | // it as a generic with specific type parameters | ||
| 553 | // when we get to that point. | ||
| 554 | Gyoji::owned<Type> type = std::make_unique<Type>( | ||
| 555 | 6 | type_definition.get_name(), | |
| 556 | 6 | type_definition.get_name(), | |
| 557 | 6 | type_definition.get_type_specifier().get_source_ref(), | |
| 558 | *defined_type | ||
| 559 | 12 | ); | |
| 560 | 6 | mir.get_types().define_type(std::move(type)); | |
| 561 | 6 | } | |
| 562 | else { | ||
| 563 | // This is a duplicate, reference the original definition. | ||
| 564 | // Case 3: Class is declared and complete, but does not match our current definition, | ||
| 565 | // so this is a duplicate. Raise an error to avoid ambiguity. | ||
| 566 | ✗ | auto & type = *it->second; | |
| 567 | ✗ | std::unique_ptr<Gyoji::context::Error> error = std::make_unique<Gyoji::context::Error>(std::string("Duplicate enum definition: ") + type_definition.get_name()); | |
| 568 | ✗ | error->add_message(type.get_defined_source_ref(), | |
| 569 | "Originally defined here" | ||
| 570 | ); | ||
| 571 | ✗ | error->add_message(type_definition.get_name_source_ref(), | |
| 572 | "Re-declared here" | ||
| 573 | ); | ||
| 574 | ✗ | compiler_context | |
| 575 | ✗ | .get_errors() | |
| 576 | ✗ | .add_error(std::move(error)); | |
| 577 | ✗ | } | |
| 578 | 6 | } | |
| 579 | |||
| 580 | |||
| 581 | void | ||
| 582 | 318 | TypeLowering::extract_from_function_specifications( | |
| 583 | const Terminal & name, | ||
| 584 | Gyoji::mir::Symbol::SymbolType symbol_type, | ||
| 585 | const Type *return_type, | ||
| 586 | const SourceReference & return_type_source_ref, | ||
| 587 | const FunctionDefinitionArgList & function_argument_list, | ||
| 588 | const UnsafeModifier & unsafe_modifier | ||
| 589 | ) | ||
| 590 | { | ||
| 591 | |||
| 592 | 318 | NS2Entity *entity = name.get_ns2_entity(); | |
| 593 | 318 | Type *maybe_class_type = mir.get_types().get_type(entity->get_parent()->get_fully_qualified_name()); | |
| 594 | 318 | const Type *class_pointer_type = nullptr; | |
| 595 | 318 | bool is_method = false; | |
| 596 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 312 times.
|
318 | if (maybe_class_type != nullptr) { |
| 597 | 6 | class_pointer_type = mir.get_types().get_pointer_to(maybe_class_type, return_type_source_ref); | |
| 598 | 6 | is_method = true; | |
| 599 | } | ||
| 600 | |||
| 601 | std::string fully_qualified_function_name = | ||
| 602 | 318 | name.get_fully_qualified_name(); | |
| 603 | |||
| 604 | |||
| 605 | ////// | ||
| 606 | // Define the type of a function pointer. | ||
| 607 | ////// | ||
| 608 | 318 | std::vector<std::string> arg_list; | |
| 609 | 318 | std::vector<Argument> fptr_arguments; | |
| 610 | 318 | const auto & function_definition_args = function_argument_list.get_arguments(); | |
| 611 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 312 times.
|
318 | if (is_method) { |
| 612 | 6 | arg_list.push_back(class_pointer_type->get_name()); | |
| 613 | 6 | fptr_arguments.push_back( | |
| 614 | 12 | Argument(class_pointer_type, name.get_source_ref()) | |
| 615 | ); | ||
| 616 | } | ||
| 617 |
2/2✓ Branch 5 taken 552 times.
✓ Branch 6 taken 318 times.
|
870 | for (const auto & function_definition_arg : function_definition_args) { |
| 618 | 552 | std::string name = function_definition_arg->get_identifier().get_fully_qualified_name(); | |
| 619 | 552 | const Type * t = extract_from_type_specifier(function_definition_arg->get_type_specifier()); | |
| 620 | 552 | arg_list.push_back(t->get_name()); | |
| 621 | 552 | fptr_arguments.push_back( | |
| 622 | 1104 | Argument(t, function_definition_arg->get_type_specifier().get_source_ref()) | |
| 623 | ); | ||
| 624 | 552 | } | |
| 625 | 318 | bool is_unsafe = unsafe_modifier.is_unsafe(); | |
| 626 | 318 | std::string arg_string = Gyoji::misc::join(arg_list, ","); | |
| 627 |
3/6✗ Branch 0 not taken.
✓ Branch 1 taken 318 times.
✓ Branch 4 taken 318 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 318 times.
|
954 | std::string unsafe_str = is_unsafe ? std::string("unsafe") : std::string(""); |
| 628 | 2226 | std::string pointer_name = return_type->get_name() + std::string("(") + unsafe_str + std::string("*)") + std::string("(") + arg_string + std::string(")"); | |
| 629 | 318 | Type *pointer_type = get_or_create(pointer_name, Type::TYPE_FUNCTION_POINTER, false, name.get_source_ref()); | |
| 630 | |||
| 631 |
2/2✓ Branch 1 taken 110 times.
✓ Branch 2 taken 208 times.
|
318 | if (!pointer_type->is_complete()) { |
| 632 | 110 | pointer_type->complete_function_pointer_definition( | |
| 633 | return_type, | ||
| 634 | fptr_arguments, | ||
| 635 | is_unsafe, | ||
| 636 | name.get_source_ref() | ||
| 637 | ); | ||
| 638 | } | ||
| 639 | ////// | ||
| 640 | // Now that the type has been defined, we can | ||
| 641 | // define the symbol for this specific function. | ||
| 642 | ////// | ||
| 643 | 318 | mir.get_symbols().define_symbol( | |
| 644 | fully_qualified_function_name, | ||
| 645 | symbol_type, | ||
| 646 | pointer_type | ||
| 647 | ); | ||
| 648 | |||
| 649 | 318 | } | |
| 650 | |||
| 651 | void | ||
| 652 | 270 | TypeLowering::extract_from_function_definition(const FileStatementFunctionDefinition & function_definition) | |
| 653 | { | ||
| 654 | const Type *return_type; | ||
| 655 | const SourceReference *return_type_source_ref; | ||
| 656 |
2/2✓ Branch 1 taken 4 times.
✓ Branch 2 taken 266 times.
|
270 | if (function_definition.is_destructor()) { |
| 657 | 8 | return_type = mir.get_types().get_type("void"); | |
| 658 | 4 | return_type_source_ref = &function_definition.get_name().get_source_ref(); | |
| 659 | } | ||
| 660 | else { | ||
| 661 | 266 | return_type = extract_from_type_specifier(function_definition.get_return_type()); | |
| 662 | 266 | return_type_source_ref = &function_definition.get_return_type().get_source_ref(); | |
| 663 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 266 times.
|
266 | if (return_type == nullptr) { |
| 664 | ✗ | compiler_context | |
| 665 | ✗ | .get_errors() | |
| 666 | ✗ | .add_simple_error(function_definition.get_return_type().get_source_ref(), | |
| 667 | "Compiler bug! Please report this message(3)", | ||
| 668 | "Function pointer type declared with invalid type" | ||
| 669 | ); | ||
| 670 | ✗ | return; | |
| 671 | } | ||
| 672 | } | ||
| 673 | 270 | extract_from_function_specifications( | |
| 674 | function_definition.get_name(), | ||
| 675 | Gyoji::mir::Symbol::SYMBOL_STATIC_FUNCTION, | ||
| 676 | return_type, | ||
| 677 | *return_type_source_ref, | ||
| 678 | function_definition.get_arguments(), | ||
| 679 | function_definition.get_unsafe_modifier() | ||
| 680 | ); | ||
| 681 | } | ||
| 682 | |||
| 683 | void | ||
| 684 | 48 | TypeLowering::extract_from_function_declaration(const FileStatementFunctionDeclaration & function_declaration) | |
| 685 | { | ||
| 686 | const Type *return_type; | ||
| 687 | const SourceReference *return_type_source_ref; | ||
| 688 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 48 times.
|
48 | if (function_declaration.is_destructor()) { |
| 689 | ✗ | return_type = mir.get_types().get_type("void"); | |
| 690 | ✗ | return_type_source_ref = &function_declaration.get_name().get_source_ref(); | |
| 691 | } | ||
| 692 | else { | ||
| 693 | 48 | return_type = extract_from_type_specifier(function_declaration.get_return_type()); | |
| 694 | 48 | return_type_source_ref = &function_declaration.get_return_type().get_source_ref(); | |
| 695 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
|
48 | if (return_type == nullptr) { |
| 696 | ✗ | compiler_context | |
| 697 | ✗ | .get_errors() | |
| 698 | ✗ | .add_simple_error(function_declaration.get_return_type().get_source_ref(), | |
| 699 | "Compiler bug! Please report this message(3)", | ||
| 700 | "Function pointer type declared with invalid type" | ||
| 701 | ); | ||
| 702 | ✗ | return; | |
| 703 | } | ||
| 704 | } | ||
| 705 | 48 | extract_from_function_specifications( | |
| 706 | function_declaration.get_name(), | ||
| 707 | Gyoji::mir::Symbol::SYMBOL_STATIC_FUNCTION, | ||
| 708 | return_type, | ||
| 709 | *return_type_source_ref, | ||
| 710 | function_declaration.get_arguments(), | ||
| 711 | function_declaration.get_unsafe_modifier() | ||
| 712 | ); | ||
| 713 | } | ||
| 714 | |||
| 715 | void | ||
| 716 | 12 | TypeLowering::extract_from_namespace(const FileStatementNamespace & namespace_declaration) | |
| 717 | { | ||
| 718 | 12 | const auto & statements = namespace_declaration.get_statement_list().get_statements(); | |
| 719 | 12 | extract_types(statements); | |
| 720 | 12 | } | |
| 721 | |||
| 722 | void | ||
| 723 | 42 | TypeLowering::extract_types(const std::vector<Gyoji::owned<FileStatement>> & statements) | |
| 724 | { | ||
| 725 |
2/2✓ Branch 5 taken 368 times.
✓ Branch 6 taken 42 times.
|
410 | for (const auto & statement : statements) { |
| 726 | 368 | const auto & file_statement = statement->get_statement(); | |
| 727 |
2/2✓ Branch 1 taken 48 times.
✓ Branch 2 taken 320 times.
|
368 | if (std::holds_alternative<Gyoji::owned<FileStatementFunctionDeclaration>>(file_statement)) { |
| 728 | 48 | extract_from_function_declaration(*std::get<Gyoji::owned<FileStatementFunctionDeclaration>>(file_statement)); | |
| 729 | } | ||
| 730 |
2/2✓ Branch 1 taken 270 times.
✓ Branch 2 taken 50 times.
|
320 | else if (std::holds_alternative<Gyoji::owned<FileStatementFunctionDefinition>>(file_statement)) { |
| 731 | 270 | extract_from_function_definition(*std::get<Gyoji::owned<FileStatementFunctionDefinition>>(file_statement)); | |
| 732 | } | ||
| 733 |
2/2✓ Branch 1 taken 48 times.
✓ Branch 2 taken 2 times.
|
50 | else if (std::holds_alternative<Gyoji::owned<FileStatementGlobalDefinition>>(file_statement)) { |
| 734 | // TODO: We should extract the global symbols | ||
| 735 | // from here. | ||
| 736 | } | ||
| 737 |
2/2✓ Branch 1 taken 8 times.
✓ Branch 2 taken 40 times.
|
48 | else if (std::holds_alternative<Gyoji::owned<ClassDeclaration>>(file_statement)) { |
| 738 | 8 | extract_from_class_declaration(*std::get<Gyoji::owned<ClassDeclaration>>(file_statement)); | |
| 739 | } | ||
| 740 |
2/2✓ Branch 1 taken 18 times.
✓ Branch 2 taken 22 times.
|
40 | else if (std::holds_alternative<Gyoji::owned<ClassDefinition>>(file_statement)) { |
| 741 | 18 | extract_from_class_definition(*std::get<Gyoji::owned<ClassDefinition>>(file_statement)); | |
| 742 | } | ||
| 743 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 22 times.
|
22 | else if (std::holds_alternative<Gyoji::owned<EnumDefinition>>(file_statement)) { |
| 744 | ✗ | extract_from_enum_definition(*std::get<Gyoji::owned<EnumDefinition>>(file_statement)); | |
| 745 | } | ||
| 746 |
2/2✓ Branch 1 taken 6 times.
✓ Branch 2 taken 16 times.
|
22 | else if (std::holds_alternative<Gyoji::owned<TypeDefinition>>(file_statement)) { |
| 747 | 6 | extract_from_type_definition(*std::get<Gyoji::owned<TypeDefinition>>(file_statement)); | |
| 748 | } | ||
| 749 |
2/2✓ Branch 1 taken 12 times.
✓ Branch 2 taken 4 times.
|
16 | else if (std::holds_alternative<Gyoji::owned<FileStatementNamespace>>(file_statement)) { |
| 750 | 12 | extract_from_namespace(*std::get<Gyoji::owned<FileStatementNamespace>>(file_statement)); | |
| 751 | } | ||
| 752 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
|
4 | else if (std::holds_alternative<Gyoji::owned<FileStatementUsing>>(file_statement)) { |
| 753 | // Nothing, no statements can be declared inside here. | ||
| 754 | } | ||
| 755 | else { | ||
| 756 | ✗ | compiler_context | |
| 757 | ✗ | .get_errors() | |
| 758 | ✗ | .add_simple_error(statement->get_source_ref(), | |
| 759 | "Compiler bug! Please report this message(1)", | ||
| 760 | "Unknown statement type in variant, extracting statements from file (compiler bug)" | ||
| 761 | ); | ||
| 762 | } | ||
| 763 | } | ||
| 764 | 42 | } | |
| 765 | |||
| 766 |