Compare commits
	
		
			No commits in common. "master" and "feature/3_implementing_popup" have entirely different histories.
		
	
	
		
			master
			...
			feature/3_
		
	
		
| @ -14,28 +14,29 @@ add_executable(SchemeEditor | ||||
|   comdel/domain/value.cpp | ||||
|   comdel/domain/schema.cpp | ||||
|   comdel/domain/component.cpp | ||||
|         comdel/domain/connection_instance.cpp | ||||
|         comdel/domain/connectioninstance.cpp | ||||
|   comdel/domain/rule.cpp | ||||
|         comdel/domain/attribute.cpp | ||||
|   comdel/domain/wireinstance.cpp | ||||
|   comdel/domain/attribute.cpp | ||||
|   comdel/domain/bus.cpp | ||||
|   comdel/domain/pin.cpp | ||||
|   comdel/domain/display.cpp | ||||
|   comdel/domain/library.cpp | ||||
|         comdel/domain/function_signature.cpp | ||||
|         comdel/domain/address_space.cpp | ||||
|         comdel/domain/instance_attribute.cpp | ||||
|   comdel/domain/functionsignature.cpp | ||||
|   comdel/domain/addressspace.cpp | ||||
|   comdel/domain/instanceattribute.cpp | ||||
|   comdel/domain/connection.cpp | ||||
|   comdel/domain/instance.cpp | ||||
|         comdel/domain/schema_creator.cpp | ||||
|         comdel/parser/comdel_parser.cpp | ||||
|         comdel/domain/schemacreator.cpp | ||||
|         comdel/parser/comdelparser.cpp | ||||
|   comdel/parser/token.cpp | ||||
|         comdel/parser/source_error.cpp | ||||
|         comdel/parser/parse_context.cpp | ||||
|         comdel/parser/tokens_type.cpp | ||||
|         comdel/parser/ast_nodes.cpp | ||||
|         comdel/parser/parser_util.cpp | ||||
|         comdel/parser/comdel_lexer.cpp | ||||
|         comdel/parser/sourceerror.cpp | ||||
|   comdel/parser/parsecontext.cpp | ||||
|   comdel/parser/tokenstype.cpp | ||||
|   comdel/parser/astnode.cpp | ||||
|   comdel/parser/parserutil.cpp | ||||
|   comdel/parser/comdellexer.cpp | ||||
|   main.cpp | ||||
|   mainwindow.ui | ||||
|         comdel/domain/comdel_validator.cpp comdel/domain/comdel_validator.h comdel/display/dialog/attribute_dialog.cpp comdel/display/dialog/attribute_dialog.h comdel/display/dialog/name_dialog.cpp comdel/display/dialog/name_dialog.h comdel/domain/comdel_generator.cpp comdel/domain/comdel_generator.h comdel/display/library_list.cpp comdel/display/library_list.h application.cpp application.h comdel/display/dialog/single_automatic_dialog.cpp comdel/display/dialog/single_automatic_dialog.h comdel/parser/color.h comdel/display/dialog/generic_dialog.cpp comdel/display/dialog/generic_dialog.h comdel/display/dialog/warning_dialog.cpp comdel/display/dialog/warning_dialog.h comdel/display/dialog/error_dialog.cpp comdel/display/dialog/error_dialog.h comdel/display/dialog/memory_dialog.cpp comdel/display/dialog/memory_dialog.h comdel/display/dialog/success_dialog.cpp comdel/display/dialog/success_dialog.h message_source.cpp message_source.h) | ||||
|         comdel/domain/comdelvalidator.cpp comdel/domain/comdelvalidator.h comdel/display/attribute_dialog.cpp comdel/display/attribute_dialog.h comdel/display/name_dialog.cpp comdel/display/name_dialog.h comdel/domain/comdel_generator.cpp comdel/domain/comdel_generator.h) | ||||
| target_link_libraries(SchemeEditor Qt5::Core Qt5::Gui Qt5::Widgets) | ||||
|  | ||||
| @ -9,92 +9,77 @@ CONFIG += c++17 | ||||
| #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0 | ||||
| 
 | ||||
| SOURCES += \ | ||||
|     comdel/display/dialog/attribute_dialog.cpp \ | ||||
|     comdel/display/dialog/error_dialog.cpp \ | ||||
|     comdel/display/dialog/generic_dialog.cpp \ | ||||
|     comdel/display/dialog/memory_dialog.cpp \ | ||||
|     comdel/display/dialog/name_dialog.cpp \ | ||||
|     comdel/display/dialog/single_automatic_dialog.cpp \ | ||||
|     comdel/display/dialog/success_dialog.cpp \ | ||||
|     comdel/display/dialog/warning_dialog.cpp \ | ||||
|     comdel/display/component_display.cpp \ | ||||
|     comdel/display/library_display.cpp \ | ||||
|     comdel/display/library_list.cpp \ | ||||
|     comdel/display/schema_display.cpp \ | ||||
|     comdel/domain/address_space.cpp \ | ||||
|     comdel/domain/addressspace.cpp \ | ||||
|     comdel/domain/attribute.cpp \ | ||||
|     comdel/domain/bus.cpp \ | ||||
|     comdel/domain/comdel_generator.cpp \ | ||||
|     comdel/domain/comdel_validator.cpp \ | ||||
|     comdel/domain/schemacreator.cpp \ | ||||
|     comdel/domain/component.cpp \ | ||||
|     comdel/domain/connection.cpp \ | ||||
|     comdel/domain/connection_instance.cpp \ | ||||
|     comdel/domain/comdelvalidator.cpp \ | ||||
|     comdel/domain/connectioninstance.cpp \ | ||||
|     comdel/domain/display.cpp \ | ||||
|     comdel/domain/function_signature.cpp \ | ||||
|     comdel/domain/functionsignature.cpp \ | ||||
|     comdel/domain/instance.cpp \ | ||||
|     comdel/domain/instance_attribute.cpp \ | ||||
|     comdel/domain/instanceattribute.cpp \ | ||||
|     comdel/domain/library.cpp \ | ||||
|     comdel/domain/pin.cpp \ | ||||
|     comdel/domain/rule.cpp \ | ||||
|     comdel/domain/schema.cpp \ | ||||
|     comdel/domain/schema_creator.cpp \ | ||||
|     comdel/domain/value.cpp \ | ||||
|     comdel/parser/ast_nodes.cpp \ | ||||
|     comdel/parser/comdel_lexer.cpp \ | ||||
|     comdel/parser/comdel_parser.cpp \ | ||||
|     comdel/parser/parse_context.cpp \ | ||||
|     comdel/parser/parser_util.cpp \ | ||||
|     comdel/parser/source_error.cpp \ | ||||
|     comdel/domain/wireinstance.cpp \ | ||||
|     comdel/parser/astnode.cpp \ | ||||
|     comdel/parser/comdellexer.cpp \ | ||||
|     comdel/parser/comdelparser.cpp \ | ||||
|     comdel/parser/parsecontext.cpp \ | ||||
|     comdel/parser/parserutil.cpp \ | ||||
|     comdel/parser/sourceerror.cpp \ | ||||
|     comdel/parser/token.cpp \ | ||||
|     comdel/parser/tokens_type.cpp \ | ||||
|     application.cpp \ | ||||
|     comdel/parser/tokenstype.cpp \ | ||||
|     comdel/display/dialogmanager.cpp \ | ||||
|     comdel/display/attribute_dialog.cpp \ | ||||
|     comdel/display/name_dialog.cpp \ | ||||
|     main.cpp \ | ||||
|     message_source.cpp \ | ||||
|     mainwindow.cpp | ||||
| 
 | ||||
| HEADERS += \ | ||||
|     comdel/display/dialog/attribute_dialog.h \ | ||||
|     comdel/display/dialog/error_dialog.h \ | ||||
|     comdel/display/dialog/generic_dialog.h \ | ||||
|     comdel/display/dialog/memory_dialog.h \ | ||||
|     comdel/display/dialog/name_dialog.h \ | ||||
|     comdel/display/dialog/single_automatic_dialog.h \ | ||||
|     comdel/display/dialog/success_dialog.h \ | ||||
|     comdel/display/dialog/warning_dialog.h \ | ||||
|     comdel/display/component_display.h \ | ||||
|     comdel/display/library_display.h \ | ||||
|     comdel/display/library_list.h \ | ||||
|     comdel/display/schema_display.h \ | ||||
|     comdel/domain/address_space.h \ | ||||
|     comdel/domain/addressspace.h \ | ||||
|     comdel/domain/attribute.h \ | ||||
|     comdel/domain/bus.h \ | ||||
|     comdel/domain/comdel_generator.h \ | ||||
|     comdel/domain/comdel_validator.h \ | ||||
|     comdel/domain/schemacreator.h \ | ||||
|     comdel/domain/component.h \ | ||||
|     comdel/domain/connection.h \ | ||||
|     comdel/domain/connection_instance.h \ | ||||
|     comdel/domain/comdelvalidator.h \ | ||||
|     comdel/domain/connectioninstance.h \ | ||||
|     comdel/domain/display.h \ | ||||
|     comdel/domain/function_signature.h \ | ||||
|     comdel/domain/functionsignature.h \ | ||||
|     comdel/domain/instance.h \ | ||||
|     comdel/domain/instance_attribute.h \ | ||||
|     comdel/domain/instanceattribute.h \ | ||||
|     comdel/domain/library.h \ | ||||
|     comdel/domain/pin.h \ | ||||
|     comdel/domain/rule.h \ | ||||
|     comdel/domain/schema.h \ | ||||
|     comdel/domain/schema_creator.h \ | ||||
|     comdel/domain/value.h \ | ||||
|     comdel/parser/ast_nodes.h \ | ||||
|     comdel/parser/comdel_lexer.h \ | ||||
|     comdel/parser/comdel_parser.h \ | ||||
|     comdel/domain/wireinstance.h \ | ||||
|     comdel/parser/astnode.h \ | ||||
|     comdel/parser/comdellexer.h \ | ||||
|     comdel/parser/comdelparser.h \ | ||||
|     comdel/parser/expected.h \ | ||||
|     comdel/parser/parse_context.h \ | ||||
|     comdel/parser/parser_util.h \ | ||||
|     comdel/parser/parsecontext.h \ | ||||
|     comdel/parser/parserutil.h \ | ||||
|     comdel/parser/poly.h \ | ||||
|     comdel/parser/presult.h \ | ||||
|     comdel/parser/source_error.h \ | ||||
|     comdel/parser/sourceerror.h \ | ||||
|     comdel/parser/token.h \ | ||||
|     comdel/parser/tokens_type.h \ | ||||
|     message_source.h \ | ||||
|     comdel/parser/tokenstype.h \ | ||||
|     comdel/display/dialogmanager.h \ | ||||
|     comdel/display/attribute_dialog.h \ | ||||
|     comdel/display/name_dialog.h \ | ||||
|     mainwindow.h | ||||
| 
 | ||||
| FORMS += \ | ||||
|  | ||||
							
								
								
									
										394
									
								
								application.cpp
									
									
									
									
									
								
							
							
						
						
									
										394
									
								
								application.cpp
									
									
									
									
									
								
							| @ -1,394 +0,0 @@ | ||||
| //
 | ||||
| // Created by bbr on 27.05.22..
 | ||||
| //
 | ||||
| 
 | ||||
| #include "application.h" | ||||
| #include "comdel/parser/parse_context.h" | ||||
| #include "comdel/parser/parser_util.h" | ||||
| #include "comdel/domain/schema_creator.h" | ||||
| #include "comdel/domain/comdel_generator.h" | ||||
| #include "comdel/domain/comdel_validator.h" | ||||
| 
 | ||||
| std::optional<domain::Library> Application::getLibrary() { | ||||
|     return library; | ||||
| } | ||||
| 
 | ||||
| domain::Schema *Application::getSchema() { | ||||
|     return schema; | ||||
| } | ||||
| 
 | ||||
| void Application::clear() { | ||||
|     if (schema != nullptr) { | ||||
|         delete schema; | ||||
|         schema = nullptr; | ||||
|     } | ||||
|     library = std::nullopt; | ||||
|     libraryPath = ""; | ||||
| } | ||||
| 
 | ||||
| bool Application::loadLibrary(std::string &filename, std::ostream &errorOutput) { | ||||
|     clear(); | ||||
| 
 | ||||
|     ParseContext parseContext; | ||||
|     auto libraryNode = load_library_from_file(&parseContext, filename.c_str(), errorOutput); | ||||
|     if (libraryNode) { | ||||
|         domain::SchemaCreator generator(validators); | ||||
|         library = generator.loadLibrary(*libraryNode); | ||||
| 
 | ||||
|         for (auto &error: generator.getErrors()) { | ||||
|             parseContext.formatError(error, errorOutput, "ERROR: "); | ||||
|         } | ||||
| 
 | ||||
|         if (library.has_value()) { | ||||
|             libraryPath = filename; | ||||
|             // on library load we create a new schema
 | ||||
|             schema = new domain::Schema(library.value()); | ||||
|         } else { | ||||
|             errorOutput << "Failed creating library model" << std::endl; | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|     } else { | ||||
|         errorOutput << "Failed parsing library" << std::endl; | ||||
|         return false; | ||||
|     } | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| std::pair<bool, std::vector<domain::ValidationError>> Application::loadSchema(std::string &filename, std::ostream &errorOutput) { | ||||
|     clear(); | ||||
| 
 | ||||
|     std::vector<domain::ValidationError> errors; | ||||
| 
 | ||||
|     ParseContext parseContext; | ||||
|     auto schemaNode = load_schema_from_file(&parseContext, filename.c_str(), errorOutput); | ||||
| 
 | ||||
|     if (schemaNode) { | ||||
|         domain::SchemaCreator generator(validators); | ||||
|         library = generator.loadLibrary(*schemaNode->library); | ||||
| 
 | ||||
|         libraryPath = schemaNode->source->asString(); | ||||
| 
 | ||||
|         for (auto &error: generator.getErrors()) { | ||||
|             parseContext.formatError(error, errorOutput, "ERROR: "); | ||||
|         } | ||||
| 
 | ||||
|         if (library) { | ||||
|             schema = generator.loadSchema(*schemaNode, *library); | ||||
| 
 | ||||
|             for (auto &error: generator.getErrors()) { | ||||
|                 parseContext.formatError(error, errorOutput, "ERROR: "); | ||||
|             } | ||||
| 
 | ||||
|             if (schema == nullptr) { | ||||
|                 clear(); | ||||
|                 return {false, errors}; | ||||
|             } | ||||
|         } else { | ||||
|             clear(); | ||||
|             return {false, errors}; | ||||
|         } | ||||
| 
 | ||||
|     } else { | ||||
|         errorOutput << "Failed schema library" << std::endl; | ||||
|         return {false, errors}; | ||||
|     } | ||||
| 
 | ||||
|     domain::ComdelValidator validator{validators}; | ||||
| 
 | ||||
|     domain::ValidationContext context; | ||||
|     context.instance = nullptr; | ||||
|     context.attribute = nullptr; | ||||
|     context.addressSpaces = {}; | ||||
| 
 | ||||
|     auto memoryReferenceValidation = validator.validateMemoryReferences(*schema, *library, context); | ||||
|     errors.insert(errors.end(), memoryReferenceValidation.begin(), memoryReferenceValidation.end()); | ||||
| 
 | ||||
|     auto nameValidation = validator.validateInstanceNames(*schema, *library, context); | ||||
|     errors.insert(errors.end(), nameValidation.begin(), nameValidation.end()); | ||||
| 
 | ||||
|     if(!errors.empty()) { | ||||
|         clear(); | ||||
|         return {false, errors}; | ||||
|     } | ||||
| 
 | ||||
|     return {true, errors}; | ||||
| } | ||||
| 
 | ||||
| bool Application::generateSchema(std::ostringstream &output) { | ||||
|     if (schema == nullptr) { | ||||
|         return false; | ||||
|     } | ||||
|     domain::generate_schema(libraryPath, schema, output); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| std::vector<domain::ValidationError> Application::validateSchema() { | ||||
|     if (schema == nullptr) { | ||||
|         return std::vector<domain::ValidationError>{domain::ValidationError(domain::Action::ERROR, "No schema loaded")}; | ||||
|     } | ||||
| 
 | ||||
|     domain::ComdelValidator validator{validators}; | ||||
| 
 | ||||
|     domain::ValidationContext context; | ||||
|     context.instance = nullptr; | ||||
|     context.attribute = nullptr; | ||||
|     context.addressSpaces = {}; | ||||
| 
 | ||||
|     for (auto &lib: library->getAddressSpaces()) { | ||||
|         context.addressSpaces.insert(std::make_pair(lib.getName(), lib)); | ||||
|     } | ||||
|     auto errors = validator.validateSchema(*schema, context); | ||||
| 
 | ||||
|     auto memoryReferenceValidation = validator.validateMemoryReferences(*schema, *library, context); | ||||
|     errors.insert(errors.end(), memoryReferenceValidation.begin(), memoryReferenceValidation.end()); | ||||
| 
 | ||||
|     auto nameValidation = validator.validateInstanceNames(*schema, *library, context); | ||||
|     errors.insert(errors.end(), nameValidation.begin(), nameValidation.end()); | ||||
| 
 | ||||
|     auto countValidation = validator.validateInstanceCount(*schema, *library, context); | ||||
|     errors.insert(errors.end(), countValidation.begin(), countValidation.end()); | ||||
| 
 | ||||
|     auto pinValidation = validator.validatePinConnections(*schema, *library, context); | ||||
|     errors.insert(errors.end(), pinValidation.begin(), pinValidation.end()); | ||||
|     return errors; | ||||
| } | ||||
| 
 | ||||
| std::vector<domain::ValidationError> Application::generateComdel(std::ostringstream &output) { | ||||
| 
 | ||||
|     auto errors = validateSchema(); | ||||
|     if (!Application::hasErrors(errors)) { | ||||
|         // as long as all validation errors are warning we continue with build
 | ||||
|         domain::generate_comdel(schema, library.value(), output); | ||||
|     } | ||||
|     return errors; | ||||
| } | ||||
| 
 | ||||
| bool Application::hasErrors(std::vector<domain::ValidationError> errors) { | ||||
|     for (auto &err: errors) { | ||||
|         if (err.type == domain::Action::ERROR) { | ||||
|             return true; | ||||
|         } | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| // static instance of application
 | ||||
| static Application *application = nullptr; | ||||
| 
 | ||||
| Application *Application::instance() { | ||||
|     if (application == nullptr) { | ||||
|         application = new Application(); | ||||
|     } | ||||
|     return application; | ||||
| } | ||||
| 
 | ||||
| std::shared_ptr<domain::ComponentInstance> | ||||
| Application::addComponent(domain::Component component, std::vector<domain::InstanceAttribute> attributes, int x, | ||||
|                           int y) { | ||||
|     std::set<std::string> names; | ||||
|     for (const auto &c: schema->componentInstances) { | ||||
|         names.insert(c->name); | ||||
|     } | ||||
|     std::string name = generateName(names, component.getInstanceName()); | ||||
| 
 | ||||
|     schema->componentInstances.push_back( | ||||
|             std::make_shared<domain::ComponentInstance>(name, attributes, std::make_pair(x, y), component)); | ||||
|     return schema->componentInstances.back(); | ||||
| } | ||||
| 
 | ||||
| std::shared_ptr<domain::BusInstance> Application::addBus(domain::Bus bus, int x, int y) { | ||||
|     std::set<std::string> names; | ||||
|     for (const auto &b: schema->busInstances) { | ||||
|         names.insert(b->name); | ||||
|     } | ||||
|     std::string name = generateName(names, bus.getInstanceName()); | ||||
| 
 | ||||
|     schema->busInstances.push_back(std::make_shared<domain::BusInstance>(name, std::make_pair(x, y), bus)); | ||||
|     return schema->busInstances.back(); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| std::string Application::generateName(std::set<std::string> &names, std::string instanceName) { | ||||
|     if (names.find(instanceName) == names.end()) { | ||||
|         return instanceName; | ||||
|     } | ||||
|     char buffer[4]; | ||||
|     for (int i = 0; i < 1000; i++) { | ||||
|         sprintf(buffer, "%03d", i); | ||||
|         auto name = instanceName + "_" + buffer; | ||||
|         if (names.find(name) == names.end()) { | ||||
|             return name; | ||||
|         } | ||||
|     } | ||||
|     // return default value as this should never happen
 | ||||
|     return instanceName; | ||||
| } | ||||
| 
 | ||||
| bool Application::removeComponent(std::string componentName) { | ||||
|     auto component = findComponentByName(componentName); | ||||
|     if (component == nullptr) { | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     std::set<domain::BusInstance*> automaticBusses; | ||||
| 
 | ||||
|     schema->connections.erase( | ||||
|             std::remove_if( | ||||
|                     schema->connections.begin(), | ||||
|                     schema->connections.end(), | ||||
|                     [component, &automaticBusses](const std::shared_ptr<domain::ConnectionInstance> &conn) { | ||||
|                         auto busConnection = dynamic_cast<domain::BusConnectionInstance *>(conn.get()); | ||||
|                         if (busConnection) { | ||||
|                             if (busConnection->instance == component) { | ||||
|                                 return true; | ||||
|                             } | ||||
|                         } | ||||
|                         auto directConnection = dynamic_cast<domain::DirectConnectionInstance *>(conn.get()); | ||||
|                         if (directConnection) { | ||||
|                             if (directConnection->instance == component || directConnection->secondInstance == component) { | ||||
|                                 automaticBusses.insert(directConnection->bus); | ||||
|                                 return true; | ||||
|                             } | ||||
|                         } | ||||
|                         return false; | ||||
|                     }), | ||||
|             schema->connections.end() | ||||
|     ); | ||||
| 
 | ||||
|     schema->busInstances.erase( | ||||
|             std::remove_if( | ||||
|                     schema->busInstances.begin(), | ||||
|                     schema->busInstances.end(), | ||||
|                     [&automaticBusses](const std::shared_ptr<domain::BusInstance> &bus) { | ||||
|                         return automaticBusses.count(bus.get()); | ||||
|                     }), | ||||
|             schema->busInstances.end() | ||||
|     ); | ||||
| 
 | ||||
|     if(component->component.getType() == domain::Component::MEMORY) { | ||||
|         for(auto& comp: schema->componentInstances) { | ||||
|             if(comp->component.getType() == domain::Component::PROCESSOR) { | ||||
|                 for(auto& attribute: comp->attributes) { | ||||
|                     if(attribute.value.isType(domain::Value::MEMORY_REFERENCE) && attribute.value.asMemoryReference() == component->name) { | ||||
|                         attribute.value = domain::Value::fromMemoryReference(std::nullopt); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     for(auto iter = schema->componentInstances.begin(); iter != schema->componentInstances.end(); ++iter) { | ||||
|         if(iter->get() == component) { | ||||
|             schema->componentInstances.erase(iter); | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| void Application::removeConnection(domain::ConnectionInstance *connectionInstance) { | ||||
|     if(auto directConnection = dynamic_cast<domain::DirectConnectionInstance*>(connectionInstance)) { | ||||
|         schema->busInstances.erase( | ||||
|                 std::remove_if( | ||||
|                         schema->busInstances.begin(), | ||||
|                         schema->busInstances.end(), | ||||
|                         [directConnection](const std::shared_ptr<domain::BusInstance> &bus) { | ||||
|                             return directConnection->bus == bus.get(); | ||||
|                         }), | ||||
|                 schema->busInstances.end() | ||||
|         ); | ||||
|     } | ||||
|     schema->connections.erase( | ||||
|             std::remove_if( | ||||
|                     schema->connections.begin(), | ||||
|                     schema->connections.end(), | ||||
|                     [connectionInstance](const std::shared_ptr<domain::ConnectionInstance> &conn) { | ||||
|                         return connectionInstance == conn.get(); | ||||
|                     }), | ||||
|                     schema->connections.end() | ||||
|             ); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| bool Application::removeBus(std::string busName) { | ||||
|     auto bus = findBusByName(busName); | ||||
|     if (bus == nullptr) { | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     schema->connections.erase( | ||||
|             std::remove_if( | ||||
|                     schema->connections.begin(), | ||||
|                     schema->connections.end(), | ||||
|                     [bus](const std::shared_ptr<domain::ConnectionInstance> &conn) { | ||||
|                         auto busConnection = dynamic_cast<domain::BusConnectionInstance *>(conn.get()); | ||||
|                         if (busConnection) { | ||||
|                             if (busConnection->bus == bus) { | ||||
|                                 return true; | ||||
|                             } | ||||
|                         } | ||||
|                         return false; | ||||
|                     }), | ||||
|             schema->connections.end() | ||||
|     ); | ||||
| 
 | ||||
|     for(auto iter = schema->busInstances.begin(); iter != schema->busInstances.end(); ++iter) { | ||||
|         if(iter->get() == bus) { | ||||
|             schema->busInstances.erase(iter); | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| domain::ComponentInstance *Application::findComponentByName(std::string componentName) { | ||||
|     for (auto &comp: schema->componentInstances) { | ||||
|         if (comp->name == componentName) { | ||||
|             return comp.get(); | ||||
|         } | ||||
|     } | ||||
|     return nullptr; | ||||
| } | ||||
| 
 | ||||
| domain::BusInstance *Application::findBusByName(std::string busName) { | ||||
|     for (auto &bus: schema->busInstances) { | ||||
|         if (bus->name == busName) { | ||||
|             return bus.get(); | ||||
|         } | ||||
|     } | ||||
|     return nullptr; | ||||
| } | ||||
| 
 | ||||
| void Application::renameComponent(std::string currentName, std::string newName) { | ||||
|     if(currentName == newName) { | ||||
|         return; | ||||
|     } | ||||
|     auto component = findComponentByName(currentName); | ||||
|     if(component) { | ||||
|         component->name = newName; | ||||
|         if(component->component.getType() == domain::Component::MEMORY) { | ||||
|             for(auto& comp: schema->componentInstances) { | ||||
|                 if(comp.get()->component.getType() == domain::Component::PROCESSOR) { | ||||
|                     for(auto& attribute: comp.get()->attributes) { | ||||
|                         if(attribute.value.isType(domain::Value::MEMORY_REFERENCE) && attribute.value.asMemoryReference() == currentName) { | ||||
|                             attribute.value = domain::Value::fromMemoryReference(newName); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void Application::renameBus(std::string currentName, std::string newName) { | ||||
|     if(currentName == newName) { | ||||
|         return; | ||||
|     } | ||||
|     auto bus = findBusByName(currentName); | ||||
|     if(bus) { | ||||
|         bus->name = newName; | ||||
|     } | ||||
| } | ||||
| @ -1,60 +0,0 @@ | ||||
| //
 | ||||
| // Created by bbr on 27.05.22..
 | ||||
| //
 | ||||
| 
 | ||||
| #ifndef SCHEMEEDITOR_APPLICATION_H | ||||
| #define SCHEMEEDITOR_APPLICATION_H | ||||
| 
 | ||||
| 
 | ||||
| #include <set> | ||||
| #include "comdel/domain/library.h" | ||||
| #include "comdel/domain/schema.h" | ||||
| #include "comdel/domain/comdel_validator.h" | ||||
| 
 | ||||
| 
 | ||||
| class Application { | ||||
| private: | ||||
|     std::string libraryPath; | ||||
|     std::optional<domain::Library> library = std::nullopt; | ||||
|     domain::Schema* schema = nullptr; | ||||
|     std::vector<domain::FunctionValidator*> validators = domain::getSupportedValidators(); | ||||
| 
 | ||||
|     std::string generateName(std::set<std::string>& names, std::string instanceName); | ||||
| 
 | ||||
|     domain::ComponentInstance *findComponentByName(std::string componentName); | ||||
|     domain::BusInstance *findBusByName(std::string busName); | ||||
| 
 | ||||
| public: | ||||
|     std::optional<domain::Library> getLibrary(); | ||||
|     domain::Schema* getSchema(); | ||||
| 
 | ||||
|     void clear(); | ||||
| 
 | ||||
|     bool loadLibrary(std::string& filename, std::ostream& errorOutput); | ||||
|     std::pair<bool, std::vector<domain::ValidationError>> loadSchema(std::string& filename, std::ostream& errorOutput); | ||||
| 
 | ||||
|     static Application* instance(); | ||||
| 
 | ||||
|     bool generateSchema(std::ostringstream &output); | ||||
|     std::vector<domain::ValidationError> validateSchema(); | ||||
|     std::vector<domain::ValidationError> generateComdel(std::ostringstream &output); | ||||
| 
 | ||||
|     std::shared_ptr<domain::ComponentInstance> addComponent(domain::Component component, std::vector<domain::InstanceAttribute> attributes, int x, int y); | ||||
|     bool removeComponent(std::string component); | ||||
| 
 | ||||
|     std::shared_ptr<domain::BusInstance> addBus(domain::Bus bus, int x, int y); | ||||
|     bool removeBus(std::string bus); | ||||
| 
 | ||||
|     static bool hasErrors(std::vector<domain::ValidationError> empty); | ||||
| 
 | ||||
|     ~Application() = default; | ||||
| 
 | ||||
|     void renameComponent(std::string currentName, std::string newName); | ||||
| 
 | ||||
|     void renameBus(std::string currentName, std::string newName); | ||||
| 
 | ||||
|     void removeConnection(domain::ConnectionInstance *pInstance); | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| #endif //SCHEMEEDITOR_APPLICATION_H
 | ||||
							
								
								
									
										66
									
								
								comdel/display/attribute_dialog.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								comdel/display/attribute_dialog.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,66 @@ | ||||
| //
 | ||||
| // Created by bbr on 18. 04. 2022..
 | ||||
| //
 | ||||
| 
 | ||||
| #include "attribute_dialog.h" | ||||
| #include "mainwindow.h" | ||||
| 
 | ||||
| namespace display { | ||||
| 
 | ||||
| void AttributeDialog::onUpdate() { | ||||
|     auto oldValue = attributeValue->value; | ||||
| 
 | ||||
|     attributeValue->value = value; | ||||
|     domain::ComdelValidator validator(domain::getSupportedValidators()); | ||||
| 
 | ||||
|     domain::ValidationContext context; | ||||
| 
 | ||||
|     for (auto &addressSpace: MainWindow::getLibrary()->getAddressSpaces()) { | ||||
|         context.addressSpaces.insert(std::make_pair(addressSpace.getName(), addressSpace)); | ||||
|     } | ||||
| 
 | ||||
|     auto validationErrors = validator.validateAttribute(attributeValue, context); | ||||
|     if(validationErrors.empty()) { | ||||
|         accept(); | ||||
|     } else { | ||||
|         bool canAccept = true; | ||||
| 
 | ||||
|         std::vector<domain::ValidationError> errors; | ||||
|         std::vector<domain::ValidationError> warnings; | ||||
|         for(auto& err: validationErrors) { | ||||
|             if(err.type == domain::Action::ERROR) { | ||||
|                 errors.push_back(err); | ||||
|             } else { | ||||
|                 warnings.push_back(err); | ||||
|             } | ||||
|         } | ||||
|         if(!errors.empty()) { | ||||
|             canAccept = false; | ||||
|             auto errorDialog = new ErrorDialog(errors); | ||||
|             errorDialog->exec(); | ||||
|         } | ||||
| 
 | ||||
|         for(auto& warning: warnings) { | ||||
|             auto warningDialog = new WarningDialog(warning); | ||||
|             int response = warningDialog->exec(); | ||||
|             if(response == QDialog::Rejected) { | ||||
|                 canAccept = false; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if(canAccept) { | ||||
|             accept(); | ||||
|         } else { | ||||
|             attributeValue->value = oldValue; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|     void MemoryDialog::onUpdate() { | ||||
|         attributeValue->value = value; | ||||
|         accept(); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										268
									
								
								comdel/display/attribute_dialog.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										268
									
								
								comdel/display/attribute_dialog.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,268 @@ | ||||
| #ifndef ATTRIBUTE_DIALOG_H | ||||
| #define ATTRIBUTE_DIALOG_H | ||||
| 
 | ||||
| #include <QIntValidator> | ||||
| #include <QPushButton> | ||||
| #include <QComboBox> | ||||
| #include <QGroupBox> | ||||
| #include <QRadioButton> | ||||
| #include <QDialog> | ||||
| #include <QLineEdit> | ||||
| #include <QLabel> | ||||
| #include <QVBoxLayout> | ||||
| #include <utility> | ||||
| #include <comdel/domain/instanceattribute.h> | ||||
| 
 | ||||
| #include <comdel/domain/value.h> | ||||
| #include "comdel/domain/comdelvalidator.h" | ||||
| 
 | ||||
| namespace display { | ||||
| 
 | ||||
| class AttributeDialog: public QDialog { | ||||
|     domain::Value value; | ||||
| 
 | ||||
|     long long int parseInt(std::string expression) { | ||||
|         try { | ||||
|             if (expression.size() > 2) { | ||||
|                 if (expression.substr(0, 2) == "0x") { | ||||
|                     return std::stoll(expression, 0, 16); | ||||
|                 } else if (expression.substr(0, 2) == "0b") { | ||||
|                     return std::stoll(expression, 0, 2); | ||||
|                 } else { | ||||
|                     return std::stoll(expression, 0, 10); | ||||
|                 } | ||||
|             } else { | ||||
|                 return std::stoll(expression, 0, 10); | ||||
|             } | ||||
|         } catch (std::exception &e) { | ||||
|             return 0; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     domain::InstanceAttribute* attributeValue; | ||||
| 
 | ||||
| public: | ||||
|     AttributeDialog(domain::InstanceAttribute *attribute) { | ||||
| 
 | ||||
|         setAttribute(Qt::WA_DeleteOnClose); | ||||
| 
 | ||||
|         attributeValue = attribute; | ||||
| 
 | ||||
|         this->setWindowTitle(QString::fromStdString("Izmjeni " + attribute->attribute.getName())); | ||||
| 
 | ||||
|         auto layout = new QVBoxLayout(this); | ||||
|         this->setLayout(layout); | ||||
|         auto popup = *attribute->attribute.getPopup(); | ||||
| 
 | ||||
|         layout->addWidget(new QLabel(popup.getTitle().c_str())); | ||||
|         layout->addWidget(new QLabel(popup.getText().c_str())); | ||||
| 
 | ||||
|         auto type = attribute->attribute.getDefault().getType(); | ||||
|         value = attribute->value; | ||||
| 
 | ||||
|         if(attribute->attribute.getPopup()->isEnumerated()) { | ||||
|             auto* combo = new QComboBox(this); | ||||
|             auto enumeration = attribute->attribute.getPopup()->getEnumeration(); | ||||
|             for(auto entry: enumeration) { | ||||
|                 combo->addItem(QString::fromStdString(entry.getName())); | ||||
|             } | ||||
| 
 | ||||
|             connect(combo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &AttributeDialog::onEnumerationChanged); | ||||
|             layout->addWidget(combo); | ||||
| 
 | ||||
|             for(int i=0; i<enumeration.size(); i++) { | ||||
|                 if(attributeValue->value.equals(enumeration[i].getValue())) { | ||||
|                     combo->setCurrentIndex(i); | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|         } else if(!(type == domain::Value::ValueType::WIRE_REFERENCE || type == domain::Value::ValueType::BOOL)) { | ||||
| 
 | ||||
|             auto edit = new QLineEdit(this); | ||||
|             connect(edit, &QLineEdit::textChanged, this, &AttributeDialog::onTextChanged); | ||||
|             layout->addWidget(edit); | ||||
| 
 | ||||
|             switch (attribute->attribute.getDefault().getType()) { | ||||
|                 case domain::Value::ValueType::INT: | ||||
|                     edit->setValidator(new QIntValidator(-10000000, 10000000, edit)); | ||||
|                     edit->insert(std::to_string(attribute->value.asInt()).c_str()); | ||||
|                     break; | ||||
|                 case domain::Value::ValueType::STRING: | ||||
|                     edit->insert(attribute->value.asString().c_str()); | ||||
|                     break; | ||||
|             } | ||||
| 
 | ||||
|         } else if(type == domain::Value::ValueType::BOOL) { | ||||
|             auto *group = new QGroupBox(this); | ||||
| 
 | ||||
|             auto *radioLayout = new QHBoxLayout(group); | ||||
|             group->setLayout(radioLayout); | ||||
| 
 | ||||
|             auto isTrue = new QRadioButton("true", group); | ||||
|             connect(isTrue, &QRadioButton::clicked, [this]() { | ||||
|                 this->value = domain::Value::fromBool(true); | ||||
|             }); | ||||
|             auto isFalse = new QRadioButton("false", group); | ||||
|             connect(isFalse, &QRadioButton::clicked, [this]() { | ||||
|                 this->value = domain::Value::fromBool(false); | ||||
|             }); | ||||
| 
 | ||||
|             if(attribute->value.asBool()) { | ||||
|                 isTrue->setChecked(true); | ||||
|             } else { | ||||
|                 isFalse->setChecked(true); | ||||
|             } | ||||
| 
 | ||||
|             radioLayout->addWidget(isTrue); | ||||
|             radioLayout->addWidget(isFalse); | ||||
|             layout->addWidget(group); | ||||
|         } | ||||
| 
 | ||||
|         auto button = new QPushButton("Ažuriraj"); | ||||
|         connect(button, &QPushButton::clicked, this, &AttributeDialog::onUpdate); | ||||
| 
 | ||||
|         layout->addWidget(button); | ||||
|     } | ||||
| 
 | ||||
| public slots: | ||||
|     void onTextChanged(const QString& string) { | ||||
|         switch (value.getType()) { | ||||
|             case domain::Value::STRING: | ||||
|                 value.setString(string.toStdString()); | ||||
|             break; | ||||
|             case domain::Value::INT: | ||||
|                 value = domain::Value::fromInt(parseInt(string.toStdString())); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     void onEnumerationChanged(int index) { | ||||
|         value = attributeValue->attribute.getPopup()->getEnumeration()[index].getValue(); | ||||
|     } | ||||
| 
 | ||||
|     void onUpdate(); | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
|     class MemoryDialog: public QDialog { | ||||
|         domain::Value value; | ||||
| 
 | ||||
|         domain::InstanceAttribute* attributeValue; | ||||
|         std::vector<std::string> memoryInstances; | ||||
| 
 | ||||
|     public: | ||||
|         MemoryDialog(domain::InstanceAttribute *attribute, std::vector<std::shared_ptr<domain::ComponentInstance>> instances) { | ||||
|             memoryInstances = std::vector<std::string>(); | ||||
| 
 | ||||
|             setAttribute(Qt::WA_DeleteOnClose); | ||||
| 
 | ||||
|             attributeValue = attribute; | ||||
| 
 | ||||
|             this->setWindowTitle(QString::fromStdString("Izmjeni " + attribute->attribute.getName())); | ||||
| 
 | ||||
|             for(auto& instance: instances) { | ||||
|                 if(instance->component.getType() == domain::Component::MEMORY) { | ||||
|                     memoryInstances.push_back(instance->name); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             auto layout = new QVBoxLayout(this); | ||||
|             this->setLayout(layout); | ||||
|             auto popup = *attribute->attribute.getPopup(); | ||||
| 
 | ||||
|             layout->addWidget(new QLabel(popup.getTitle().c_str())); | ||||
|             layout->addWidget(new QLabel(popup.getText().c_str())); | ||||
| 
 | ||||
|             value = attribute->value; | ||||
| 
 | ||||
|             auto* combo = new QComboBox(this); | ||||
|             for(auto& entry: memoryInstances) { | ||||
|                 combo->addItem(QString::fromStdString(entry)); | ||||
|             } | ||||
|             combo->addItem("null"); | ||||
| 
 | ||||
|             connect(combo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &MemoryDialog::onMemoryChanged); | ||||
|             layout->addWidget(combo); | ||||
| 
 | ||||
|             combo->setCurrentIndex(memoryInstances.size()); | ||||
|             for(int i=0; i<memoryInstances.size(); i++) { | ||||
|                 if(attributeValue->value.asMemoryReference().has_value() && attributeValue->value.asMemoryReference() == memoryInstances[i]) { | ||||
|                     combo->setCurrentIndex(i); | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             auto button = new QPushButton("Ažuriraj"); | ||||
|             connect(button, &QPushButton::clicked, this, &MemoryDialog::onUpdate); | ||||
| 
 | ||||
|             layout->addWidget(button); | ||||
|         } | ||||
| 
 | ||||
|     public slots: | ||||
| 
 | ||||
|         void onMemoryChanged(int index) { | ||||
|             if(index == memoryInstances.size()) { | ||||
|                 value = domain::Value::fromMemoryReference(std::nullopt); | ||||
|             } else { | ||||
|                 value = domain::Value::fromMemoryReference(memoryInstances[index]); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         void onUpdate(); | ||||
| 
 | ||||
|     }; | ||||
| 
 | ||||
| 
 | ||||
|     class ErrorDialog: public QDialog { | ||||
| 
 | ||||
|     public: | ||||
|         ErrorDialog(std::vector<domain::ValidationError> errors) { | ||||
| 
 | ||||
|             setAttribute(Qt::WA_DeleteOnClose); | ||||
| 
 | ||||
|             this->setWindowTitle("Greške"); | ||||
| 
 | ||||
|             auto layout = new QVBoxLayout(this); | ||||
|             this->setLayout(layout); | ||||
| 
 | ||||
|             for(auto& err: errors) { | ||||
|                 layout->addWidget(new QLabel(QString::fromStdString(err.message), this)); | ||||
|             } | ||||
| 
 | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     class WarningDialog: public QDialog { | ||||
| 
 | ||||
|     public: | ||||
|         WarningDialog(domain::ValidationError error) { | ||||
| 
 | ||||
|             setAttribute(Qt::WA_DeleteOnClose); | ||||
| 
 | ||||
|             this->setWindowTitle("Upozorenje"); | ||||
| 
 | ||||
|             auto layout = new QVBoxLayout(this); | ||||
|             this->setLayout(layout); | ||||
| 
 | ||||
|             layout->addWidget(new QLabel(QString::fromStdString(error.message), this)); | ||||
| 
 | ||||
|             auto buttonLayout = new QHBoxLayout(this); | ||||
| 
 | ||||
|             auto okButton = new QPushButton("U redu", this); | ||||
|             auto cancelButton = new QPushButton("Odustani", this); | ||||
| 
 | ||||
|             connect(okButton, &QPushButton::clicked, [this]() { accept(); }); | ||||
|             connect(cancelButton, &QPushButton::clicked, [this]() { reject(); }); | ||||
| 
 | ||||
|             buttonLayout->addWidget(okButton); | ||||
|             buttonLayout->addWidget(cancelButton); | ||||
| 
 | ||||
|             layout->addItem(buttonLayout); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif //ATTRIBUTE_DIALOG_H
 | ||||
| @ -1,356 +1,49 @@ | ||||
| #include "component_display.h" | ||||
| #include "comdel/display/dialog/attribute_dialog.h" | ||||
| #include "comdel/display/dialog/name_dialog.h" | ||||
| #include "attribute_dialog.h" | ||||
| #include "name_dialog.h" | ||||
| #include "mainwindow.h" | ||||
| #include "application.h" | ||||
| #include "comdel/display/dialog/single_automatic_dialog.h" | ||||
| #include "comdel/display/dialog/memory_dialog.h" | ||||
| #include "message_source.h" | ||||
| 
 | ||||
| #include <QMenu> | ||||
| #include <QLine> | ||||
| #include <QPen> | ||||
| #include <QGraphicsSceneContextMenuEvent> | ||||
| #include <set> | ||||
| 
 | ||||
| #include <QGraphicsScene> | ||||
| #include <iostream> | ||||
| 
 | ||||
| namespace display { | ||||
| 
 | ||||
|     QPen connectionPen(QColor::fromRgb(150, 150, 250)); | ||||
| 
 | ||||
|     Component::Component(const std::shared_ptr<domain::ComponentInstance> &instance): instance(instance) { | ||||
|         setFlag(ItemSendsGeometryChanges, true); | ||||
|         setToolTip(QString::fromStdString(instance->name + "::" + instance->component.getDisplayName())); | ||||
|         instance->component.getDisplay().render(this, domain::ui::DisplayContext(instance.get())); | ||||
|     } | ||||
| 
 | ||||
|     void Component::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) { | ||||
|         QMenu menu; | ||||
|         menu.addAction(QMESSAGE("msg_dialog_name_update"), [this]() { | ||||
|             std::set<std::string> names; | ||||
|             for(const auto &component: Application::instance()->getSchema()->componentInstances) { | ||||
|                 names.insert(component->name); | ||||
|             } | ||||
|             auto dialog = new NameDialog(this->instance->name, names); | ||||
|             dialog->exec(); | ||||
| 
 | ||||
|             auto currentName = this->instance->name; | ||||
|             auto newName = dialog->getName(); | ||||
| 
 | ||||
|             Application::instance()->renameComponent(currentName, newName); | ||||
|             setToolTip(QString::fromStdString(instance->name + "::" + instance->component.getDisplayName())); | ||||
|         }); | ||||
|         menu.addSeparator(); | ||||
|         for (int i = 0; i < this->instance->attributes.size(); i++) { | ||||
|             auto *attr = &this->instance->attributes[i]; | ||||
|             bool enabled = attr->attribute.getPopup().has_value(); | ||||
| void Component::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) { | ||||
|     QMenu menu; | ||||
|     menu.addAction("Izmjeni ime", [this](){ | ||||
|         auto dialog = new NameDialog(this->instance.get()); | ||||
|         dialog->exec(); | ||||
|     }); | ||||
|     menu.addSeparator(); | ||||
|     for(int i=0; i<this->instance->attributes.size(); i++) { | ||||
|         auto* attr = &this->instance->attributes[i]; | ||||
|         bool enabled = attr->attribute.getPopup().has_value(); | ||||
| 
 | ||||
|         auto action = menu.addAction(QString::fromStdString("Izmjeni " + attr->name), | ||||
|                                      [attr]() { | ||||
|             if(attr->value.getType() == domain::Value::MEMORY_REFERENCE) { | ||||
|                 menu.addAction(QMESSAGE("msg_dialog_memory_update"), [attr]() { | ||||
|                     auto dialog = new MemoryDialog(MESSAGE("msg_dialog_memory_update"), | ||||
|                                                    MESSAGE("msg_dialog_actions_update"), | ||||
|                                                    attr, | ||||
|                                                    Application::instance()->getSchema()->componentInstances); | ||||
|                     dialog->exec(); | ||||
|                 }); | ||||
|                 auto dialog = new MemoryDialog(attr, MainWindow::getSchema()->componentInstances); | ||||
|                 dialog->exec(); | ||||
|             } else { | ||||
|                 std::map<std::string, std::string> params = {{"attribute", attr->attribute.getDisplayName()}}; | ||||
|                 auto action = menu.addAction(QMESSAGE_PARAM("msg_dialog_attribute_update", params), | ||||
|                     [attr]() { | ||||
|                         std::map<std::string, std::string> params = {{"attribute", attr->attribute.getDisplayName()}}; | ||||
|                         auto dialog = new AttributeDialog(MESSAGE_PARAM("msg_dialog_attribute_update", params), | ||||
|                                                           "msg_dialog_actions_update", | ||||
|                                                           attr); | ||||
|                         dialog->exec(); | ||||
|                 }); | ||||
|                 action->setEnabled(enabled); | ||||
|                 auto dialog = new AttributeDialog(attr); | ||||
|                 dialog->exec(); | ||||
|             } | ||||
|         } | ||||
|         menu.addSeparator(); | ||||
|         std::map<std::string, std::string> params = {{"name", instance->name}}; | ||||
|         menu.addAction(QMESSAGE_PARAM("msg_dialog_actions_remove_named", params), [this]() { | ||||
|             Application::instance()->removeComponent(this->instance->name); | ||||
|             auto view = dynamic_cast<Schema *>(this->scene()->views()[0]); | ||||
|             view->refreshContent(); | ||||
|         }); | ||||
| 
 | ||||
|         menu.exec(event->screenPos()); | ||||
|     } | ||||
| 
 | ||||
|     void Pin::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) { | ||||
|         QMenu menu; | ||||
| 
 | ||||
|         auto pinConnections = Application::instance()->getSchema()->getConnections(componentInstance->name, pin.getName()); | ||||
| 
 | ||||
|         if(isSingleAutomatic(pinConnections)) { | ||||
|             auto *update = menu.addMenu(QMESSAGE("msg_pin_update")); | ||||
|             auto *remove = menu.addMenu(QMESSAGE("msg_pin_remove")); | ||||
|             for (auto pinConnection: pinConnections) { | ||||
|                 // this always must be true as only directConnections can be connected multiple times
 | ||||
|                 if (auto directConnection = dynamic_cast<domain::DirectConnectionInstance *>(pinConnection)) { | ||||
|                     if (directConnection->bus->bus.getType() == domain::Bus::SINGLE_AUTOMATIC) { | ||||
|                         auto params = MessageSource::instance()->map( | ||||
|                                 {{"wire1", directConnection->attributes[0].value}, | ||||
|                                  {"wire2", directConnection->attributes[1].value}} | ||||
|                         ); | ||||
|                         update->addAction(QMESSAGE_PARAM("msg_sa_pin_update_title", params), | ||||
|                                           [directConnection]() { | ||||
|                             auto params = MessageSource::instance()->map( | ||||
|                                     {{"wire1", directConnection->attributes[0].value}, | ||||
|                                      {"wire2", directConnection->attributes[1].value}} | ||||
|                             ); | ||||
|                             auto dialog = new SingleAutomaticDialog(MESSAGE_PARAM("msg_sa_pin_update_title", params), | ||||
|                                                                     MESSAGE("msg_pin_update_action"), | ||||
|                                                                     directConnection->attributes); | ||||
|                             dialog->exec(); | ||||
|                         }); | ||||
|                         remove->addAction(QMESSAGE_PARAM("msg_sa_pin_remove_title", params), | ||||
|                                           [this, directConnection]() { | ||||
|                                               Application::instance()->removeConnection(directConnection); | ||||
|                                               auto view = dynamic_cast<Schema *>(this->scene()->views()[0]); | ||||
|                                               view->refreshContent(); | ||||
|                                           }); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } else if(!pinConnections.empty()) { | ||||
|             auto pinConnection = pinConnections[0]; | ||||
|             if(auto busConnection = dynamic_cast<domain::BusConnectionInstance*>(pinConnection)) { | ||||
|                 menu.addSection(QString::fromStdString(busConnection->bus->name)); | ||||
|             } else if(auto directConnection = dynamic_cast<domain::DirectConnectionInstance*>(pinConnection)) { | ||||
|                 if(directConnection->instance == componentInstance.get()) { | ||||
|                     menu.addSection(QString::fromStdString(directConnection->secondInstance->name + "." + directConnection->connection.getSecondComponent()->pin)); | ||||
|                 } else { | ||||
|                     menu.addSection(QString::fromStdString(directConnection->instance->name + "." + directConnection->connection.getComponent().pin)); | ||||
|                 } | ||||
|             } | ||||
|             for (int i = 0; i < pinConnection->attributes.size(); i++) { | ||||
|                 auto *attr = &pinConnection->attributes[i]; | ||||
|                 std::map<std::string, std::string> params = {{"name", attr->attribute.getDisplayName()}}; | ||||
|                 menu.addAction(QMESSAGE_PARAM("msg_dialog_actions_update_named", params), | ||||
|                                [attr]() { | ||||
|                                    std::map<std::string, std::string> params = {{"name", attr->attribute.getDisplayName()}}; | ||||
|                                    auto dialog = new AttributeDialog(MESSAGE_PARAM("msg_dialog_actions_update_named", params), "msg_pin_update_action", attr); | ||||
|                                 dialog->exec(); | ||||
|                 }); | ||||
|             } | ||||
|             menu.addAction(QMESSAGE("msg_pin_remove_action"), [this, pinConnection]() { | ||||
|                 Application::instance()->removeConnection(pinConnection); | ||||
|                 auto view = dynamic_cast<Schema *>(this->scene()->views()[0]); | ||||
|                 view->refreshContent(); | ||||
|             }); | ||||
|         } | ||||
|         menu.exec(event->screenPos()); | ||||
|     } | ||||
| 
 | ||||
|     void Pin::mousePressEvent(QGraphicsSceneMouseEvent *event) { | ||||
|         if (event->button() == Qt::MouseButton::LeftButton) { | ||||
|             auto view = dynamic_cast<Schema *>(this->scene()->views()[0]); | ||||
|             view->state = Schema::CREATING_CONNECTION; | ||||
|             view->context.pin = this; | ||||
|             view->context.startingPoint = dynamic_cast<ComponentGroup *>(this->parentItem())->pos() + | ||||
|                                           QPointF(pin.getDisplayPin().getConnectionX(), | ||||
|                                                   pin.getDisplayPin().getConnectionY()); | ||||
|             view->context.line = new QGraphicsLineItem(QLineF(view->context.startingPoint, event->scenePos())); | ||||
|             view->context.line->setPen(QPen(QColor::fromRgb(100, 100, 250), 1, Qt::PenStyle::DashLine)); | ||||
|             view->context.line->setZValue(1000); | ||||
|             this->scene()->addItem(view->context.line); | ||||
| 
 | ||||
|             view->showConnectable(this); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void Pin::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { | ||||
|         auto view = dynamic_cast<Schema *>(this->scene()->views()[0]); | ||||
|         if (view->state == Schema::CREATING_CONNECTION) { | ||||
|             auto line = view->context.line->line(); | ||||
|             line.setP2(event->scenePos()); | ||||
|             view->context.line->setLine(line); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void Pin::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { | ||||
|         if (event->button() == Qt::MouseButton::LeftButton) { | ||||
|             auto view = dynamic_cast<Schema *>(this->scene()->views()[0]); | ||||
|             view->state = Schema::DEFAULT; | ||||
|             this->scene()->removeItem(view->context.line); | ||||
|             delete view->context.line; | ||||
|             view->removeConnectable(event->scenePos()); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     domain::Pin &Pin::getPin() { | ||||
|         return pin; | ||||
|     } | ||||
| 
 | ||||
|     domain::ComponentInstance *Pin::getComponentInstance() { | ||||
|         return componentInstance.get(); | ||||
|     } | ||||
| 
 | ||||
|     bool Pin::isSingleAutomatic(std::vector<domain::ConnectionInstance *> pinConnections) { | ||||
|         if(pinConnections.empty()) { | ||||
|             return false; | ||||
|         } | ||||
|         auto pinConnection = pinConnections[0]; | ||||
|         if(auto directConnection = dynamic_cast<domain::DirectConnectionInstance*>(pinConnection)) { | ||||
|             return directConnection->bus->bus.getType() == domain::Bus::SINGLE_AUTOMATIC; | ||||
|         } else { | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     Bus::Bus(const std::shared_ptr<domain::BusInstance> &instance): busInstance(instance) { | ||||
|         instance->bus.getDisplayBus()->render(this, instance->size); | ||||
|         setToolTip(QString::fromStdString(busInstance->name + "::" + busInstance->bus.getName())); | ||||
|     } | ||||
| 
 | ||||
|     void Bus::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) { | ||||
|         QMenu menu; | ||||
|         menu.addAction(QMESSAGE("msg_dialog_name_update"), [this]() { | ||||
|             std::set<std::string> names; | ||||
|             for(const auto &component: Application::instance()->getSchema()->busInstances) { | ||||
|                 names.insert(component->name); | ||||
|             } | ||||
|             auto dialog = new NameDialog(this->busInstance->name, names); | ||||
|             dialog->exec(); | ||||
| 
 | ||||
|             auto currentName = this->busInstance->name; | ||||
|             auto newName = dialog->getName(); | ||||
| 
 | ||||
|             Application::instance()->renameBus(currentName, newName); | ||||
|             setToolTip(QString::fromStdString(busInstance->name + "::" + busInstance->bus.getDisplayName())); | ||||
|         }); | ||||
|         menu.addSeparator(); | ||||
| 
 | ||||
|         std::map<std::string, std::string> params = {{"name", busInstance->name}}; | ||||
|         menu.addAction(QMESSAGE_PARAM("msg_dialog_actions_remove_named", params), [this]() { | ||||
|             Application::instance()->removeBus(this->busInstance->name); | ||||
|             auto view = dynamic_cast<Schema *>(this->scene()->views()[0]); | ||||
|             view->refreshContent(); | ||||
|         }); | ||||
|         menu.exec(event->screenPos()); | ||||
|     } | ||||
| 
 | ||||
|     QVariant BusGroup::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) { | ||||
|         if (change == ItemPositionChange && scene()) { | ||||
|             // value is the new position.
 | ||||
|             QPoint newPos = value.toPointF().toPoint(); | ||||
|             busInstance->position.first = newPos.x(); | ||||
|             busInstance->position.second = newPos.y(); | ||||
| 
 | ||||
|             auto view = dynamic_cast<Schema *>(scene()->views()[0]); | ||||
|             view->updateConnections(); | ||||
|         } | ||||
|         return QGraphicsItem::itemChange(change, value); | ||||
|     } | ||||
| 
 | ||||
|     BusGroup::BusGroup(const std::shared_ptr<domain::BusInstance> &instance) : busInstance(instance) { | ||||
|         setFlag(ItemIsMovable, true); | ||||
|         setFlag(ItemSendsGeometryChanges, true); | ||||
| 
 | ||||
|         setHandlesChildEvents(false); | ||||
| 
 | ||||
|         bus = new display::Bus(instance); | ||||
|         addToGroup(bus); | ||||
| 
 | ||||
|         setPos(instance->position.first, instance->position.second); | ||||
|         action->setEnabled(enabled); | ||||
|     } | ||||
|     menu.exec(event->screenPos()); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|     QVariant ComponentGroup::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) { | ||||
|         if (change == ItemPositionChange && scene()) { | ||||
|             // value is the new position.
 | ||||
|             QPoint newPos = value.toPointF().toPoint(); | ||||
|             componentInstance->position.first = newPos.x(); | ||||
|             componentInstance->position.second = newPos.y(); | ||||
| 
 | ||||
|             auto view = dynamic_cast<Schema *>(scene()->views()[0]); | ||||
|             view->updateConnections(); | ||||
|         } | ||||
|         return QGraphicsItem::itemChange(change, value); | ||||
|     } | ||||
| 
 | ||||
|     std::shared_ptr<domain::ComponentInstance> ComponentGroup::getComponentInstance() { | ||||
|         return componentInstance; | ||||
|     } | ||||
| 
 | ||||
|     std::vector<display::Pin *> &ComponentGroup::getPins() { | ||||
|         return pins; | ||||
|     } | ||||
| 
 | ||||
|     ComponentGroup::ComponentGroup(const std::shared_ptr<domain::ComponentInstance> &instance): componentInstance( | ||||
|             instance) { | ||||
|         setFlag(ItemIsMovable, true); | ||||
|         setFlag(ItemSendsGeometryChanges, true); | ||||
| 
 | ||||
|         setHandlesChildEvents(false); | ||||
| 
 | ||||
|         addToGroup(new display::Component(instance)); | ||||
| 
 | ||||
|         for (auto &pin: instance->component.getPins()) { | ||||
|             pins.push_back(new display::Pin(pin, componentInstance)); | ||||
|             addToGroup(pins.back()); | ||||
|         } | ||||
| 
 | ||||
|         setPos(instance->position.first, instance->position.second); | ||||
|     } | ||||
| 
 | ||||
|     BusConnection::BusConnection(domain::BusConnectionInstance *connection, ComponentGroup *component, BusGroup *bus): connection( | ||||
|             connection), component(component), bus(bus) { | ||||
|         updateConnection(); | ||||
|         setPen(connectionPen); | ||||
|         setZValue(-1); | ||||
|         setHandlesChildEvents(false); | ||||
|     } | ||||
| 
 | ||||
|     void BusConnection::updateConnection() { | ||||
|         auto busPosition = bus->boundingRect(); | ||||
|         auto pin = connection->instance->component.getPin( | ||||
|                 connection->connection.getComponent().pin).getDisplayPin(); | ||||
| 
 | ||||
|         setLine(connection->instance->position.first + pin.getConnectionX(), | ||||
|                 connection->instance->position.second + pin.getConnectionY(), | ||||
|                 connection->bus->position.first + busPosition.width() / 2, | ||||
|                 connection->bus->position.second + busPosition.height() / 2); | ||||
| 
 | ||||
|         connection->start.first = connection->instance->position.first + pin.getConnectionX(); | ||||
|         connection->start.second = connection->instance->position.second + pin.getConnectionY(); | ||||
|         connection->end.first = connection->bus->position.first + busPosition.width() / 2; | ||||
|         connection->end.second = connection->bus->position.second + busPosition.height() / 2; | ||||
|     } | ||||
| 
 | ||||
|     DirectConnection::DirectConnection(domain::DirectConnectionInstance *connection, ComponentGroup *first, | ||||
|                                        ComponentGroup *second): connection(connection), first(first), second(second) { | ||||
|         updateConnection(); | ||||
|         setPen(connectionPen); | ||||
|         setZValue(-1); | ||||
|         setHandlesChildEvents(false); | ||||
|     } | ||||
| 
 | ||||
|     void DirectConnection::updateConnection() { | ||||
|         domain::ui::Pin pin1, pin2; | ||||
|         if(connection->connection.getComponent().component == connection->instance->component.getName()) { | ||||
|             pin1 = connection->instance->component.getPin( | ||||
|                     connection->connection.getComponent().pin).getDisplayPin(); | ||||
|             pin2 = connection->secondInstance->component.getPin( | ||||
|                     connection->connection.getSecondComponent()->pin).getDisplayPin(); | ||||
| 
 | ||||
|         } else { | ||||
|             pin1 = connection->instance->component.getPin( | ||||
|                     connection->connection.getSecondComponent()->pin).getDisplayPin(); | ||||
|             pin2 = connection->secondInstance->component.getPin( | ||||
|                     connection->connection.getComponent().pin).getDisplayPin(); | ||||
|         } | ||||
| 
 | ||||
|         setLine(connection->instance->position.first + pin1.getConnectionX(), | ||||
|                 connection->instance->position.second + pin1.getConnectionY(), | ||||
|                 connection->secondInstance->position.first + pin2.getConnectionX(), | ||||
|                 connection->secondInstance->position.second + pin2.getConnectionY()); | ||||
| 
 | ||||
|         connection->start.first = connection->instance->position.first + pin1.getConnectionX(); | ||||
|         connection->start.second = connection->instance->position.second + pin1.getConnectionY(); | ||||
|         connection->end.first = connection->secondInstance->position.first + pin2.getConnectionX(); | ||||
|         connection->end.second = connection->secondInstance->position.second + pin2.getConnectionY(); | ||||
|     } | ||||
| void Bus::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) { | ||||
|     QMenu menu; | ||||
|     menu.addAction("Izmjeni ime", [this](){ | ||||
|         auto dialog = new NameDialog(this->busInstance.get()); | ||||
|         dialog->exec(); | ||||
|     }); | ||||
|     menu.exec(event->screenPos()); | ||||
| } | ||||
| 
 | ||||
| } // namespace display
 | ||||
|  | ||||
| @ -2,114 +2,78 @@ | ||||
| #define DISPLAY_COMPONENT_H | ||||
| 
 | ||||
| #include <comdel/domain/instance.h> | ||||
| #include <comdel/domain/wireinstance.h> | ||||
| 
 | ||||
| #include <QGraphicsItemGroup> | ||||
| #include <QGraphicsSceneMouseEvent> | ||||
| #include <QGraphicsSceneMouseEvent> | ||||
| #include <utility> | ||||
| #include "comdel/domain/connection_instance.h" | ||||
| 
 | ||||
| namespace display { | ||||
| 
 | ||||
|     class Pin : public QGraphicsItemGroup { | ||||
|     private: | ||||
|         domain::Pin pin; | ||||
|         std::shared_ptr<domain::ComponentInstance> componentInstance; | ||||
| class Pin: public QGraphicsItemGroup | ||||
| { | ||||
| private: | ||||
|     domain::Pin pin; | ||||
| public: | ||||
|     Pin(domain::Pin pin): pin(pin) { | ||||
|         pin.getDisplay().render(this); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
|     public: | ||||
|         Pin(domain::Pin pin, std::shared_ptr<domain::ComponentInstance> componentInstance) : pin(pin), componentInstance(std::move(componentInstance)) { | ||||
|             pin.getDisplayPin().render(this); | ||||
|             this->setToolTip(QString::fromStdString(pin.getTooltip())); | ||||
| class Component: public QGraphicsItemGroup | ||||
| { | ||||
| private: | ||||
|     std::shared_ptr<domain::ComponentInstance> instance; | ||||
| public: | ||||
|     Component(const std::shared_ptr<domain::ComponentInstance>& instance): instance(instance) { | ||||
|         instance->component.getDisplay().render(this); | ||||
|     } | ||||
|     void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override; | ||||
| }; | ||||
| 
 | ||||
| class Bus: public QGraphicsItemGroup | ||||
| { | ||||
|     std::shared_ptr<domain::BusInstance> busInstance; | ||||
| public: | ||||
|     Bus(const std::shared_ptr<domain::BusInstance>& instance): busInstance(instance) { | ||||
|         instance->bus.getDisplay()->render(this); | ||||
|     } | ||||
|     void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override; | ||||
| }; | ||||
| 
 | ||||
| class ComponentGroup: public QGraphicsItemGroup | ||||
| { | ||||
| private: | ||||
|     std::shared_ptr<domain::ComponentInstance> componentInstance; | ||||
| 
 | ||||
| public: | ||||
|     explicit ComponentGroup(const std::shared_ptr<domain::ComponentInstance>& instance): componentInstance(instance) { | ||||
|         setFlag(ItemIsMovable, true); | ||||
|         setHandlesChildEvents(false); | ||||
| 
 | ||||
|         addToGroup(new display::Component(instance)); | ||||
| 
 | ||||
|         for(auto &pin: instance->component.getPins()) { | ||||
|             addToGroup(new display::Pin(pin)); | ||||
|         } | ||||
| 
 | ||||
|         void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override; | ||||
|         setPos(instance->position.first, instance->position.second); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
|         void mousePressEvent(QGraphicsSceneMouseEvent *event) override; | ||||
| class BusGroup: public QGraphicsItemGroup | ||||
| { | ||||
| private: | ||||
|     std::shared_ptr<domain::BusInstance> busInstance; | ||||
| 
 | ||||
|         void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override; | ||||
| public: | ||||
|     explicit BusGroup(const std::shared_ptr<domain::BusInstance>& instance): busInstance(instance) { | ||||
|         setFlag(ItemIsMovable, true); | ||||
|         setHandlesChildEvents(false); | ||||
| 
 | ||||
|         void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override; | ||||
| 
 | ||||
|         domain::Pin &getPin(); | ||||
| 
 | ||||
|         domain::ComponentInstance *getComponentInstance(); | ||||
| 
 | ||||
|         bool isSingleAutomatic(std::vector<domain::ConnectionInstance *> pinConnections); | ||||
|     }; | ||||
| 
 | ||||
|     class Component : public QGraphicsItemGroup { | ||||
|     private: | ||||
|         std::shared_ptr<domain::ComponentInstance> instance; | ||||
|     public: | ||||
|         explicit Component(const std::shared_ptr<domain::ComponentInstance> &instance); | ||||
| 
 | ||||
|         void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override; | ||||
| 
 | ||||
|     }; | ||||
| 
 | ||||
|     class Bus : public QGraphicsItemGroup { | ||||
|         std::shared_ptr<domain::BusInstance> busInstance; | ||||
|     public: | ||||
|         explicit Bus(const std::shared_ptr<domain::BusInstance> &instance); | ||||
| 
 | ||||
|         void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override; | ||||
|     }; | ||||
| 
 | ||||
|     class ComponentGroup : public QGraphicsItemGroup { | ||||
|     private: | ||||
|         std::shared_ptr<domain::ComponentInstance> componentInstance; | ||||
|         std::vector<display::Pin *> pins; | ||||
| 
 | ||||
|     public: | ||||
| 
 | ||||
|         std::shared_ptr<domain::ComponentInstance> getComponentInstance(); | ||||
| 
 | ||||
|         std::vector<display::Pin *> &getPins(); | ||||
| 
 | ||||
|         explicit ComponentGroup(const std::shared_ptr<domain::ComponentInstance> &instance); | ||||
| 
 | ||||
|     protected: | ||||
|         QVariant itemChange(GraphicsItemChange change, const QVariant &value) override; | ||||
| 
 | ||||
|     }; | ||||
| 
 | ||||
|     class BusGroup : public QGraphicsItemGroup { | ||||
|     private: | ||||
|         std::shared_ptr<domain::BusInstance> busInstance; | ||||
|         display::Bus *bus; | ||||
| 
 | ||||
|     public: | ||||
|         explicit BusGroup(const std::shared_ptr<domain::BusInstance> &instance); | ||||
| 
 | ||||
|     protected: | ||||
|         QVariant itemChange(GraphicsItemChange change, const QVariant &value) override; | ||||
|     }; | ||||
| 
 | ||||
|     class BusConnection : public QGraphicsLineItem { | ||||
|     private: | ||||
|         domain::BusConnectionInstance *connection; | ||||
|         ComponentGroup *component; | ||||
|         BusGroup *bus; | ||||
| 
 | ||||
|     public: | ||||
|         BusConnection(domain::BusConnectionInstance *connection, ComponentGroup *component, BusGroup *bus); | ||||
| 
 | ||||
|         void updateConnection(); | ||||
|     }; | ||||
| 
 | ||||
| 
 | ||||
|     class DirectConnection : public QGraphicsLineItem { | ||||
|     private: | ||||
|         domain::DirectConnectionInstance *connection; | ||||
|         ComponentGroup *first; | ||||
|         ComponentGroup *second; | ||||
| 
 | ||||
|     public: | ||||
|         DirectConnection(domain::DirectConnectionInstance *connection, ComponentGroup *first, ComponentGroup *second); | ||||
| 
 | ||||
|         void updateConnection(); | ||||
|     }; | ||||
|         addToGroup(new display::Bus(instance)); | ||||
| 
 | ||||
|         setPos(instance->position.first, instance->position.second); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| } // namespace display
 | ||||
| 
 | ||||
|  | ||||
| @ -1,182 +0,0 @@ | ||||
| #include "attribute_dialog.h" | ||||
| #include "mainwindow.h" | ||||
| 
 | ||||
| #include "application.h" | ||||
| #include "error_dialog.h" | ||||
| #include "warning_dialog.h" | ||||
| #include "message_source.h" | ||||
| #include <stdexcept> | ||||
| 
 | ||||
| namespace display { | ||||
| 
 | ||||
|     long long int parseInt(std::string expression) { | ||||
|         try { | ||||
|             if (expression.size() > 2) { | ||||
|                 if (expression.substr(0, 2) == "0x") { | ||||
|                     return std::stoll(expression, nullptr, 16); | ||||
|                 } else if (expression.substr(0, 2) == "0b") { | ||||
|                     return std::stoll(expression, nullptr, 2); | ||||
|                 } else { | ||||
|                     return std::stoll(expression, nullptr, 10); | ||||
|                 } | ||||
|             } else { | ||||
|                 return std::stoll(expression, nullptr, 10); | ||||
|             } | ||||
|         } catch (std::exception &e) { | ||||
|             return 0; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     AttributeDialog::AttributeDialog(std::string title, std::string action, domain::InstanceAttribute *attribute): | ||||
|             GenericDialog(title, action), attributeValue(attribute), value(attribute->value), popup(*attribute->attribute.getPopup()) { | ||||
| 
 | ||||
|         auto *contentLayout = new QVBoxLayout(); | ||||
|         content->setLayout(contentLayout); | ||||
| 
 | ||||
|         contentLayout->addWidget(new QLabel(popup.getTitle().c_str())); | ||||
|         contentLayout->addWidget(new QLabel(popup.getText().c_str())); | ||||
| 
 | ||||
|         auto type = attribute->value.getType(); | ||||
| 
 | ||||
|         if(popup.isEnumerated()) { | ||||
|             contentLayout->addWidget(setupEnumeration()); | ||||
|         } else if(type == domain::Value::INT || type == domain::Value::STRING) { | ||||
|             contentLayout->addWidget(setupLineEdit(type)); | ||||
|         } else if(type == domain::Value::BOOL) { | ||||
|             contentLayout->addWidget(setupBool()); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     bool AttributeDialog::onUpdate() { | ||||
|         auto validationErrors = validate(); | ||||
|         if (validationErrors.empty()) { | ||||
|             attributeValue->value = value; | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         std::vector<domain::ValidationError> errors, warnings; | ||||
|         for (auto &err: validationErrors) { | ||||
|             if (err.type == domain::Action::ERROR) { | ||||
|                 errors.push_back(err); | ||||
|             } else { | ||||
|                 warnings.push_back(err); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if (!errors.empty()) { | ||||
|             auto errorDialog = new ErrorDialog(errors); | ||||
|             errorDialog->exec(); | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         bool canAccept = true; | ||||
|         for (auto &warning: warnings) { | ||||
|             auto warningDialog = new WarningDialog(warning); | ||||
|             int response = warningDialog->exec(); | ||||
|             if (response == QDialog::Rejected) { | ||||
|                 canAccept = false; | ||||
|             } | ||||
|         } | ||||
|         if(canAccept) { | ||||
|             attributeValue->value = value; | ||||
|         } | ||||
|         return canAccept; | ||||
|     } | ||||
| 
 | ||||
|     void AttributeDialog::onTextChanged(const QString &string) { | ||||
|         switch (value.getType()) { | ||||
|             case domain::Value::STRING: | ||||
|                 value.setString(string.toStdString()); | ||||
|                 break; | ||||
|             case domain::Value::INT: | ||||
|                 value = domain::Value::fromInt(parseInt(string.toStdString())); | ||||
|                 break; | ||||
|             default: | ||||
|                 throw std::runtime_error("invalid value type in text change"); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void AttributeDialog::onEnumerationChanged(int index) { | ||||
|         value = attributeValue->attribute.getPopup()->getEnumeration()[index].getValue(); | ||||
|     } | ||||
| 
 | ||||
|     QComboBox *AttributeDialog::setupEnumeration() { | ||||
|         auto *combo = new QComboBox(this); | ||||
| 
 | ||||
|         auto enumeration = popup.getEnumeration(); | ||||
|         for (auto entry: enumeration) { | ||||
|             combo->addItem(QString::fromStdString(entry.getName())); | ||||
|         } | ||||
|         connect(combo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, | ||||
|                 &AttributeDialog::onEnumerationChanged); | ||||
| 
 | ||||
|         for (int i = 0; i < enumeration.size(); i++) { | ||||
|             if (attributeValue->value.equals(enumeration[i].getValue())) { | ||||
|                 combo->setCurrentIndex(i); | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return combo; | ||||
|     } | ||||
| 
 | ||||
|     QLineEdit *AttributeDialog::setupLineEdit(domain::Value::ValueType type) { | ||||
|         auto edit = new QLineEdit(this); | ||||
|         connect(edit, &QLineEdit::textChanged, this, &AttributeDialog::onTextChanged); | ||||
| 
 | ||||
|         switch (type) { | ||||
|             case domain::Value::ValueType::INT: | ||||
|                 edit->setValidator(new QIntValidator(-10000000, 10000000, edit)); | ||||
|                 edit->insert(std::to_string(value.asInt()).c_str()); | ||||
|                 break; | ||||
|             case domain::Value::ValueType::STRING: | ||||
|                 edit->insert(value.asString().c_str()); | ||||
|                 break; | ||||
|         } | ||||
|         return edit; | ||||
|     } | ||||
| 
 | ||||
|     QGroupBox *AttributeDialog::setupBool() { | ||||
|         auto *group = new QGroupBox(this); | ||||
| 
 | ||||
|         auto *radioLayout = new QHBoxLayout(group); | ||||
|         group->setLayout(radioLayout); | ||||
| 
 | ||||
|         auto isTrue = new QRadioButton(QMESSAGE("msg_boolean_true"), group); | ||||
|         connect(isTrue, &QRadioButton::clicked, [this]() { | ||||
|             this->value = domain::Value::fromBool(true); | ||||
|         }); | ||||
|         auto isFalse = new QRadioButton(QMESSAGE("msg_boolean_false"), group); | ||||
|         connect(isFalse, &QRadioButton::clicked, [this]() { | ||||
|             this->value = domain::Value::fromBool(false); | ||||
|         }); | ||||
| 
 | ||||
|         if (value.asBool()) { | ||||
|             isTrue->setChecked(true); | ||||
|         } else { | ||||
|             isFalse->setChecked(true); | ||||
|         } | ||||
| 
 | ||||
|         radioLayout->addWidget(isTrue); | ||||
|         radioLayout->addWidget(isFalse); | ||||
| 
 | ||||
|         return group; | ||||
|     } | ||||
| 
 | ||||
|     std::vector<domain::ValidationError> AttributeDialog::validate() { | ||||
|         domain::ComdelValidator validator(domain::getSupportedValidators()); | ||||
| 
 | ||||
|         auto currentValue = attributeValue->value; | ||||
|         attributeValue->value = value; | ||||
|         domain::ValidationContext context; | ||||
| 
 | ||||
|         for (auto &addressSpace: Application::instance()->getLibrary()->getAddressSpaces()) { | ||||
|             context.addressSpaces.insert(std::make_pair(addressSpace.getName(), addressSpace)); | ||||
|         } | ||||
| 
 | ||||
|         auto errors = validator.validateAttribute(attributeValue, context); | ||||
|         attributeValue->value = currentValue; | ||||
|         return errors; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,47 +0,0 @@ | ||||
| #ifndef ATTRIBUTE_DIALOG_H | ||||
| #define ATTRIBUTE_DIALOG_H | ||||
| 
 | ||||
| #include <QIntValidator> | ||||
| #include <QPushButton> | ||||
| #include <QComboBox> | ||||
| #include <QGroupBox> | ||||
| #include <QRadioButton> | ||||
| #include <QDialog> | ||||
| #include <QLineEdit> | ||||
| #include <QLabel> | ||||
| #include <QVBoxLayout> | ||||
| #include <utility> | ||||
| #include "comdel/domain/instance_attribute.h" | ||||
| 
 | ||||
| #include "comdel/domain/value.h" | ||||
| #include "comdel/domain/comdel_validator.h" | ||||
| #include "generic_dialog.h" | ||||
| 
 | ||||
| namespace display { | ||||
| 
 | ||||
|     class AttributeDialog : public GenericDialog { | ||||
|     public: | ||||
|         AttributeDialog(std::string title, std::string action, domain::InstanceAttribute *attribute); | ||||
| 
 | ||||
|     public slots: | ||||
|         void onTextChanged(const QString &string); | ||||
|         void onEnumerationChanged(int index); | ||||
| 
 | ||||
|     protected: | ||||
|         bool onUpdate() override; | ||||
| 
 | ||||
|     private: | ||||
|         QComboBox *setupEnumeration(); | ||||
|         QLineEdit *setupLineEdit(domain::Value::ValueType type); | ||||
|         QGroupBox *setupBool(); | ||||
| 
 | ||||
|         std::vector<domain::ValidationError> validate(); | ||||
| 
 | ||||
|         domain::Value value; | ||||
|         domain::InstanceAttribute *attributeValue; | ||||
|         domain::Popup popup; | ||||
|     }; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif //ATTRIBUTE_DIALOG_H
 | ||||
| @ -1,34 +0,0 @@ | ||||
| #include <QVBoxLayout> | ||||
| #include <QLabel> | ||||
| #include <QPlainTextEdit> | ||||
| #include "error_dialog.h" | ||||
| 
 | ||||
| namespace display { | ||||
| 
 | ||||
|     ErrorDialog::ErrorDialog(std::vector<domain::ValidationError> errors) | ||||
|         : GenericDialog("msg_dialog_error_title", std::nullopt, "msg_dialog_error_close") { | ||||
| 
 | ||||
|         auto contentLayout = new QVBoxLayout(); | ||||
|         content->setLayout(contentLayout); | ||||
| 
 | ||||
|         for (auto &err: errors) { | ||||
|             contentLayout->addWidget(new QLabel(QString::fromStdString(err.message), this)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     ErrorDialog::ErrorDialog(std::ostringstream& errorStream) | ||||
|             : GenericDialog("msg_dialog_error_title", std::nullopt, "msg_dialog_error_close") { | ||||
| 
 | ||||
|         auto contentLayout = new QVBoxLayout(); | ||||
|         content->setLayout(contentLayout); | ||||
| 
 | ||||
|         setMinimumWidth(1000); | ||||
| 
 | ||||
|         auto log = new QPlainTextEdit(); | ||||
|         log->setFont(QFont("Courier")); | ||||
|         log->appendPlainText(QString::fromStdString(errorStream.str())); | ||||
|         log->setReadOnly(true); | ||||
|         contentLayout->addWidget(log); | ||||
|     } | ||||
| 
 | ||||
| } // display
 | ||||
| @ -1,22 +0,0 @@ | ||||
| #ifndef SCHEMEEDITOR_ERROR_DIALOG_H | ||||
| #define SCHEMEEDITOR_ERROR_DIALOG_H | ||||
| 
 | ||||
| #include "generic_dialog.h" | ||||
| #include "comdel/domain/comdel_validator.h" | ||||
| #include <sstream> | ||||
| 
 | ||||
| 
 | ||||
| namespace display { | ||||
| 
 | ||||
|     class ErrorDialog : public GenericDialog { | ||||
|     public: | ||||
|         ErrorDialog(std::vector<domain::ValidationError> errors); | ||||
|         ErrorDialog(std::ostringstream& errorStream); | ||||
| 
 | ||||
|     protected: | ||||
|         bool onUpdate() override { return true; } | ||||
|     }; | ||||
| 
 | ||||
| } // display
 | ||||
| 
 | ||||
| #endif //SCHEMEEDITOR_ERROR_DIALOG_H
 | ||||
| @ -1,35 +0,0 @@ | ||||
| #include <QVBoxLayout> | ||||
| #include "generic_dialog.h" | ||||
| 
 | ||||
| #include "message_source.h" | ||||
| 
 | ||||
| display::GenericDialog::GenericDialog(std::string title, std::optional<std::string> action, std::string cancel) { | ||||
|     setAttribute(Qt::WA_DeleteOnClose); | ||||
|     setWindowTitle(QMESSAGE(title)); | ||||
| 
 | ||||
|     setLayout(new QVBoxLayout()); | ||||
|     content = new QWidget(this); | ||||
|     layout()->addWidget(content); | ||||
| 
 | ||||
|     auto actionWidget = new QWidget(this); | ||||
|     auto actionBar = new QHBoxLayout(actionWidget); | ||||
|     layout()->addWidget(actionWidget); | ||||
| 
 | ||||
|     // if action isn't defined only close button is offered
 | ||||
|     if(action.has_value()) { | ||||
|         okButton = new QPushButton(QMESSAGE(*action), this); | ||||
|         connect(okButton, &QPushButton::clicked, this, [this](){ | ||||
|             if(this->onUpdate()) { | ||||
|                 this->accept(); | ||||
|             } | ||||
|         }); | ||||
|         actionBar->addWidget(okButton); | ||||
|     } | ||||
|     cancelButton = new QPushButton(QMESSAGE(cancel), this); | ||||
|     connect(cancelButton, &QPushButton::clicked, [this]() { reject(); }); | ||||
|     actionBar->addWidget(cancelButton); | ||||
| } | ||||
| 
 | ||||
| void display::GenericDialog::setOkButtonDisabled(bool disabled) { | ||||
|     okButton->setDisabled(disabled); | ||||
| } | ||||
| @ -1,33 +0,0 @@ | ||||
| #ifndef SCHEMEEDITOR_GENERIC_DIALOG_H | ||||
| #define SCHEMEEDITOR_GENERIC_DIALOG_H | ||||
| 
 | ||||
| #include <QDialog> | ||||
| #include <QWidget> | ||||
| #include <QPushButton> | ||||
| 
 | ||||
| #include <optional> | ||||
| 
 | ||||
| namespace display { | ||||
| 
 | ||||
|     class GenericDialog: public QDialog { | ||||
|     public: | ||||
| 
 | ||||
|         explicit GenericDialog(std::string title, | ||||
|                                std::optional<std::string> action = "msg_dialog_actions_update", | ||||
|                                std::string cancel = "msg_dialog_actions_cancel"); | ||||
| 
 | ||||
|     protected: | ||||
|         void setOkButtonDisabled(bool disabled); | ||||
|         virtual bool onUpdate() = 0; | ||||
| 
 | ||||
|     private: | ||||
|         QPushButton *okButton; | ||||
|         QPushButton *cancelButton; | ||||
| 
 | ||||
|     protected: | ||||
|         QWidget *content; | ||||
|     }; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif //SCHEMEEDITOR_GENERIC_DIALOG_H
 | ||||
| @ -1,60 +0,0 @@ | ||||
| #include <QVBoxLayout> | ||||
| #include <QLabel> | ||||
| #include "memory_dialog.h" | ||||
| #include "message_source.h" | ||||
| 
 | ||||
| namespace display { | ||||
| 
 | ||||
| 
 | ||||
|     MemoryDialog::MemoryDialog(std::string title, std::string action, domain::InstanceAttribute *attribute, | ||||
|                                std::vector<std::shared_ptr<domain::ComponentInstance>> instances) | ||||
|                                : GenericDialog(title, action), value(attribute->value), attributeValue(attribute), popup(*attribute->attribute.getPopup()) { | ||||
| 
 | ||||
|         for (auto &instance: instances) { | ||||
|             if (instance->component.getType() == domain::Component::MEMORY) { | ||||
|                 memoryInstances.push_back(instance->name); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         auto contentLayout = new QVBoxLayout(content); | ||||
|         content->setLayout(contentLayout); | ||||
| 
 | ||||
|         contentLayout->addWidget(new QLabel(popup.getTitle().c_str())); | ||||
|         contentLayout->addWidget(new QLabel(popup.getText().c_str())); | ||||
| 
 | ||||
|         contentLayout->addWidget(setupEnumeration()); | ||||
|     } | ||||
| 
 | ||||
|     bool MemoryDialog::onUpdate() { | ||||
|         attributeValue->value = value; | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     QComboBox *MemoryDialog::setupEnumeration() { | ||||
|         auto *combo = new QComboBox(this); | ||||
| 
 | ||||
|         for (const auto& entry: memoryInstances) { | ||||
|             combo->addItem(QString::fromStdString(entry)); | ||||
|         } | ||||
|         combo->addItem(QMESSAGE("msg_dialog_memory_default")); | ||||
| 
 | ||||
|         connect(combo, QOverload<int>::of(&QComboBox::currentIndexChanged), [this](int index) { | ||||
|             if(index == memoryInstances.size()) { | ||||
|                 value = domain::Value::fromMemoryReference(std::nullopt); | ||||
|             } else { | ||||
|                 value = domain::Value::fromMemoryReference(this->memoryInstances[index]); | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         combo->setCurrentIndex(memoryInstances.size()); | ||||
|         for (int i = 0; i < memoryInstances.size(); i++) { | ||||
|             if (attributeValue->value.equals(domain::Value::fromMemoryReference(memoryInstances[i]))) { | ||||
|                 combo->setCurrentIndex(i); | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return combo; | ||||
|     } | ||||
| 
 | ||||
| } // display
 | ||||
| @ -1,33 +0,0 @@ | ||||
| #ifndef SCHEMEEDITOR_MEMORY_DIALOG_H | ||||
| #define SCHEMEEDITOR_MEMORY_DIALOG_H | ||||
| 
 | ||||
| #include <QComboBox> | ||||
| #include "generic_dialog.h" | ||||
| #include "comdel/domain/instance_attribute.h" | ||||
| #include "comdel/domain/instance.h" | ||||
| 
 | ||||
| 
 | ||||
| namespace display { | ||||
| 
 | ||||
|     class MemoryDialog : public GenericDialog { | ||||
|     public: | ||||
|         MemoryDialog(std::string title, std::string action, domain::InstanceAttribute *attribute, | ||||
|                      std::vector<std::shared_ptr<domain::ComponentInstance>> instances); | ||||
| 
 | ||||
|     protected: | ||||
|         bool onUpdate() override; | ||||
| 
 | ||||
|     private: | ||||
|         QComboBox *setupEnumeration(); | ||||
| 
 | ||||
|         domain::Value value; | ||||
|         domain::InstanceAttribute *attributeValue; | ||||
|         std::vector<std::string> memoryInstances; | ||||
| 
 | ||||
|         domain::Popup popup; | ||||
|     }; | ||||
| 
 | ||||
| 
 | ||||
| } // display
 | ||||
| 
 | ||||
| #endif //SCHEMEEDITOR_MEMORY_DIALOG_H
 | ||||
| @ -1,40 +0,0 @@ | ||||
| #include <set> | ||||
| #include "name_dialog.h" | ||||
| #include "message_source.h" | ||||
| 
 | ||||
| namespace display { | ||||
| 
 | ||||
|     NameDialog::NameDialog(std::string currentName, std::set<std::string> &names) | ||||
|         : GenericDialog("msg_dialog_name_update"), currentName(currentName), usedNames(names) { | ||||
| 
 | ||||
|         usedNames.erase(currentName); | ||||
| 
 | ||||
|         auto *contentLayout = new QVBoxLayout(); | ||||
|         contentLayout->addWidget(new QLabel(QMESSAGE("msg_dialog_name_update"), this)); | ||||
| 
 | ||||
|         edit = new QLineEdit(this); | ||||
|         edit->insert(currentName.c_str()); | ||||
|         connect(edit, &QLineEdit::textChanged, this, &NameDialog::onNameUpdate); | ||||
|         contentLayout->addWidget(edit); | ||||
| 
 | ||||
|         content->setLayout(contentLayout); | ||||
|     } | ||||
| 
 | ||||
|     void NameDialog::onNameUpdate(const QString &text) { | ||||
|         if(usedNames.find(text.toStdString()) == usedNames.end()) { | ||||
|             setOkButtonDisabled(false); | ||||
|         } else { | ||||
|             setOkButtonDisabled(true); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     std::string NameDialog::getName() { | ||||
|         return currentName; | ||||
|     } | ||||
| 
 | ||||
|     bool NameDialog::onUpdate() { | ||||
|         currentName = edit->text().toStdString(); | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,40 +0,0 @@ | ||||
| #ifndef NAME_DIALOG_H | ||||
| #define NAME_DIALOG_H | ||||
| 
 | ||||
| #include <QDialog> | ||||
| #include <QLabel> | ||||
| #include <QVBoxLayout> | ||||
| #include <QLineEdit> | ||||
| #include <QPushButton> | ||||
| 
 | ||||
| #include <set> | ||||
| 
 | ||||
| #include "comdel/domain/instance.h" | ||||
| #include "generic_dialog.h" | ||||
| 
 | ||||
| namespace display { | ||||
| 
 | ||||
|     class NameDialog : public GenericDialog { | ||||
| 
 | ||||
|     public: | ||||
|         NameDialog(std::string currentName, std::set<std::string>& names); | ||||
| 
 | ||||
|         std::string getName(); | ||||
| 
 | ||||
|     protected: | ||||
|         bool onUpdate() override; | ||||
| 
 | ||||
|     public slots: | ||||
|         void onNameUpdate(const QString& text); | ||||
| 
 | ||||
|     private: | ||||
|         std::set<std::string> usedNames; | ||||
|         QLineEdit *edit = nullptr; | ||||
|         std::string currentName; | ||||
| 
 | ||||
|     }; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #endif //NAME_DIALOG_H
 | ||||
| @ -1,65 +0,0 @@ | ||||
| #include "single_automatic_dialog.h" | ||||
| #include <QVBoxLayout> | ||||
| #include <QLabel> | ||||
| #include <QComboBox> | ||||
| #include <QPushButton> | ||||
| 
 | ||||
| namespace display { | ||||
| 
 | ||||
|     SingleAutomaticDialog::SingleAutomaticDialog(std::string title, std::string action, | ||||
|                                                  std::vector<domain::InstanceAttribute> &values) | ||||
|                                                  : GenericDialog(title, action), attributes(values) { | ||||
|         firstValue = values[0].value; | ||||
|         secondValue = values[1].value; | ||||
| 
 | ||||
|         auto *contentLayout = new QHBoxLayout(); | ||||
|         auto *firstLayout = new QVBoxLayout(); | ||||
|         auto *secondLayout = new QVBoxLayout(); | ||||
| 
 | ||||
|         content->setLayout(contentLayout); | ||||
|         contentLayout->addLayout(firstLayout); | ||||
|         contentLayout->addLayout(secondLayout); | ||||
| 
 | ||||
|         setupValues(firstLayout, values[0], &SingleAutomaticDialog::onFirstEnumerationChanged); | ||||
|         setupValues(secondLayout, values[1], &SingleAutomaticDialog::onSecondEnumerationChanged); | ||||
|     } | ||||
| 
 | ||||
|     void SingleAutomaticDialog::setupValues(QVBoxLayout *layout, domain::InstanceAttribute &attribute, void (display::SingleAutomaticDialog::* handler)(int)) { | ||||
| 
 | ||||
|         auto popup = *attribute.attribute.getPopup(); | ||||
| 
 | ||||
|         layout->addWidget(new QLabel(popup.getTitle().c_str())); | ||||
|         layout->addWidget(new QLabel(popup.getText().c_str())); | ||||
| 
 | ||||
|         auto *combo = new QComboBox(this); | ||||
|         auto enumeration = attribute.attribute.getPopup()->getEnumeration(); | ||||
|         for (auto entry: enumeration) { | ||||
|             combo->addItem(QString::fromStdString(entry.getName())); | ||||
|         } | ||||
| 
 | ||||
|         connect(combo, QOverload<int>::of(&QComboBox::currentIndexChanged), this,handler); | ||||
|         layout->addWidget(combo); | ||||
| 
 | ||||
|         for (int i = 0; i < enumeration.size(); i++) { | ||||
|             if (attribute.value.equals(enumeration[i].getValue())) { | ||||
|                 combo->setCurrentIndex(i); | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void SingleAutomaticDialog::onFirstEnumerationChanged(int index) { | ||||
|         firstValue = attributes[0].attribute.getPopup()->getEnumeration()[index].getValue(); | ||||
|     } | ||||
| 
 | ||||
|     void SingleAutomaticDialog::onSecondEnumerationChanged(int index) { | ||||
|         secondValue = attributes[1].attribute.getPopup()->getEnumeration()[index].getValue(); | ||||
|     } | ||||
| 
 | ||||
|     bool SingleAutomaticDialog::onUpdate() { | ||||
|         attributes[0].value = firstValue; | ||||
|         attributes[1].value = secondValue; | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
| } // display
 | ||||
| @ -1,36 +0,0 @@ | ||||
| #ifndef SCHEMEEDITOR_SINGLE_AUTOMATIC_DIALOG_H | ||||
| #define SCHEMEEDITOR_SINGLE_AUTOMATIC_DIALOG_H | ||||
| 
 | ||||
| #include <vector> | ||||
| #include <QDialog> | ||||
| #include <QVBoxLayout> | ||||
| #include "comdel/domain/value.h" | ||||
| #include "comdel/domain/instance_attribute.h" | ||||
| #include "generic_dialog.h" | ||||
| 
 | ||||
| namespace display { | ||||
| 
 | ||||
|     class SingleAutomaticDialog: public GenericDialog { | ||||
|         domain::Value firstValue; | ||||
|         domain::Value secondValue; | ||||
|         std::vector<domain::InstanceAttribute> &attributes; | ||||
| 
 | ||||
|     public: | ||||
|         explicit SingleAutomaticDialog( | ||||
|                 std::string title, | ||||
|                 std::string action, | ||||
|                 std::vector<domain::InstanceAttribute>& values); | ||||
| 
 | ||||
|     protected: | ||||
|         bool onUpdate() override; | ||||
|         void setupValues(QVBoxLayout *layout, domain::InstanceAttribute &attribute, void (display::SingleAutomaticDialog::* handler)(int)); | ||||
| 
 | ||||
|     public slots: | ||||
| 
 | ||||
|         void onFirstEnumerationChanged(int index); | ||||
|         void onSecondEnumerationChanged(int index); | ||||
|     }; | ||||
| 
 | ||||
| } // display
 | ||||
| 
 | ||||
| #endif //SCHEMEEDITOR_SINGLE_AUTOMATIC_DIALOG_H
 | ||||
| @ -1,19 +0,0 @@ | ||||
| #include <QVBoxLayout> | ||||
| #include <QLabel> | ||||
| #include <QPushButton> | ||||
| #include "success_dialog.h" | ||||
| #include "message_source.h" | ||||
| 
 | ||||
| namespace display { | ||||
| 
 | ||||
|     SuccessDialog::SuccessDialog(std::string message) { | ||||
|         setLayout(new QVBoxLayout()); | ||||
|         setWindowTitle(QMESSAGE("msg_dialog_success_title")); | ||||
|         layout()->addWidget(new QLabel(QString::fromStdString(message))); | ||||
| 
 | ||||
|         auto button = new QPushButton(QMESSAGE("msg_dialog_actions_ok")); | ||||
|         connect(button, &QPushButton::clicked, [this]() {accept();}); | ||||
|         layout()->addWidget(button); | ||||
|     } | ||||
| 
 | ||||
| } // display
 | ||||
| @ -1,19 +0,0 @@ | ||||
| //
 | ||||
| // Created by bbr on 14.06.22..
 | ||||
| //
 | ||||
| 
 | ||||
| #ifndef SCHEMEEDITOR_SUCCESS_DIALOG_H | ||||
| #define SCHEMEEDITOR_SUCCESS_DIALOG_H | ||||
| 
 | ||||
| #include <QDialog> | ||||
| 
 | ||||
| namespace display { | ||||
| 
 | ||||
|     class SuccessDialog: public QDialog { | ||||
|     public: | ||||
|         explicit SuccessDialog(std::string message); | ||||
|     }; | ||||
| 
 | ||||
| } // display
 | ||||
| 
 | ||||
| #endif //SCHEMEEDITOR_SUCCESS_DIALOG_H
 | ||||
| @ -1,16 +0,0 @@ | ||||
| #include <QVBoxLayout> | ||||
| #include <QLabel> | ||||
| #include "warning_dialog.h" | ||||
| 
 | ||||
| namespace display { | ||||
| 
 | ||||
|     WarningDialog::WarningDialog(domain::ValidationError error) | ||||
|         : GenericDialog("msg_dialog_warning_title", "msg_dialog_actions_ok") { | ||||
| 
 | ||||
|         auto contentLayout = new QVBoxLayout(); | ||||
|         content->setLayout(contentLayout); | ||||
| 
 | ||||
|         contentLayout->addWidget(new QLabel(QString::fromStdString(error.message), this)); | ||||
|     } | ||||
| 
 | ||||
| } // display
 | ||||
| @ -1,20 +0,0 @@ | ||||
| #ifndef SCHEMEEDITOR_WARNING_DIALOG_H | ||||
| #define SCHEMEEDITOR_WARNING_DIALOG_H | ||||
| 
 | ||||
| #include "generic_dialog.h" | ||||
| #include "comdel/domain/comdel_validator.h" | ||||
| 
 | ||||
| namespace display { | ||||
| 
 | ||||
|     class WarningDialog : public GenericDialog { | ||||
|     public: | ||||
|         WarningDialog(domain::ValidationError error); | ||||
| 
 | ||||
|     protected: | ||||
|         bool onUpdate() override { return true; }; | ||||
|     }; | ||||
| 
 | ||||
| 
 | ||||
| } // display
 | ||||
| 
 | ||||
| #endif //SCHEMEEDITOR_WARNING_DIALOG_H
 | ||||
| @ -1,60 +1,52 @@ | ||||
| #include "library_display.h" | ||||
| #include "message_source.h" | ||||
| 
 | ||||
| #include <QLabel> | ||||
| #include <QListWidget> | ||||
| #include <QVBoxLayout> | ||||
| #include <application.h> | ||||
| 
 | ||||
| namespace display { | ||||
| 
 | ||||
|     Library::Library() { | ||||
|         auto layout = new QVBoxLayout(); | ||||
|         this->setLayout(layout); | ||||
| Library::Library() | ||||
| { | ||||
|     auto layout = new QVBoxLayout(); | ||||
|     this->setLayout(layout); | ||||
| 
 | ||||
|         componentList = new LibraryList(this); | ||||
|         busList = new LibraryList(this); | ||||
|     componentList = new QListWidget(); | ||||
|     busList = new QListWidget(); | ||||
| 
 | ||||
|         layout->setContentsMargins(4, 4, 4, 4); | ||||
|     layout->setMargin(4); | ||||
|     layout->addWidget(new QLabel("Components:")); | ||||
|     layout->addWidget(componentList, 1); | ||||
|     layout->addSpacing(8); | ||||
|     layout->addWidget(new QLabel("Buses:")); | ||||
|     layout->addWidget(busList, 1); | ||||
| 
 | ||||
|         componentsLabel = new QLabel(QMESSAGE("msg_sidebar_components")); | ||||
|         busLabel = new QLabel(QMESSAGE("msg_sidebar_busses")); | ||||
|     setLibrary(library); | ||||
| } | ||||
| 
 | ||||
|         layout->addWidget(componentsLabel); | ||||
|         layout->addWidget(componentList, 1); | ||||
|         layout->addSpacing(8); | ||||
|         layout->addWidget(busLabel); | ||||
|         layout->addWidget(busList, 1); | ||||
| void Library::setLibrary(std::optional<domain::Library> library) { | ||||
| 
 | ||||
|     componentList->clear(); | ||||
|     busList->clear(); | ||||
| 
 | ||||
|     if(!library) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     void Library::refreshContent() { | ||||
|         library = Application::instance()->getLibrary(); | ||||
| 
 | ||||
|         componentsLabel->setText(QMESSAGE("msg_sidebar_components")); | ||||
|         busLabel->setText(QMESSAGE("msg_sidebar_busses")); | ||||
| 
 | ||||
|         componentList->clear(); | ||||
|         busList->clear(); | ||||
| 
 | ||||
|         if (!library) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         for (auto &component: library->getComponents()) { | ||||
|             auto item = new LibraryListItem{component.getDisplayName(), "comdel/component", component.getName(), | ||||
|                                             componentList}; | ||||
|             item->setToolTip(QString::fromStdString(component.getTooltip())); | ||||
|             componentList->addItem(item); | ||||
|         } | ||||
| 
 | ||||
|         for (auto &bus: library->getBuses()) { | ||||
|             if (bus.getType() == domain::Bus::REGULAR) { | ||||
|                 auto item = new LibraryListItem{bus.getDisplayName(), "comdel/bus", bus.getName(), busList}; | ||||
|                 item->setToolTip(QString::fromStdString(bus.getTooltip())); | ||||
|                 busList->addItem(item); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|     for(auto& component: library->getComponents()) { | ||||
|         auto item = new QListWidgetItem{QString::fromStdString(component.getName())}; | ||||
|         item->setToolTip(QString::fromStdString(component.getTooltip())); | ||||
|         componentList->addItem(item); | ||||
|     } | ||||
| 
 | ||||
|     for(auto& bus: library->getBuses()) { | ||||
|         if(bus.getType() == domain::Bus::REGULAR) { | ||||
|             auto item = new QListWidgetItem{QString::fromStdString(bus.getName())}; | ||||
|             item->setToolTip(QString::fromStdString(bus.getTooltip())); | ||||
|             busList->addItem(item); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| } // namespace display
 | ||||
|  | ||||
| @ -5,26 +5,23 @@ | ||||
| #include <QWidget> | ||||
| 
 | ||||
| #include <comdel/domain/library.h> | ||||
| #include <QLabel> | ||||
| #include "library_list.h" | ||||
| 
 | ||||
| namespace display { | ||||
| 
 | ||||
|     class Library : public QWidget { | ||||
|     public: | ||||
|         Library(); | ||||
| class Library: public QWidget | ||||
| { | ||||
| public: | ||||
|     Library(); | ||||
| 
 | ||||
|         void refreshContent(); | ||||
|     void setLibrary(std::optional<domain::Library> library); | ||||
| 
 | ||||
|     private: | ||||
|         std::optional<domain::Library> library; | ||||
| private: | ||||
|     std::optional<domain::Library> library; | ||||
| 
 | ||||
|         LibraryList *componentList; | ||||
|         LibraryList *busList; | ||||
|     QListWidget *componentList; | ||||
|     QListWidget *busList; | ||||
| 
 | ||||
|         QLabel *componentsLabel; | ||||
|         QLabel *busLabel; | ||||
|     }; | ||||
| }; | ||||
| 
 | ||||
| } // namespace display
 | ||||
| 
 | ||||
|  | ||||
| @ -1,32 +0,0 @@ | ||||
| //
 | ||||
| // Created by bbr on 22.05.22..
 | ||||
| //
 | ||||
| 
 | ||||
| #include "library_list.h" | ||||
| 
 | ||||
| #include <QMouseEvent> | ||||
| #include <QDrag> | ||||
| #include <QMimeData> | ||||
| 
 | ||||
| namespace display { | ||||
| 
 | ||||
|     LibraryList::LibraryList(QWidget *parent) : QListWidget(parent) { | ||||
|         setDragDropMode(DragOnly); | ||||
|     } | ||||
| 
 | ||||
|     QMimeData *LibraryList::mimeData(const QList<QListWidgetItem *> items) const { | ||||
|         for (auto qItem: items) { | ||||
|             // we only allow one item to be dragged at a time
 | ||||
|             auto item = dynamic_cast<LibraryListItem *>(qItem); | ||||
|             auto *md = new QMimeData(); | ||||
|             md->setData(QString::fromStdString(item->mimeType), QByteArray::fromStdString(item->value)); | ||||
|             return md; | ||||
|         } | ||||
|         return nullptr; | ||||
|     } | ||||
| 
 | ||||
|     LibraryListItem::LibraryListItem(std::string title, std::string mimeType, std::string value, QListWidget *parent) | ||||
|             : QListWidgetItem(parent), mimeType(mimeType), value(value) { | ||||
|         setText(QString::fromStdString(title)); | ||||
|     } | ||||
| } // display
 | ||||
| @ -1,34 +0,0 @@ | ||||
| //
 | ||||
| // Created by bbr on 22.05.22..
 | ||||
| //
 | ||||
| 
 | ||||
| #ifndef SCHEMEEDITOR_LIBRARY_LIST_H | ||||
| #define SCHEMEEDITOR_LIBRARY_LIST_H | ||||
| 
 | ||||
| #include <QListWidget> | ||||
| #include <QList> | ||||
| #include <QMimeData> | ||||
| 
 | ||||
| namespace display { | ||||
| 
 | ||||
|     class LibraryList : public QListWidget { | ||||
|     Q_OBJECT | ||||
|     public: | ||||
|         LibraryList(QWidget *parent); | ||||
| 
 | ||||
|     protected: | ||||
|         QMimeData *mimeData(const QList<QListWidgetItem *> items) const override; | ||||
|     }; | ||||
| 
 | ||||
|     class LibraryListItem : public QListWidgetItem { | ||||
| 
 | ||||
|     public: | ||||
|         std::string mimeType; | ||||
|         std::string value; | ||||
| 
 | ||||
|         LibraryListItem(std::string title, std::string mimeType, std::string value, QListWidget *parent); | ||||
|     }; | ||||
| 
 | ||||
| } // display
 | ||||
| 
 | ||||
| #endif //SCHEMEEDITOR_LIBRARY_LIST_H
 | ||||
							
								
								
									
										5
									
								
								comdel/display/name_dialog.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								comdel/display/name_dialog.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| //
 | ||||
| // Created by bbr on 18. 04. 2022..
 | ||||
| //
 | ||||
| 
 | ||||
| #include "name_dialog.h" | ||||
							
								
								
									
										64
									
								
								comdel/display/name_dialog.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								comdel/display/name_dialog.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,64 @@ | ||||
| #ifndef NAME_DIALOG_H | ||||
| #define NAME_DIALOG_H | ||||
| 
 | ||||
| #include <QDialog> | ||||
| #include <QLabel> | ||||
| #include <QVBoxLayout> | ||||
| #include <QLineEdit> | ||||
| #include <QPushButton> | ||||
| 
 | ||||
| #include <comdel/domain/instance.h> | ||||
| 
 | ||||
| namespace display { | ||||
| 
 | ||||
| class NameDialog: public QDialog { | ||||
| 
 | ||||
|     QLineEdit *edit = nullptr; | ||||
|     domain::ComponentInstance *componentInstance = nullptr; | ||||
|     domain::BusInstance *busInstance = nullptr; | ||||
| 
 | ||||
| public: | ||||
| 
 | ||||
|     NameDialog(domain::ComponentInstance *instance): componentInstance(instance) { | ||||
|         auto *layout = new QVBoxLayout(this); | ||||
|         layout->addWidget(new QLabel("Izmjeni ime", this)); | ||||
| 
 | ||||
|         edit = new QLineEdit(this); | ||||
|         edit->insert(instance->name.c_str()); | ||||
|         layout->addWidget(edit); | ||||
|         this->setWindowTitle("Izmjeni ime"); | ||||
|         auto *button = new QPushButton("Ažuriraj", this); | ||||
|         connect(button, &QPushButton::clicked, this, &NameDialog::onNameChange); | ||||
|         layout->addWidget(button); | ||||
|         this->setLayout(layout); | ||||
|     } | ||||
| 
 | ||||
|     NameDialog(domain::BusInstance *instance): busInstance(instance) { | ||||
|         auto *layout = new QVBoxLayout(this); | ||||
|         layout->addWidget(new QLabel("Izmjeni ime", this)); | ||||
| 
 | ||||
|         edit = new QLineEdit(this); | ||||
|         edit->insert(instance->name.c_str()); | ||||
|         layout->addWidget(edit); | ||||
|         this->setWindowTitle("Izmjeni ime"); | ||||
|         auto *button = new QPushButton("Ažuriraj", this); | ||||
|         connect(button, &QPushButton::clicked, this, &NameDialog::onNameChange); | ||||
|         layout->addWidget(button); | ||||
|         this->setLayout(layout); | ||||
|     } | ||||
| 
 | ||||
| public slots: | ||||
|     void onNameChange() { | ||||
|         if(componentInstance != nullptr) { | ||||
|             componentInstance->name = this->edit->text().toStdString(); | ||||
|         } else if(busInstance != nullptr) { | ||||
|             busInstance->name = this->edit->text().toStdString(); | ||||
|         } | ||||
|         this->close(); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #endif //NAME_DIALOG_H
 | ||||
| @ -1,337 +1,28 @@ | ||||
| #include "component_display.h" | ||||
| #include "schema_display.h" | ||||
| #include "application.h" | ||||
| #include "comdel/display/dialog/attribute_dialog.h" | ||||
| #include "comdel/display/dialog/single_automatic_dialog.h" | ||||
| #include "comdel/display/dialog/memory_dialog.h" | ||||
| 
 | ||||
| #include <QDrag> | ||||
| #include <QDragEnterEvent> | ||||
| #include <QMimeData> | ||||
| #include "message_source.h" | ||||
| 
 | ||||
| 
 | ||||
| namespace display { | ||||
| 
 | ||||
|     Schema::Schema() { | ||||
|         schema = nullptr; | ||||
|         library = std::nullopt; | ||||
|         setRenderHint(QPainter::Antialiasing); | ||||
|         setAlignment(Qt::AlignCenter); | ||||
|         this->setScene(&scene); | ||||
|         this->setAcceptDrops(true); | ||||
|     } | ||||
| Schema::Schema() | ||||
| { | ||||
|     this->setScene(&scene); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|     void Schema::refreshContent() { | ||||
|         schema = Application::instance()->getSchema(); | ||||
|         library = Application::instance()->getLibrary(); | ||||
| 
 | ||||
|         components.clear(); | ||||
|         buses.clear(); | ||||
|         scene.clear(); | ||||
|         pins.clear(); | ||||
|         busConnections.clear(); | ||||
|         directConnections.clear(); | ||||
| 
 | ||||
|         if (schema != nullptr) { | ||||
|             for (auto &instance: schema->componentInstances) { | ||||
|                 auto group = new display::ComponentGroup(instance); | ||||
|                 for (auto pin: group->getPins()) { | ||||
|                     display::Pin *p = pin; | ||||
|                     domain::ConnectionComponent connection{instance->name, p->getPin().getName()}; | ||||
|                     pins.insert(std::make_pair(connection, p)); | ||||
|                 } | ||||
|                 components.insert(std::make_pair(instance->name, group)); | ||||
|                 scene.addItem(group); | ||||
|             } | ||||
|             for (auto &instance: schema->busInstances) { | ||||
|                 if (instance->bus.getDisplayBus().has_value()) { | ||||
|                     auto group = new display::BusGroup(instance); | ||||
|                     buses.insert(std::make_pair(instance->name, group)); | ||||
|                     scene.addItem(group); | ||||
|                 } | ||||
|             } | ||||
|             for (auto &connection: schema->connections) { | ||||
|                 auto busInstance = dynamic_cast<domain::BusConnectionInstance *>(connection.get()); | ||||
|                 if (busInstance != nullptr) { | ||||
|                     auto con = new display::BusConnection(busInstance, components[busInstance->instance->name], | ||||
|                                                           buses[busInstance->bus->name]); | ||||
|                     busConnections.push_back(con); | ||||
|                     scene.addItem(con); | ||||
|                 } | ||||
|                 auto directInstance = dynamic_cast<domain::DirectConnectionInstance *>(connection.get()); | ||||
|                 if (directInstance != nullptr) { | ||||
|                     auto con = new display::DirectConnection(directInstance, components[directInstance->instance->name], | ||||
|                                                              components[directInstance->secondInstance->name]); | ||||
|                     directConnections.push_back(con); | ||||
|                     scene.addItem(con); | ||||
|                 } | ||||
| void Schema::setSchema(domain::Schema* _schema) | ||||
| { | ||||
|     scene.clear(); | ||||
|     this->schema = _schema; | ||||
|     if(schema != nullptr) { | ||||
|         for(auto &instance: schema->componentInstances) { | ||||
|             scene.addItem(new display::ComponentGroup(instance)); | ||||
|         } | ||||
|         for(auto &instance: schema->busInstances) { | ||||
|             if(instance->bus.getDisplay().has_value()) { | ||||
|                 scene.addItem(new display::BusGroup(instance)); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void Schema::updateConnections() { | ||||
|         if (schema != nullptr) { | ||||
|             for (auto conn: busConnections) { | ||||
|                 conn->updateConnection(); | ||||
|             } | ||||
|             for (auto conn: directConnections) { | ||||
|                 conn->updateConnection(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void Schema::dragEnterEvent(QDragEnterEvent *event) { | ||||
|         if (event->mimeData()->hasFormat("comdel/component") || | ||||
|             event->mimeData()->hasFormat("comdel/bus")) { | ||||
|             event->acceptProposedAction(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void Schema::dropEvent(QDropEvent *event) { | ||||
|         if (event->mimeData()->hasFormat("comdel/component")) { | ||||
|             auto component = library->getComponent(event->mimeData()->data("comdel/component").toStdString()); | ||||
| 
 | ||||
|             auto attributes = populateAttributes(component.getAttributes()); | ||||
|             if(attributes.size() != component.getAttributes().size()) { | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             auto currentPos = this->mapToScene(event->pos()).toPoint(); | ||||
| 
 | ||||
|             auto instance = Application::instance()->addComponent(component, attributes, currentPos.x(), currentPos.y()); | ||||
| 
 | ||||
|             auto group = new display::ComponentGroup(instance); | ||||
|             scene.addItem(group); | ||||
|             for (auto pin: group->getPins()) { | ||||
|                 display::Pin *p = pin; | ||||
|                 domain::ConnectionComponent connection{instance->name, p->getPin().getName()}; | ||||
|                 pins.insert(std::make_pair(connection, p)); | ||||
|             } | ||||
| 
 | ||||
|             components[instance->name] = group; | ||||
| 
 | ||||
|             event->acceptProposedAction(); | ||||
|         } | ||||
|         if (event->mimeData()->hasFormat("comdel/bus")) { | ||||
|             auto bus = library->getBus(event->mimeData()->data("comdel/bus").toStdString()); | ||||
| 
 | ||||
|             auto currentPos = this->mapToScene(event->pos()).toPoint(); | ||||
| 
 | ||||
|             auto instance = Application::instance()->addBus(bus, currentPos.x(), currentPos.y()); | ||||
| 
 | ||||
|             auto group = new display::BusGroup(instance); | ||||
|             scene.addItem(group); | ||||
|             buses[instance->name] = group; | ||||
| 
 | ||||
|             event->acceptProposedAction(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void Schema::dragMoveEvent(QDragMoveEvent *event) { | ||||
|         event->acceptProposedAction(); | ||||
|     } | ||||
| 
 | ||||
|     void Schema::removeConnectable(QPointF endPoint) { | ||||
|         auto instance = context.pin->getComponentInstance(); | ||||
|         auto &pin = context.pin->getPin(); | ||||
| 
 | ||||
|         auto availableConnections = schema->availableConnections(instance->name, pin.getName(), true); | ||||
| 
 | ||||
|         for(auto &connection: availableConnections) { | ||||
|             if(connection.type != domain::ConnectionEntry::BUS) { | ||||
|                 continue; | ||||
|             } | ||||
|             auto bus = connection.busInstance.value(); | ||||
|             if(buses[bus->name] == nullptr) { | ||||
|                 continue; | ||||
|             } | ||||
|             auto rect = buses[bus->name]->boundingRect(); | ||||
|             rect = QRectF(buses[bus->name]->x(), buses[bus->name]->y(), rect.width(), rect.height()); | ||||
| 
 | ||||
|             if (rect.contains(endPoint)) { | ||||
|                 auto con = library->getConnection({instance->component.getName(), pin.getName()}, bus->bus.getName()); | ||||
|                 if (con.has_value()) { | ||||
|                     auto attributes = populateAttributes(con->getAttributes()); | ||||
|                     if(attributes.size() != con->getAttributes().size()) { | ||||
|                         clearSelectable(); | ||||
|                         return; | ||||
|                     } | ||||
| 
 | ||||
|                     auto conInstance = std::make_shared<domain::BusConnectionInstance>(instance, attributes, bus, *con); | ||||
|                     schema->connections.push_back(conInstance); | ||||
| 
 | ||||
|                     if (conInstance != nullptr) { | ||||
|                         auto c = new display::BusConnection(conInstance.get(), components[conInstance->instance->name], | ||||
|                                                             buses[conInstance->bus->name]); | ||||
|                         busConnections.push_back(c); | ||||
|                         scene.addItem(c); | ||||
|                     } | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         for (auto &connection: availableConnections) { | ||||
|             if(connection.type != domain::ConnectionEntry::COMPONENT) { | ||||
|                 continue; | ||||
|             } | ||||
|             auto pinInstance = domain::ConnectionComponent{connection.componentInstance.value()->name, connection.pin.value().getName()}; | ||||
|             auto pin = pins[pinInstance]->getPin().getDisplayPin(); | ||||
|             auto position = pins[pinInstance]->getComponentInstance()->position; | ||||
| 
 | ||||
|             auto rect = QRectF(position.first + pin.x, position.second + pin.y, pin.w, pin.h); | ||||
| 
 | ||||
|             if (rect.contains(endPoint)) { | ||||
|                 auto name = components[pinInstance.component]->getComponentInstance()->component.getName(); | ||||
|                 auto con = library->getConnection({instance->component.getName(), context.pin->getPin().getName()}, | ||||
|                                                   {name, pinInstance.pin}); | ||||
|                 if (con.has_value()) { | ||||
|                     auto busInstance = Application::instance()->addBus(library->getBus(con->getBus()), 0, 0); | ||||
| 
 | ||||
|                     std::vector<domain::InstanceAttribute> attributes; | ||||
|                     if(library->getBus(con->getBus()).getType() == domain::Bus::SINGLE_AUTOMATIC) { | ||||
|                         attributes = populateSingleAutomaticConnection(*con); | ||||
|                     } else { | ||||
|                         attributes = populateAttributes(con->getAttributes()); | ||||
|                     } | ||||
|                     if(attributes.size() != con->getAttributes().size()) { | ||||
|                         clearSelectable(); | ||||
|                         return; | ||||
|                     } | ||||
| 
 | ||||
|                     std::shared_ptr<domain::DirectConnectionInstance> conInstance = nullptr; | ||||
|                     if(con->getComponent() == domain::ConnectionComponent{instance->component.getName(), context.pin->getPin().getName()}) { | ||||
|                         conInstance = std::make_shared<domain::DirectConnectionInstance>(instance, | ||||
|                                                                            components[pinInstance.component]->getComponentInstance().get(), | ||||
|                                                                            attributes, busInstance.get(), | ||||
|                                                                            *con); | ||||
|                     } else { | ||||
|                         conInstance = std::make_shared<domain::DirectConnectionInstance>(components[pinInstance.component]->getComponentInstance().get(), | ||||
|                                                                                          instance, | ||||
|                                                                                          attributes, busInstance.get(), | ||||
|                                                                                          *con); | ||||
|                     } | ||||
| 
 | ||||
|                     schema->connections.push_back(conInstance); | ||||
| 
 | ||||
| 
 | ||||
|                     if (conInstance != nullptr) { | ||||
|                         auto c = new display::DirectConnection(conInstance.get(), | ||||
|                                                                components[conInstance->instance->name], | ||||
|                                                                components[conInstance->secondInstance->name]); | ||||
|                         directConnections.push_back(c); | ||||
|                         scene.addItem(c); | ||||
|                     } | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         clearSelectable(); | ||||
|     } | ||||
| 
 | ||||
|     void Schema::showConnectable(Pin *domainPin) { | ||||
|         auto &pin = domainPin->getPin(); | ||||
| 
 | ||||
|         auto availableConnections = schema->availableConnections(domainPin->getComponentInstance()->name, pin.getName(), true); | ||||
| 
 | ||||
|         for(auto &connection: availableConnections) { | ||||
|             if(connection.type != domain::ConnectionEntry::BUS) { | ||||
|                 continue; | ||||
|             } | ||||
|             auto bus = connection.busInstance.value(); | ||||
|             auto &group = buses[bus->name]; | ||||
|             if(group == nullptr) { | ||||
|                 continue; | ||||
|             } | ||||
|             auto rect = new QGraphicsRectItem(group->boundingRect()); | ||||
|             rect->setBrush(selectedBrush); | ||||
|             rect->setPos(group->scenePos()); | ||||
| 
 | ||||
|             auto _rect = rect->rect(); | ||||
|             _rect.setWidth(_rect.width() + 1); | ||||
|             _rect.setHeight(_rect.height() + 1); | ||||
|             rect->setRect(_rect); | ||||
| 
 | ||||
|             context.selectable.push_back(rect); | ||||
|             scene.addItem(rect); | ||||
|         } | ||||
| 
 | ||||
|         for (auto &connection: availableConnections) { | ||||
|             if(connection.type != domain::ConnectionEntry::COMPONENT) { | ||||
|                 continue; | ||||
|             } | ||||
|             auto pinInstance = domain::ConnectionComponent{connection.componentInstance.value()->name, connection.pin.value().getName()}; | ||||
|             auto &instance = pins[pinInstance]; | ||||
|             auto rect = new QGraphicsRectItem(instance->boundingRect()); | ||||
|             rect->setBrush(selectedBrush); | ||||
|             rect->setPen(selectedPen); | ||||
|             rect->setPos(instance->scenePos()); | ||||
| 
 | ||||
|             auto _rect = rect->rect(); | ||||
|             _rect.setWidth(_rect.width() + 1); | ||||
|             _rect.setHeight(_rect.height() + 1); | ||||
|             rect->setRect(_rect); | ||||
| 
 | ||||
|             context.selectable.push_back(rect); | ||||
|             scene.addItem(rect); | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     std::vector<domain::InstanceAttribute> Schema::populateAttributes(std::vector<domain::Attribute>& attributes) { | ||||
|         std::vector<domain::InstanceAttribute> instanceAttributes; | ||||
| 
 | ||||
|         for (auto attr: attributes) { | ||||
|             domain::InstanceAttribute attribute(attr.getName(), attr.getDefault(), attr); | ||||
|             if(attr.getPopup().has_value() && attr.getPopup()->getType() == domain::Popup::AUTOMATIC) { | ||||
|                 if(attr.getDefault().isType(domain::Value::MEMORY_REFERENCE)) { | ||||
|                     auto dialog = new MemoryDialog("msg_dialog_memory_set", "msg_dialog_actions_set", &attribute, schema->componentInstances); | ||||
|                     if(dialog->exec() == QDialog::Rejected) { | ||||
|                         // if any dialog isn't set, whole creation is rejected
 | ||||
|                         return {}; | ||||
|                     } | ||||
|                 } else { | ||||
|                     std::map<std::string, std::string> params = {{"attribute", attribute.attribute.getDisplayName()}}; | ||||
|                     auto dialog = new AttributeDialog(MESSAGE_PARAM("msg_dialog_attribute_set", params), "msg_dialog_actions_set", &attribute); | ||||
|                     if(dialog->exec() == QDialog::Rejected) { | ||||
|                         // if any dialog isn't set, whole creation is rejected
 | ||||
|                         return {}; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             instanceAttributes.push_back(attribute); | ||||
|         } | ||||
|         return instanceAttributes; | ||||
|     } | ||||
| 
 | ||||
|     std::vector<domain::InstanceAttribute> Schema::populateSingleAutomaticConnection(domain::Connection connection) { | ||||
|         std::vector<domain::InstanceAttribute> instanceAttributes; | ||||
| 
 | ||||
|         for (auto attr: connection.getAttributes()) { | ||||
|             instanceAttributes.emplace_back(attr.getName(), attr.getDefault(), attr); | ||||
|         } | ||||
| 
 | ||||
|         auto dialog = new display::SingleAutomaticDialog("msg_dialog_sa_pin_set", "msg_dialog_actions_set", instanceAttributes); | ||||
|         if(dialog->exec() == QDialog::Rejected) { | ||||
|             // if dialog is rejected, whole creation is rejected
 | ||||
|             return {}; | ||||
|         } | ||||
| 
 | ||||
|         return instanceAttributes; | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     void Schema::clearSelectable() { | ||||
|         updateConnections(); | ||||
| 
 | ||||
|         for (auto &item: this->context.selectable) { | ||||
|             this->scene.removeItem(item); | ||||
|             delete item; | ||||
|         } | ||||
|         this->context.selectable.clear(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| } // namespace display
 | ||||
|  | ||||
| @ -4,78 +4,23 @@ | ||||
| 
 | ||||
| #include <QGraphicsView> | ||||
| #include <QWidget> | ||||
| #include <QColor> | ||||
| #include <QGraphicsLineItem> | ||||
| 
 | ||||
| #include <comdel/domain/schema.h> | ||||
| #include <comdel/domain/library.h> | ||||
| #include "component_display.h" | ||||
| 
 | ||||
| namespace display { | ||||
| 
 | ||||
|     class BusConnection; | ||||
| class Schema: public QGraphicsView | ||||
| { | ||||
| public: | ||||
|     Schema(); | ||||
| 
 | ||||
|     class Schema : public QGraphicsView { | ||||
|     Q_OBJECT | ||||
|     void setSchema(domain::Schema* schema); | ||||
| 
 | ||||
|     public: | ||||
| private: | ||||
|     QGraphicsScene scene; | ||||
| 
 | ||||
|         QBrush selectedBrush = QBrush(QColor::fromRgb(50, 50, 150, 100), Qt::BrushStyle::SolidPattern); | ||||
|         QPen selectedPen = QPen(QColor::fromRgb(50, 50, 150), 1, Qt::PenStyle::SolidLine); | ||||
|         QPen activeLinePen = QPen(QColor::fromRgb(250, 100, 100)); | ||||
| 
 | ||||
|         enum State { | ||||
|             DEFAULT, | ||||
|             CREATING_CONNECTION | ||||
|         }; | ||||
| 
 | ||||
|         struct Context { | ||||
|             display::Pin *pin = nullptr; | ||||
|             QPointF startingPoint; | ||||
|             QGraphicsLineItem *line = nullptr; | ||||
|             std::vector<QGraphicsRectItem *> selectable; | ||||
|         }; | ||||
| 
 | ||||
|         std::map<std::string, display::ComponentGroup *> components; | ||||
|         std::map<std::string, display::BusGroup *> buses; | ||||
|         std::map<domain::ConnectionComponent, display::Pin *> pins; | ||||
| 
 | ||||
|         State state = DEFAULT; | ||||
|         Context context; | ||||
| 
 | ||||
|         Schema(); | ||||
| 
 | ||||
|         std::vector<BusConnection *> busConnections; | ||||
|         std::vector<DirectConnection *> directConnections; | ||||
| 
 | ||||
|         void updateConnections(); | ||||
| 
 | ||||
|         void removeConnectable(QPointF f); | ||||
| 
 | ||||
|         void showConnectable(Pin *pin); | ||||
| 
 | ||||
|         void refreshContent(); | ||||
| 
 | ||||
|     protected: | ||||
| 
 | ||||
|         void dragEnterEvent(QDragEnterEvent *event) override; | ||||
| 
 | ||||
|         void dropEvent(QDropEvent *event) override; | ||||
| 
 | ||||
|         void dragMoveEvent(QDragMoveEvent *event) override; | ||||
| 
 | ||||
|     private: | ||||
|         QGraphicsScene scene; | ||||
| 
 | ||||
|         domain::Schema *schema{}; | ||||
|         std::optional<domain::Library> library; | ||||
| 
 | ||||
|         std::vector<domain::InstanceAttribute> populateAttributes(std::vector<domain::Attribute>& attributes); | ||||
| 
 | ||||
|         std::vector<domain::InstanceAttribute> populateSingleAutomaticConnection(domain::Connection connection); | ||||
| 
 | ||||
|         void clearSelectable(); | ||||
|     }; | ||||
|     domain::Schema* schema; | ||||
| }; | ||||
| 
 | ||||
| } // namespace display
 | ||||
| 
 | ||||
|  | ||||
| @ -1,29 +0,0 @@ | ||||
| #include <algorithm> | ||||
| #include "address_space.h" | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
|     AddressSpace::AddressSpace(std::string name, long long start, long long end) : | ||||
|             name(name), start(start), end(end) {} | ||||
| 
 | ||||
|     std::string AddressSpace::getName() { | ||||
|         return name; | ||||
|     } | ||||
| 
 | ||||
|     long long AddressSpace::getStart() const { | ||||
|         return start; | ||||
|     } | ||||
| 
 | ||||
|     long long AddressSpace::getEnd() const { | ||||
|         return end; | ||||
|     } | ||||
| 
 | ||||
|     bool AddressSpace::contains(long long int address) { | ||||
|         return address >= start && address < end; | ||||
|     } | ||||
| 
 | ||||
|     bool AddressSpace::contains(long long int pstart, long long int pend) { | ||||
|         return pstart >= start && pend < end; | ||||
|     } | ||||
| 
 | ||||
| } // namespace domain
 | ||||
| @ -1,29 +0,0 @@ | ||||
| #ifndef DOMAIN_ADDRESS_SPACE_H | ||||
| #define DOMAIN_ADDRESS_SPACE_H | ||||
| 
 | ||||
| #include <string> | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
|     class AddressSpace { | ||||
|         std::string name; | ||||
|         long long start; | ||||
|         long long end; | ||||
| 
 | ||||
|     public: | ||||
|         AddressSpace(std::string name, long long start, long long end); | ||||
| 
 | ||||
|         std::string getName(); | ||||
| 
 | ||||
|         long long getStart() const; | ||||
| 
 | ||||
|         long long getEnd() const; | ||||
| 
 | ||||
|         bool contains(long long int address); | ||||
| 
 | ||||
|         bool contains(long long int start, long long int end); | ||||
|     }; | ||||
| 
 | ||||
| } // namespace domain
 | ||||
| 
 | ||||
| #endif // DOMAIN_ADDRESS_SPACE_H
 | ||||
							
								
								
									
										28
									
								
								comdel/domain/addressspace.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								comdel/domain/addressspace.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | ||||
| #include <algorithm> | ||||
| #include "addressspace.h" | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
| AddressSpace::AddressSpace(std::string name, long long start, long long end): | ||||
|     name(name), start(start), end(end) | ||||
| {} | ||||
| 
 | ||||
| std::string AddressSpace::getName() { | ||||
|     return name; | ||||
| } | ||||
| long long AddressSpace::getStart() const { | ||||
|     return start; | ||||
| } | ||||
| long long AddressSpace::getEnd() const { | ||||
|     return end; | ||||
| } | ||||
| 
 | ||||
| bool AddressSpace::contains(long long int address) { | ||||
|     return address >= start && address < end; | ||||
| } | ||||
| 
 | ||||
| bool AddressSpace::contains(long long int pstart, long long int pend) { | ||||
|     return pstart >= start && pend < end; | ||||
| } | ||||
| 
 | ||||
| } // namespace domain
 | ||||
							
								
								
									
										27
									
								
								comdel/domain/addressspace.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								comdel/domain/addressspace.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,27 @@ | ||||
| #ifndef DOMAIN_ADDRESS_SPACE_H | ||||
| #define DOMAIN_ADDRESS_SPACE_H | ||||
| 
 | ||||
| #include <string> | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
| class AddressSpace | ||||
| { | ||||
|     std::string name; | ||||
|     long long start; | ||||
|     long long end; | ||||
| 
 | ||||
| public: | ||||
|     AddressSpace(std::string name, long long start, long long end); | ||||
| 
 | ||||
|     std::string getName(); | ||||
|     long long getStart() const; | ||||
|     long long getEnd() const; | ||||
| 
 | ||||
|     bool contains(long long int address); | ||||
|     bool contains(long long int start, long long int end); | ||||
| }; | ||||
| 
 | ||||
| } // namespace domain
 | ||||
| 
 | ||||
| #endif // DOMAIN_ADDRESS_SPACE_H
 | ||||
| @ -2,72 +2,55 @@ | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
|     Enumeration::Enumeration(std::string name, Value value) | ||||
|             : name(name), value(value) {} | ||||
| Enumeration::Enumeration(std::string name, Value value) | ||||
|     : name(name), value(value) | ||||
| {} | ||||
| 
 | ||||
|     std::string &Enumeration::getName() { | ||||
|         return name; | ||||
|     } | ||||
| 
 | ||||
|     Value Enumeration::getValue() { | ||||
|         return value; | ||||
|     } | ||||
| std::string& Enumeration::getName() { | ||||
|     return name; | ||||
| } | ||||
| Value Enumeration::getValue() { | ||||
|     return value; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|     Popup::Popup(std::string title, std::string text, PopupType type, std::vector<Rule> rules, | ||||
|                  std::vector<Enumeration> enumeration) | ||||
|             : title(title), text(text), type(type), rules(rules), enumerated(enumeration.size() > 0), | ||||
|               enumeration(enumeration) {} | ||||
| Popup::Popup(std::string title, std::string text, PopupType type, std::vector<Rule> rules, std::vector<Enumeration> enumeration) | ||||
|     : title(title), text(text), type(type), rules(rules), enumerated(enumeration.size() > 0), enumeration(enumeration) | ||||
| {} | ||||
| 
 | ||||
|     std::string Popup::getTitle() { | ||||
|         return title; | ||||
|     } | ||||
| std::string Popup::getTitle() { | ||||
|     return title; | ||||
| } | ||||
| std::string Popup::getText() { | ||||
|     return text; | ||||
| } | ||||
| Popup::PopupType Popup::getType() { | ||||
|     return type; | ||||
| } | ||||
| std::vector<Rule> Popup::getRules() { | ||||
|     return rules; | ||||
| } | ||||
| 
 | ||||
|     std::string Popup::getText() { | ||||
|         return text; | ||||
|     } | ||||
| 
 | ||||
|     Popup::PopupType Popup::getType() { | ||||
|         return type; | ||||
|     } | ||||
| 
 | ||||
|     std::vector<Rule> Popup::getRules() { | ||||
|         return rules; | ||||
|     } | ||||
| 
 | ||||
|     bool Popup::isEnumerated() { | ||||
|         return enumerated; | ||||
|     } | ||||
| 
 | ||||
|     std::vector<Enumeration> &Popup::getEnumeration() { | ||||
|         return enumeration; | ||||
|     } | ||||
| bool Popup::isEnumerated() { | ||||
|     return enumerated; | ||||
| } | ||||
| std::vector<Enumeration> &Popup::getEnumeration() { | ||||
|     return enumeration; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|     Attribute::Attribute(std::string name, std::optional<std::string> displayName, Value defaultValue, std::optional<Popup> popup) | ||||
|             : name(name), displayName(displayName), defaultValue(defaultValue), popup(popup) {} | ||||
| Attribute::Attribute(std::string name, Value defaultValue, std::optional<Popup> popup) | ||||
|     : name(name), defaultValue(defaultValue), popup(popup) | ||||
| {} | ||||
| 
 | ||||
|     std::string Attribute::getDisplayName() { | ||||
|         if(displayName.has_value()) { | ||||
|             return *displayName; | ||||
|         } | ||||
|         return name; | ||||
|     } | ||||
| 
 | ||||
|     std::string Attribute::getName() { | ||||
|         return name; | ||||
|     } | ||||
| 
 | ||||
|     Value Attribute::getDefault() { | ||||
|         return defaultValue; | ||||
|     } | ||||
| 
 | ||||
|     std::optional<Popup> Attribute::getPopup() { | ||||
|         return popup; | ||||
|     } | ||||
| 
 | ||||
|     void Attribute::setPupup(std::optional<Popup> popup)  { | ||||
|         this->popup = popup; | ||||
|     } | ||||
| std::string Attribute::getName() { | ||||
|     return name; | ||||
| } | ||||
| Value Attribute::getDefault() { | ||||
|     return defaultValue; | ||||
| } | ||||
| std::optional<Popup> Attribute::getPopup() { | ||||
|     return popup; | ||||
| } | ||||
| 
 | ||||
| } // namespace domain
 | ||||
|  | ||||
| @ -9,73 +9,62 @@ | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
|     class Enumeration { | ||||
|         std::string name; | ||||
|         Value value; | ||||
|     public: | ||||
|         Enumeration(std::string name, Value value); | ||||
| class Enumeration { | ||||
|     std::string name; | ||||
|     Value value; | ||||
| public: | ||||
|     Enumeration(std::string name, Value value); | ||||
| 
 | ||||
|         std::string &getName(); | ||||
|     std::string& getName(); | ||||
|     Value getValue(); | ||||
| }; | ||||
| 
 | ||||
|         Value getValue(); | ||||
| class Popup { | ||||
| public: | ||||
|     enum PopupType { | ||||
|         AUTOMATIC, | ||||
|         ON_DEMAND | ||||
|     }; | ||||
| 
 | ||||
|     class Popup { | ||||
|     public: | ||||
|         enum PopupType { | ||||
|             AUTOMATIC, | ||||
|             ON_DEMAND | ||||
|         }; | ||||
| private: | ||||
|     std::string title; | ||||
|     std::string text; | ||||
|     PopupType type; | ||||
| 
 | ||||
|     private: | ||||
|         std::string title; | ||||
|         std::string text; | ||||
|         PopupType type; | ||||
|     bool enumerated; | ||||
|     std::vector<Enumeration> enumeration; | ||||
|     std::vector<Rule> rules; | ||||
| 
 | ||||
|         bool enumerated; | ||||
|         std::vector<Enumeration> enumeration; | ||||
|         std::vector<Rule> rules; | ||||
| public: | ||||
|     Popup(std::string title, std::string text, PopupType type, std::vector<Rule> rules, std::vector<Enumeration> enumeration); | ||||
| 
 | ||||
|     public: | ||||
|         Popup(std::string title, std::string text, PopupType type, std::vector<Rule> rules, | ||||
|               std::vector<Enumeration> enumeration); | ||||
|     std::string getTitle(); | ||||
|     std::string getText(); | ||||
|     PopupType getType(); | ||||
|     std::vector<Rule> getRules(); | ||||
| 
 | ||||
|         std::string getTitle(); | ||||
|     bool isEnumerated(); | ||||
|     std::vector<Enumeration> &getEnumeration(); | ||||
| 
 | ||||
|         std::string getText(); | ||||
|     void setEnumeration(std::vector<Enumeration> enums) { | ||||
|         enumerated = true; | ||||
|         enumeration = std::move(enums); | ||||
|     } | ||||
| 
 | ||||
|         PopupType getType(); | ||||
| }; | ||||
| 
 | ||||
|         std::vector<Rule> getRules(); | ||||
| class Attribute | ||||
| { | ||||
|     std::string name; | ||||
|     Value defaultValue; | ||||
|     std::optional<Popup> popup; | ||||
| public: | ||||
|     Attribute(std::string name, Value defaultValue, std::optional<Popup> popup = std::nullopt); | ||||
| 
 | ||||
|         bool isEnumerated(); | ||||
| 
 | ||||
|         std::vector<Enumeration> &getEnumeration(); | ||||
| 
 | ||||
|         void setEnumeration(std::vector<Enumeration> enums) { | ||||
|             enumerated = true; | ||||
|             enumeration = enums; | ||||
|         } | ||||
| 
 | ||||
|     }; | ||||
| 
 | ||||
|     class Attribute { | ||||
|         std::string name; | ||||
|         std::optional<std::string> displayName; | ||||
|         Value defaultValue; | ||||
|         std::optional<Popup> popup; | ||||
|     public: | ||||
|         Attribute(std::string name, std::optional<std::string> displayName, Value defaultValue, std::optional<Popup> popup = std::nullopt); | ||||
| 
 | ||||
|         std::string getName(); | ||||
| 
 | ||||
|         std::string getDisplayName(); | ||||
| 
 | ||||
|         Value getDefault(); | ||||
| 
 | ||||
|         std::optional<Popup> getPopup(); | ||||
|         void setPupup(std::optional<Popup> popup); | ||||
|     }; | ||||
|     std::string getName(); | ||||
|     Value getDefault(); | ||||
|     std::optional<Popup> getPopup(); | ||||
| }; | ||||
| 
 | ||||
| } // namespace domain
 | ||||
| 
 | ||||
|  | ||||
| @ -2,72 +2,52 @@ | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
|     Wire::Wire(std::string name, WireType type, int width, bool hidden, bool hasTerminate, Value terminateWith) | ||||
|             : name(name), type(type), width(width), hidden(hidden), hasTerminate(hasTerminate), | ||||
|               terminateWith(terminateWith) {} | ||||
| Wire::Wire(std::string name, WireType type, int width, bool hidden, bool hasTerminate, Value terminateWith) | ||||
|     : name(name), type(type), width(width), hidden(hidden), hasTerminate(hasTerminate), terminateWith(terminateWith) | ||||
| {} | ||||
| 
 | ||||
|     std::string Wire::getName() { | ||||
|         return name; | ||||
|     } | ||||
| std::string Wire::getName() { | ||||
|     return name; | ||||
| } | ||||
| int Wire::getWidth() { | ||||
|     return width; | ||||
| } | ||||
| bool Wire::isHidden() { | ||||
|     return hidden; | ||||
| } | ||||
| 
 | ||||
|     std::string Bus::getInstanceName() { | ||||
|         return instanceName; | ||||
|     } | ||||
| bool Wire::hasTerminateWith() { | ||||
|     return hasTerminate; | ||||
| } | ||||
| Value Wire::getTerminateWith() { | ||||
|     return terminateWith; | ||||
| } | ||||
| Wire::WireType Wire::getType() { | ||||
|     return type; | ||||
| } | ||||
| 
 | ||||
| Bus::Bus(std::string name, std::string tooltip, BusType type, std::pair<int, int> count, std::vector<Wire> wires, std::optional<Display> display) | ||||
|     : name(name), tooltip(tooltip), type(type), count(count), wires(wires), display(display) | ||||
| {} | ||||
| 
 | ||||
|     int Wire::getWidth() { | ||||
|         return width; | ||||
|     } | ||||
| std::string Bus::getName() { | ||||
|     return name; | ||||
| } | ||||
| std::string Bus::getTooltip() { | ||||
|     return tooltip; | ||||
| } | ||||
| Bus::BusType Bus::getType() { | ||||
|     return type; | ||||
| } | ||||
| std::pair<int, int> Bus::getCount() { | ||||
|     return count; | ||||
| } | ||||
| std::optional<Display> Bus::getDisplay() { | ||||
|     return display; | ||||
| } | ||||
| std::vector<Wire> Bus::getWires() { | ||||
|     return wires; | ||||
| } | ||||
| 
 | ||||
|     bool Wire::isHidden() { | ||||
|         return hidden; | ||||
|     } | ||||
| 
 | ||||
|     bool Wire::hasTerminateWith() { | ||||
|         return hasTerminate; | ||||
|     } | ||||
| 
 | ||||
|     Value Wire::getTerminateWith() { | ||||
|         return terminateWith; | ||||
|     } | ||||
| 
 | ||||
|     Wire::WireType Wire::getType() { | ||||
|         return type; | ||||
|     } | ||||
| 
 | ||||
|     Bus::Bus(std::string name, std::optional<std::string> displayName, std::string instanceName, std::string tooltip, BusType type, std::pair<int, int> count, std::vector<Wire> wires, | ||||
|              std::optional<ui::Bus> displayBus) | ||||
|             : name(name), displayName(displayName), instanceName(instanceName), tooltip(tooltip), type(type), count(count), wires(wires), displayBus(displayBus) {} | ||||
| 
 | ||||
|     std::string Bus::getName() { | ||||
|         return name; | ||||
|     } | ||||
| 
 | ||||
|     std::string Bus::getDisplayName() { | ||||
|         if(displayName.has_value()) { | ||||
|             return *displayName; | ||||
|         } | ||||
|         return name; | ||||
|     } | ||||
| 
 | ||||
|     std::string Bus::getTooltip() { | ||||
|         return tooltip; | ||||
|     } | ||||
| 
 | ||||
|     Bus::BusType Bus::getType() { | ||||
|         return type; | ||||
|     } | ||||
| 
 | ||||
|     std::pair<int, int> Bus::getCount() { | ||||
|         return count; | ||||
|     } | ||||
| 
 | ||||
|     std::vector<Wire> Bus::getWires() { | ||||
|         return wires; | ||||
|     } | ||||
| 
 | ||||
|     std::optional<ui::Bus> Bus::getDisplayBus() { | ||||
|         return displayBus; | ||||
|     } | ||||
| 
 | ||||
| } // namespace domain
 | ||||
|  | ||||
| @ -11,78 +11,63 @@ | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
|     class Wire { | ||||
|     public: | ||||
|         enum WireType { | ||||
|             WIRE_DEFAULT, | ||||
|             WIRED_AND, | ||||
|             WIRED_OR, | ||||
|             R_WIRE | ||||
|         }; | ||||
| 
 | ||||
| 
 | ||||
|     private: | ||||
|         std::string name; | ||||
|         WireType type; | ||||
|         int width; | ||||
|         bool hidden = false; | ||||
|         bool hasTerminate = false; | ||||
|         Value terminateWith; | ||||
| 
 | ||||
|     public: | ||||
|         Wire(std::string name, WireType type, int width, bool hidden, bool hasTerminate, Value terminateWith); | ||||
| 
 | ||||
|         std::string getName(); | ||||
| 
 | ||||
|         int getWidth(); | ||||
| 
 | ||||
|         bool isHidden(); | ||||
| 
 | ||||
|         bool hasTerminateWith(); | ||||
| 
 | ||||
|         Value getTerminateWith(); | ||||
| 
 | ||||
|         WireType getType(); | ||||
| class Wire | ||||
| { | ||||
| public: | ||||
|     enum WireType { | ||||
|         WIRE_DEFAULT, | ||||
|         WIRED_AND, | ||||
|         WIRED_OR, | ||||
|         R_WIRE | ||||
|     }; | ||||
| 
 | ||||
|     class Bus { | ||||
|     public: | ||||
|         enum BusType { | ||||
|             AUTOMATIC, | ||||
|             REGULAR, | ||||
|             SINGLE_AUTOMATIC | ||||
|         }; | ||||
|     private: | ||||
|         std::string name; | ||||
|         std::optional<std::string> displayName; | ||||
|         std::string instanceName; | ||||
|         std::string tooltip; | ||||
|         BusType type; | ||||
| 
 | ||||
|         std::pair<int, int> count; | ||||
|         std::optional<ui::Bus> displayBus; | ||||
|         std::vector<Wire> wires; | ||||
| private: | ||||
|     std::string name; | ||||
|     WireType type; | ||||
|     int width; | ||||
|     bool hidden; | ||||
|     bool hasTerminate; | ||||
|     Value terminateWith; | ||||
| 
 | ||||
|     public: | ||||
|         Bus(std::string name, std::optional<std::string> displayName, std::string instanceName, std::string tooltip, BusType type, std::pair<int, int> count, std::vector<Wire> wires, | ||||
|             std::optional<ui::Bus> display = std::nullopt); | ||||
| public: | ||||
|     Wire(std::string name, WireType type, int width, bool hidden, bool hasTerminate, Value terminateWith); | ||||
| 
 | ||||
|         std::string getName(); | ||||
|     std::string getName(); | ||||
|     int getWidth(); | ||||
|     bool isHidden(); | ||||
|     bool hasTerminateWith(); | ||||
|     Value getTerminateWith(); | ||||
|     WireType getType(); | ||||
| }; | ||||
| 
 | ||||
|         std::string getDisplayName(); | ||||
| 
 | ||||
|         std::string getInstanceName(); | ||||
| 
 | ||||
|         std::string getTooltip(); | ||||
| 
 | ||||
|         BusType getType(); | ||||
| 
 | ||||
|         std::pair<int, int> getCount(); | ||||
| 
 | ||||
|         std::vector<Wire> getWires(); | ||||
| 
 | ||||
|         std::optional<ui::Bus> getDisplayBus(); | ||||
| class Bus | ||||
| { | ||||
| public: | ||||
|     enum BusType { | ||||
|         AUTOMATIC, | ||||
|         REGULAR, | ||||
|         SINGLE_AUTOMATIC | ||||
|     }; | ||||
| private: | ||||
|     std::string name; | ||||
|     std::string tooltip; | ||||
|     BusType type; | ||||
| 
 | ||||
|     std::pair<int, int> count; | ||||
|     std::optional<Display> display; | ||||
|     std::vector<Wire> wires; | ||||
| 
 | ||||
| public: | ||||
|     Bus(std::string name, std::string tooltip, BusType type, std::pair<int, int> count, std::vector<Wire> wires, std::optional<Display> display = std::nullopt); | ||||
| 
 | ||||
|     std::string getName(); | ||||
|     std::string getTooltip(); | ||||
|     BusType getType(); | ||||
|     std::pair<int, int> getCount(); | ||||
|     std::vector<Wire> getWires(); | ||||
|     std::optional<Display> getDisplay(); | ||||
| }; | ||||
| 
 | ||||
| } // namespace domain
 | ||||
| 
 | ||||
|  | ||||
| @ -3,415 +3,337 @@ | ||||
| //
 | ||||
| 
 | ||||
| #include <set> | ||||
| #include <QLayout> | ||||
| #include "comdel_generator.h" | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
|     void generate_schema(std::string &librarySource, Schema *schema, std::ostream &buffer) { | ||||
|         buffer << "@source \"" << librarySource << "\"" << std::endl << std::endl; | ||||
| void generateSchemaFile(std::string& librarySource, Schema *schema, std::ostream &buffer) { | ||||
|     buffer << "@source " << librarySource << std::endl << std::endl; | ||||
| 
 | ||||
|         buffer << "@schema {" << std::endl; | ||||
|     buffer << "@schema {" << std::endl; | ||||
| 
 | ||||
|         for (auto &componentInstance: schema->componentInstances) { | ||||
|             buffer << "\t" << "@instance " << componentInstance->name << " " << componentInstance->component.getName() | ||||
|                    << " {" << std::endl; | ||||
|             buffer << "\t\t" << "@position (" << componentInstance->position.first << ", " | ||||
|                    << componentInstance->position.second << ")" << std::endl; | ||||
|     for(auto &componentInstance: schema->componentInstances) { | ||||
|         buffer << "\t"   << "@instance " << componentInstance->name << " " << componentInstance->component.getName() << " {" << std::endl; | ||||
|         buffer << "\t\t" << "@position (" << componentInstance->position.first << ", " << componentInstance->position.second << ")" << std::endl; | ||||
| 
 | ||||
|             for (auto &attribute: componentInstance->attributes) { | ||||
|         for(auto &attribute: componentInstance->attributes) { | ||||
|             buffer << "\t\t" << "@attribute " << attribute.name << " " << attribute.value.stringify() << std::endl; | ||||
|         } | ||||
| 
 | ||||
|         buffer << "\t}" << std::endl << std::endl; | ||||
|     } | ||||
| 
 | ||||
|     for(auto &busInstance: schema->busInstances) { | ||||
|         buffer << "\t"   << "@instance " << busInstance->name << " " << busInstance->bus.getName() << " {" << std::endl; | ||||
|         buffer << "\t\t" << "@position (" << busInstance->position.first << ", " << busInstance->position.second << ")" << std::endl; | ||||
|         buffer << "\t\t" << "@size " << busInstance->size << std::endl; | ||||
|         buffer << "\t}" << std::endl << std::endl; | ||||
|     } | ||||
| 
 | ||||
|     for(auto &conn: schema->connections) { | ||||
|         auto busConn = dynamic_cast<domain::BusConnectionInstance*>(conn.get()); | ||||
|         if(busConn) { | ||||
|             buffer << "\t"  << "@connection (" << busConn->instance->name << "." << busConn->connection.getComponent().pin << ", " << busConn->bus->name << ") {" << std::endl; | ||||
| 
 | ||||
|             for(auto attribute: busConn->attributes) { | ||||
|                 buffer << "\t\t" << "@attribute " << attribute.name << " " << attribute.value.stringify() << std::endl; | ||||
|             } | ||||
| 
 | ||||
|             buffer << "\t}" << std::endl << std::endl; | ||||
|             buffer << "\t"  << "}" << std::endl; | ||||
|         } | ||||
|         auto dirConn = dynamic_cast<domain::DirectConnectionInstance*>(conn.get()); | ||||
|         if(dirConn) { | ||||
|             buffer  << "\t"  << "@connection (" << dirConn->instance->name << "." << dirConn->connection.getComponent().pin << ", " | ||||
|                     << dirConn->bus->name << ", " | ||||
|                     << dirConn->secondInstance->name << "." << dirConn->connection.getSecondComponent()->pin | ||||
|                     << ") {" << std::endl; | ||||
| 
 | ||||
|         for (auto &busInstance: schema->busInstances) { | ||||
|             buffer << "\t" << "@instance " << busInstance->name << " " << busInstance->bus.getName() << " {" | ||||
|                    << std::endl; | ||||
|             buffer << "\t\t" << "@position (" << busInstance->position.first << ", " << busInstance->position.second | ||||
|                    << ")" << std::endl; | ||||
|             buffer << "\t\t" << "@size " << busInstance->size << std::endl; | ||||
|             buffer << "\t}" << std::endl << std::endl; | ||||
|         } | ||||
| 
 | ||||
|         for (auto &conn: schema->connections) { | ||||
|             auto busConn = dynamic_cast<domain::BusConnectionInstance *>(conn.get()); | ||||
|             if (busConn) { | ||||
|                 buffer << "\t" << "@connection (" << busConn->instance->name << "." | ||||
|                        << busConn->connection.getComponent().pin << ", " << busConn->bus->name << ") {" << std::endl; | ||||
| 
 | ||||
|                 for (auto attribute: busConn->attributes) { | ||||
|                     buffer << "\t\t" << "@attribute " << attribute.name << " " << attribute.value.stringify() | ||||
|                            << std::endl; | ||||
|                 } | ||||
| 
 | ||||
|                 buffer << "\t" << "}" << std::endl; | ||||
|             for(auto attribute: dirConn->attributes) { | ||||
|                 buffer << "\t\t" << "@attribute " << attribute.name << " " << attribute.value.stringify() << std::endl; | ||||
|             } | ||||
|             auto dirConn = dynamic_cast<domain::DirectConnectionInstance *>(conn.get()); | ||||
|             if (dirConn) { | ||||
|                 buffer << "\t" << "@connection (" << dirConn->instance->name << "." | ||||
|                        << dirConn->connection.getComponent().pin << ", " | ||||
|                        << dirConn->bus->name << ", " | ||||
|                        << dirConn->secondInstance->name << "." << dirConn->connection.getSecondComponent()->pin | ||||
|                        << ") {" << std::endl; | ||||
| 
 | ||||
|                 for (auto attribute: dirConn->attributes) { | ||||
|                     buffer << "\t\t" << "@attribute " << attribute.name << " " << attribute.value.stringify() | ||||
|                            << std::endl; | ||||
|                 } | ||||
|             buffer << "\t"  << "}" << std::endl; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|                 buffer << "\t" << "}" << std::endl; | ||||
|     buffer << "}" << std::endl; | ||||
| } | ||||
| 
 | ||||
| std::set<std::string> createImports(Schema *schema); | ||||
| 
 | ||||
| std::map<string, string> generateWires(Schema *schema, ostream &ostream); | ||||
| 
 | ||||
| void generateSubComponents(Schema *schema, map <string, string> &wires, ostream &buffer); | ||||
| 
 | ||||
| void generateDisplay(Schema *schema, ostream &buffer); | ||||
| 
 | ||||
| void generateComdelFile(Schema *schema, Library &library, std::ostream &buffer) { | ||||
|     buffer << library.getHeader() << std::endl; | ||||
| 
 | ||||
|     std::set<std::string> imports = createImports(schema); | ||||
| 
 | ||||
|     for(auto& import: imports) { | ||||
|        buffer << "#include \"" << library.getComponentDirectory() << "\\" << import << "\"" << std::endl; | ||||
|     } | ||||
| 
 | ||||
|     buffer << "\n\n" << std::endl; | ||||
| 
 | ||||
|     buffer << "component System" << std::endl << "{" << std::endl; | ||||
| 
 | ||||
|     if(library.getComponentHeader().has_value()) { | ||||
|         buffer << library.getComponentHeader().value() << endl; | ||||
|     } | ||||
| 
 | ||||
|     auto wires = generateWires(schema, buffer); | ||||
| 
 | ||||
|     generateSubComponents(schema, wires, buffer); | ||||
| 
 | ||||
|     generateDisplay(schema, buffer); | ||||
| 
 | ||||
|     buffer << "}"; | ||||
| } | ||||
| 
 | ||||
| void generateBus(BusInstance *bus, ostream &buffer); | ||||
| 
 | ||||
| void generateDisplay(Schema *schema, ostream &buffer) { | ||||
|     buffer << "\n\tdisplay {\n"; | ||||
| 
 | ||||
|     for(auto &component: schema->componentInstances) { | ||||
|         buffer << "\t\tcomponent { x: " << component->position.first << "; y: " << component->position.second << "; ref: \"" << component->name << "\"; }" << std::endl; | ||||
|     } | ||||
| 
 | ||||
|     for(auto &bus: schema->busInstances) { | ||||
|         generateBus(bus.get(), buffer); | ||||
|     } | ||||
| 
 | ||||
|     buffer << "\t}\n"; | ||||
| } | ||||
| 
 | ||||
| void generateBus(BusInstance *bus, ostream &buffer) { | ||||
|     buffer << "\n"; | ||||
|     buffer << "\t\t// " << bus->name << " bus\n\n"; | ||||
| 
 | ||||
|     if(bus->bus.getDisplay().has_value()) { | ||||
|         bus->bus.getDisplay()->comdel(buffer, bus->position.first, bus->position.second, bus->size); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void generateWire(std::string &name, Wire& wire, ostream &buffer); | ||||
| 
 | ||||
| std::map<string, string> generateWires(Schema *schema, ostream &buffer) { | ||||
|     std::set<string> usedNames; | ||||
|     std::map<string, string> usedMappings; | ||||
|     for(auto &bus: schema->busInstances) { | ||||
|         buffer << "\t//" << bus->name << std::endl; | ||||
|         for(auto& wire: bus->bus.getWires()) { | ||||
|             std::string name = wire.getName(); | ||||
|             if(usedNames.count(wire.getName()) > 0) { | ||||
|                 name = bus->name + "__" + wire.getName(); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         buffer << "}" << std::endl; | ||||
|     } | ||||
| 
 | ||||
|     std::set<std::string> createImports(Schema *schema); | ||||
| 
 | ||||
|     std::map<string, string> generateWires(Schema *schema, ostream &ostream); | ||||
| 
 | ||||
|     void generateSubComponents(Schema *schema, map<string, string> &wires, ostream &buffer); | ||||
| 
 | ||||
|     void generateDisplay(Schema *schema, ostream &buffer); | ||||
| 
 | ||||
|     void generate_comdel(Schema *schema, Library &library, std::ostream &buffer) { | ||||
|         buffer << library.getHeader() << std::endl; | ||||
| 
 | ||||
|         std::set<std::string> imports = createImports(schema); | ||||
| 
 | ||||
|         for (auto &import: imports) { | ||||
|             buffer << "#include \"" << library.getComponentDirectory() << "\\" << import << "\"" << std::endl; | ||||
|         } | ||||
| 
 | ||||
|         buffer << "\n\n" << std::endl; | ||||
| 
 | ||||
|         buffer << "component System" << std::endl << "{" << std::endl; | ||||
| 
 | ||||
|         if (library.getComponentHeader().has_value()) { | ||||
|             buffer << library.getComponentHeader().value() << endl; | ||||
|         } | ||||
| 
 | ||||
|         auto wires = generateWires(schema, buffer); | ||||
| 
 | ||||
|         generateSubComponents(schema, wires, buffer); | ||||
| 
 | ||||
|         generateDisplay(schema, buffer); | ||||
| 
 | ||||
|         buffer << "}"; | ||||
|     } | ||||
| 
 | ||||
|     void generateBus(BusInstance *bus, ostream &buffer); | ||||
| 
 | ||||
|     void generateConnection(ConnectionInstance *connection, ostream &buffer); | ||||
| 
 | ||||
|     void generateDisplay(Schema *schema, ostream &buffer) { | ||||
|         buffer << "\n\tdisplay {\n"; | ||||
| 
 | ||||
|         for (auto &component: schema->componentInstances) { | ||||
|             buffer << "\t\tcomponent { x: " << component->position.first << "; y: " << component->position.second | ||||
|                    << "; ref: \"" << component->name << "\"; }" << std::endl; | ||||
|         } | ||||
| 
 | ||||
|         for (auto &bus: schema->busInstances) { | ||||
|             generateBus(bus.get(), buffer); | ||||
|         } | ||||
| 
 | ||||
|         buffer << "\n"; | ||||
| 
 | ||||
|         for (auto &connection: schema->connections) { | ||||
|             generateConnection(connection.get(), buffer); | ||||
|         } | ||||
| 
 | ||||
|         buffer << "\t}\n"; | ||||
|     } | ||||
| 
 | ||||
|     void generateConnection(ConnectionInstance *connection, ostream &buffer) { | ||||
| 
 | ||||
|         auto x1 = connection->start.first; | ||||
|         auto y1 = connection->start.second; | ||||
|         auto x2 = connection->end.first; | ||||
|         auto y2 = connection->end.second; | ||||
| 
 | ||||
|         buffer << "\t\tpath {\n"; | ||||
|         buffer << "\t\t\tx:0; y:0;\n"; | ||||
|         buffer << "\t\t\tpoints: ("; | ||||
|         buffer << "(" << x1 << ", " << y1 << "),"; | ||||
|         buffer << "(" << (x2 - x1) << "," << (y2 - y1) << "));\n"; | ||||
|         buffer << "\t\t}" << std::endl; | ||||
|     } | ||||
| 
 | ||||
|     void generateBus(BusInstance *bus, ostream &buffer) { | ||||
|         buffer << "\n"; | ||||
|         buffer << "\t\t// " << bus->name << " bus\n\n"; | ||||
| 
 | ||||
|         if (bus->bus.getDisplayBus().has_value()) { | ||||
|             bus->bus.getDisplayBus()->comdel(buffer, bus->position.first, bus->position.second, bus->size); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void generateWire(std::string &name, Wire &wire, ostream &buffer); | ||||
| 
 | ||||
|     std::map<string, string> generateWires(Schema *schema, ostream &buffer) { | ||||
|         std::set<string> usedNames; | ||||
|         std::map<string, string> usedMappings; | ||||
|         for (auto &bus: schema->busInstances) { | ||||
|             buffer << "\t//" << bus->name << std::endl; | ||||
|             for (auto &wire: bus->bus.getWires()) { | ||||
|                 auto name = wire.getName(); | ||||
|                 if (usedNames.count(name) > 0) { | ||||
|                     name = bus->name + "__" + wire.getName(); | ||||
|                 } | ||||
|                 usedNames.insert(name); | ||||
|                 usedMappings.insert(std::make_pair(bus->name + "." + wire.getName(), name)); | ||||
| 
 | ||||
|                 generateWire(name, wire, buffer); | ||||
|             if(wire.isHidden()) { | ||||
|                 name = "--" + name; | ||||
|             } | ||||
|             buffer << std::endl << std::endl; | ||||
|             usedNames.insert(name); | ||||
|             usedMappings.insert(std::make_pair(bus->name + "." + wire.getName(), name)); | ||||
| 
 | ||||
|             generateWire(name, wire, buffer); | ||||
|         } | ||||
|         return usedMappings; | ||||
|         buffer << std::endl << std::endl; | ||||
|     } | ||||
|     return usedMappings; | ||||
| } | ||||
| 
 | ||||
| void generateWire(std::string &name, Wire& wire, ostream &buffer) { | ||||
|     buffer << "\t"; | ||||
|     switch (wire.getType()) { | ||||
|         case Wire::R_WIRE: | ||||
|             buffer << "r_wire"; | ||||
|             break; | ||||
|         case Wire::WIRED_AND: | ||||
|             buffer << "wired_and"; | ||||
|             break; | ||||
|         case Wire::WIRED_OR: | ||||
|             buffer << "wired_or"; | ||||
|             break; | ||||
|         default: | ||||
|             buffer << "wire"; | ||||
|     } | ||||
| 
 | ||||
|     void generateWire(std::string &name, Wire &wire, ostream &buffer) { | ||||
|         buffer << "\t"; | ||||
|         switch (wire.getType()) { | ||||
|             case Wire::R_WIRE: | ||||
|                 buffer << "r_wire"; | ||||
|                 break; | ||||
|             case Wire::WIRED_AND: | ||||
|                 buffer << "wired_and"; | ||||
|                 break; | ||||
|             case Wire::WIRED_OR: | ||||
|                 buffer << "wired_or"; | ||||
|                 break; | ||||
|             default: | ||||
|                 buffer << "wire"; | ||||
|         } | ||||
| 
 | ||||
|         if (wire.getWidth() != 1) { | ||||
|             buffer << "<" << wire.getWidth() << ">"; | ||||
|         } | ||||
|         buffer << " " << (wire.isHidden() ? "--" : "") << name; | ||||
|         if(wire.hasTerminateWith()) { | ||||
|             buffer << " = " << wire.getTerminateWith().asInt(); | ||||
|         } | ||||
|         buffer << ";" << std::endl; | ||||
|     if(wire.getWidth() != 1) { | ||||
|         buffer << "<" << wire.getWidth() << ">"; | ||||
|     } | ||||
|     buffer << " " << name << ";" << std::endl; | ||||
| } | ||||
| 
 | ||||
|     std::set<std::string> createImports(Schema *schema) { | ||||
|         std::set<std::string> importSet; | ||||
|         for (auto &component: schema->componentInstances) { | ||||
|             importSet.insert(component->component.getSource()); | ||||
|         } | ||||
|         return importSet; | ||||
| std::set<std::string> createImports(Schema *schema) { | ||||
|     std::set<std::string> importSet; | ||||
|     for(auto &component: schema->componentInstances) { | ||||
|         importSet.insert(component->component.getSource()); | ||||
|     } | ||||
|     return importSet; | ||||
| } | ||||
| 
 | ||||
|     void | ||||
|     generateAutomaticPin(DirectConnectionInstance *connection, string name, string pin, map<string, string> wireNames, | ||||
|                          stringstream &buffer); | ||||
| void generateAutomaticPin(DirectConnectionInstance *connection, string name, string pin, map<string, string> wireNames, stringstream &buffer); | ||||
| 
 | ||||
|     void generateSingleAutomaticPin(DirectConnectionInstance *instance, string name, string pin, | ||||
|                                     map<string, string> &wireNames, | ||||
|                                     stringstream &buffer); | ||||
| void generateSingleAutomaticPin(DirectConnectionInstance *instance, string name, string pin, | ||||
|                                map <string, string> &wireNames, | ||||
|                                stringstream &buffer); | ||||
| 
 | ||||
|     void generateSingleAutomaticPin(std::vector<ConnectionInstance*> connections, ComponentInstance *instance, string pin, | ||||
|                                     map<string, string> &wireNames, stringstream &buffer); | ||||
| 
 | ||||
|     void generateComponent(Schema *schema, map<string, string> &wires, ostream &buffer, | ||||
|                            shared_ptr<ComponentInstance> &component); | ||||
|     void generateComponent(Schema *schema, map <string, string> &wires, ostream &buffer, | ||||
|                            shared_ptr <ComponentInstance> &component); | ||||
| 
 | ||||
|     void generateSubComponents(Schema *schema, map<string, string> &wires, ostream &buffer) { | ||||
| 
 | ||||
|         buffer << "\t// components --------------------------------------------" << std::endl; | ||||
|     buffer << "\t// components --------------------------------------------" << std::endl; | ||||
| 
 | ||||
|         for (auto &component: schema->componentInstances) { | ||||
|             if (component->component.getType() == Component::MEMORY) { | ||||
|                 generateComponent(schema, wires, buffer, component); | ||||
|             } | ||||
|     for(auto& component: schema->componentInstances) { | ||||
|         if(component->component.getType() == Component::MEMORY) { | ||||
|             generateComponent(schema, wires, buffer, component); | ||||
|         } | ||||
|         for (auto &component: schema->componentInstances) { | ||||
|             if (component->component.getType() != Component::MEMORY) { | ||||
|                 generateComponent(schema, wires, buffer, component); | ||||
|             } | ||||
|     } | ||||
|     for(auto& component: schema->componentInstances) { | ||||
|         if(component->component.getType() != Component::MEMORY) { | ||||
|             generateComponent(schema, wires, buffer, component); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void generateComponent(Schema *schema, map <string, string> &wires, ostream &buffer, | ||||
|                        shared_ptr <ComponentInstance> &component) { | ||||
|     buffer << "\tsubcomponent " << component->component.getName() << " " << component->name; | ||||
| 
 | ||||
|     std::optional<InstanceAttribute> memory; | ||||
| 
 | ||||
|     std::vector<InstanceAttribute> attributes; | ||||
|     for(auto& attr: component->attributes) { | ||||
|         if(attr.name != "_memory") { | ||||
|             attributes.push_back(attr); | ||||
|         } else if(attr.name == "_memory" && attr.value.asMemoryReference().has_value()) { | ||||
|             memory = attr; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void generateComponent(Schema *schema, map<string, string> &wires, ostream &buffer, | ||||
|                            shared_ptr<ComponentInstance> &component) { | ||||
|         buffer << "\tsubcomponent " << component->component.getName() << " " << component->name; | ||||
| 
 | ||||
|         std::optional<InstanceAttribute> memory; | ||||
| 
 | ||||
|         std::vector<InstanceAttribute> attributes; | ||||
|         for (auto &attr: component->attributes) { | ||||
|             if (attr.name != "_memory") { | ||||
|                 attributes.push_back(attr); | ||||
|             } else if (attr.name == "_memory" && attr.value.asMemoryReference().has_value()) { | ||||
|                 memory = attr; | ||||
|             } | ||||
|     if(!attributes.empty()) { | ||||
|         buffer << "<"; | ||||
|         buffer << attributes[0].value.stringify(); | ||||
|         for(int i=1; i<attributes.size(); i++) { | ||||
|             buffer << ", " << attributes[i].value.stringify(); | ||||
|         } | ||||
|         buffer << ">"; | ||||
|     } | ||||
| 
 | ||||
|         if (!attributes.empty()) { | ||||
|             buffer << "<"; | ||||
|             buffer << attributes[0].value.stringify(); | ||||
|             for (int i = 1; i < attributes.size(); i++) { | ||||
|                 buffer << ", " << attributes[i].value.stringify(); | ||||
|             } | ||||
|             buffer << ">"; | ||||
|         } | ||||
|     stringstream tempOutput; | ||||
| 
 | ||||
|         stringstream tempOutput; | ||||
| 
 | ||||
|         for (auto &pin: component->component.getPins()) { | ||||
|             if (schema->hasConnection(component->name, pin.getName())) { | ||||
|                 auto connections = schema->getConnections(component->name, pin.getName()); | ||||
|                 if(connections.size() == 1) { | ||||
|                     auto conn = connections[0]; | ||||
|                     auto busConn = dynamic_cast<BusConnectionInstance *>(conn); | ||||
|                     if (busConn != nullptr) { | ||||
|                         for (auto wire: busConn->connection.getWires()) { | ||||
|                             if (wire.isType(Value::ATTRIBUTE_REFERENCE)) { | ||||
|                                 auto attribute = busConn->getAttribute(wire.asReference()); | ||||
|                                 if (wire.isType(Value::WIRE_REFERENCE)) { | ||||
|                                     tempOutput << wires[busConn->bus->name + "." + attribute.value.asReference()] << ", "; | ||||
|                                 } else if (wire.isType(Value::NIL)) { | ||||
|                                     tempOutput << "*, "; | ||||
|                                 } else { | ||||
|                                     tempOutput << attribute.value.stringify() << ", "; | ||||
|                                 } | ||||
|                             } else { | ||||
|                                 if (wire.isType(Value::WIRE_REFERENCE)) { | ||||
|                                     tempOutput << wires[busConn->bus->name + "." + wire.asReference()] << ", "; | ||||
|                                 } else if (wire.isType(Value::NIL)) { | ||||
|                                     tempOutput << "*, "; | ||||
|                                 } else { | ||||
|                                     tempOutput << wire.stringify() << ", "; | ||||
|                                 } | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                     auto dirConn = dynamic_cast<DirectConnectionInstance *>(conn); | ||||
|                     if (dirConn != nullptr) { | ||||
|                         if (dirConn->bus->bus.getType() == Bus::AUTOMATIC) { | ||||
|                             generateAutomaticPin(dirConn, component->name, pin.getName(), wires, tempOutput); | ||||
|     for(auto &pin: component->component.getPins()) { | ||||
|         if(schema->hasConnection(component->name, pin.getName())) { | ||||
|             auto conn = schema->getConnection(component->name, pin.getName()); | ||||
|             auto busConn = dynamic_cast<BusConnectionInstance*>(conn); | ||||
|             if(busConn != nullptr) { | ||||
|                 for(auto wire: busConn->connection.getWires()) { | ||||
|                     if(wire.isType(Value::ATTRIBUTE_REFERENCE)) { | ||||
|                         auto attribute = busConn->getAttribute(wire.asReference()); | ||||
|                         if(wire.isType(Value::WIRE_REFERENCE)) { | ||||
|                             tempOutput << wires[busConn->bus->name + "." + attribute.value.asReference()] << ", "; | ||||
|                         } else if(wire.isType(Value::NIL)) { | ||||
|                             tempOutput << "*, "; | ||||
|                         } else { | ||||
|                             generateSingleAutomaticPin(dirConn, component->name, pin.getName(), wires, tempOutput); | ||||
|                             tempOutput << attribute.value.stringify() << ", "; | ||||
|                         } | ||||
|                     } else { | ||||
|                         if(wire.isType(Value::WIRE_REFERENCE)) { | ||||
|                             tempOutput << wires[busConn->bus->name + "." + wire.asReference()] << ", "; | ||||
|                         } else if(wire.isType(Value::NIL)) { | ||||
|                             tempOutput << "*, "; | ||||
|                         } else { | ||||
|                             tempOutput << wire.stringify() << ", "; | ||||
|                         } | ||||
|                     } | ||||
|                 } else { | ||||
|                     generateSingleAutomaticPin(connections, component.get(), pin.getName(), wires, tempOutput); | ||||
|                 } | ||||
|             } else { | ||||
|                 // if no connection exists than defaults must exist
 | ||||
|                 for (auto &wire: *pin.getWires()) { | ||||
|                     if(wire.isType(Value::NIL)) { | ||||
|                         tempOutput << "*, "; | ||||
|                     } else { | ||||
|                         tempOutput << wire.stringify() << ", "; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         auto wireList = tempOutput.str(); | ||||
|         wireList.pop_back(); | ||||
|         wireList.pop_back(); // remove last COMMA(", ")
 | ||||
| 
 | ||||
|         buffer << "(" << wireList << ")"; | ||||
| 
 | ||||
|         if (memory.has_value()) { | ||||
|             buffer << " uses " << *memory->value.asMemoryReference(); | ||||
|         } | ||||
| 
 | ||||
|         buffer << ";" << std::endl; | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     void generateSingleAutomaticPin(DirectConnectionInstance *connection, string name, string pin, | ||||
|                                     map<string, string> &wireNames, stringstream &buffer) { | ||||
|         std::vector<Value> wires; | ||||
|         std::string selected; | ||||
|         std::vector<Value> defaults; | ||||
|         if (connection->instance->name == name && connection->connection.getComponent().pin == pin) { | ||||
|             wires = connection->connection.getWires(); | ||||
|             selected = connection->attributes[0].value.asString(); | ||||
|             defaults = *connection->instance->component.getPin(pin).getWires(); | ||||
|         } else { | ||||
|             wires = *connection->connection.getSecondWires(); | ||||
|             selected = connection->attributes[1].value.asString(); | ||||
|             defaults = *connection->secondInstance->component.getPin(pin).getWires(); | ||||
|         } | ||||
| 
 | ||||
|         for (int i = 0; i < wires.size(); i++) { | ||||
|             if (wires[i].isType(Value::STRING)) { | ||||
|                 if (wires[i].asString() == selected) { | ||||
|                     auto wireName = connection->bus->name + "." + connection->bus->bus.getWires()[0].getName(); | ||||
|                     buffer << wireNames[wireName] << ", "; | ||||
|                 } else if(defaults[i].isType(Value::NIL)) { | ||||
|                     buffer << "*, "; | ||||
|                 } else { | ||||
|                     buffer << defaults[i].stringify() << ", "; | ||||
|                 } | ||||
|             } else if(defaults[i].isType(Value::NIL)) { | ||||
|                 buffer << "*, "; | ||||
|             } else { | ||||
|                 buffer << wires[i].stringify() << ", "; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void generateSingleAutomaticPin(std::vector<ConnectionInstance*> connections, ComponentInstance *instance, string pin, | ||||
|                                     map<string, string> &wireNames, stringstream &buffer) { | ||||
|         std::map<int, BusInstance*> selectedValues; | ||||
|         for(auto conn: connections) { | ||||
|             auto dirConn = dynamic_cast<DirectConnectionInstance*>(conn); | ||||
|             auto index = dirConn->getSelected(ConnectionComponent{instance->name, pin}); | ||||
|             selectedValues.insert(std::make_pair(index, dirConn->bus)); | ||||
|             if(dirConn != nullptr) { | ||||
|                 if(dirConn->bus->bus.getType() == Bus::AUTOMATIC) { | ||||
|                     generateAutomaticPin(dirConn, component->name, pin.getName(), wires, tempOutput); | ||||
|                 } else { | ||||
|                     generateSingleAutomaticPin(dirConn, component->name, pin.getName(), wires, tempOutput); | ||||
|                 } | ||||
|             } | ||||
|         } else { | ||||
|             // if no connection exists than defaults must exist
 | ||||
|             for(auto& wire: *pin.getWires()) { | ||||
|                 tempOutput << wire.stringify() << ", "; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|         std::vector<Value> defaultWires = instance->component.getPin(pin).getWires().value(); | ||||
|     auto wireList = tempOutput.str(); | ||||
|     wireList.pop_back(); | ||||
|     wireList.pop_back(); // remove last COMMA(", ")
 | ||||
| 
 | ||||
|         for (int i=0; i<defaultWires.size(); i++) { | ||||
|             if(selectedValues.count(i) > 0) { | ||||
|                 auto wireName = selectedValues[i]->name + "." + selectedValues[i]->bus.getWires()[0].getName(); | ||||
|                 buffer << wireNames[wireName] << ", "; | ||||
|             } else if(defaultWires[i].isType(Value::NIL)) { | ||||
|     buffer << "(" << wireList << ")"; | ||||
| 
 | ||||
|     if(memory.has_value()) { | ||||
|         buffer << " uses " << *memory->value.asMemoryReference(); | ||||
|     } | ||||
| 
 | ||||
|     buffer << ";" << std::endl; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| void generateSingleAutomaticPin(DirectConnectionInstance *connection, string name, string pin, map <string, string> &wireNames, stringstream &buffer) { | ||||
|     std::vector<Value> wires; | ||||
|     std::string selected; | ||||
|     std::vector<Value> defaults; | ||||
|     if(connection->instance->name == name && connection->connection.getComponent().pin == pin) { | ||||
|         wires = connection->connection.getWires(); | ||||
|         selected = connection->attributes[0].value.asReference(); | ||||
|         defaults = *connection->instance->component.getPin(pin).getWires(); | ||||
|     } else { | ||||
|         wires = *connection->connection.getSecondWires(); | ||||
|         selected = connection->attributes[1].value.asReference(); | ||||
|         defaults = *connection->secondInstance->component.getPin(pin).getWires(); | ||||
|     } | ||||
| 
 | ||||
|     for(int i=0; i<wires.size(); i++) { | ||||
|         if(wires[i].isType(Value::STRING)) { | ||||
|             if(wires[i].asString() == selected) { | ||||
|                 buffer << wireNames[connection->bus->name + "." + connection->bus->bus.getWires()[0].getName()] << ", "; | ||||
|             } else { | ||||
|                 buffer << defaults[i].stringify(); | ||||
|             } | ||||
|         } else { | ||||
|             buffer << wires[i].stringify() << ", "; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void generateAutomaticPin(DirectConnectionInstance *connection, string name, string pin, map<string, string> wireNames, stringstream &buffer) { | ||||
|     std::vector<Value> wires; | ||||
|     if(connection->instance->name == name && connection->connection.getComponent().pin == pin) { | ||||
|         wires = connection->connection.getWires(); | ||||
|     } else { | ||||
|         wires = *connection->connection.getSecondWires(); | ||||
|     } | ||||
|     for(auto& wire: wires) { | ||||
|         if(wire.isType(Value::ATTRIBUTE_REFERENCE)) { | ||||
|             auto attribute = connection->getAttribute(wire.asReference()); | ||||
|             if(wire.isType(Value::WIRE_REFERENCE)) { | ||||
|                 buffer << wireNames[connection->bus->name + "." + attribute.value.asReference()] << ", "; | ||||
|             } else if(wire.isType(Value::NIL)) { | ||||
|                 buffer << "*, "; | ||||
|             } else { | ||||
|                 buffer << defaultWires[i].stringify() << ", "; | ||||
|                 buffer << attribute.value.stringify() << ", "; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void generateAutomaticPin(DirectConnectionInstance *connection, string name, string pin, map<string, string> wireNames, | ||||
|                          stringstream &buffer) { | ||||
|         std::vector<Value> wires; | ||||
|         if (connection->instance->name == name && connection->connection.getComponent().pin == pin) { | ||||
|             wires = connection->connection.getWires(); | ||||
|         } else { | ||||
|             wires = *connection->connection.getSecondWires(); | ||||
|         } | ||||
|         for (auto &wire: wires) { | ||||
|             if (wire.isType(Value::ATTRIBUTE_REFERENCE)) { | ||||
|                 auto attribute = connection->getAttribute(wire.asReference()); | ||||
|                 if (wire.isType(Value::WIRE_REFERENCE)) { | ||||
|                     buffer << wireNames[connection->bus->name + "." + attribute.value.asReference()] << ", "; | ||||
|                 } else if (wire.isType(Value::NIL)) { | ||||
|                     buffer << "*, "; | ||||
|                 } else { | ||||
|                     buffer << attribute.value.stringify() << ", "; | ||||
|                 } | ||||
|             if(wire.isType(Value::WIRE_REFERENCE)) { | ||||
|                 buffer << wireNames[connection->bus->name + "." + wire.asReference()] << ", "; | ||||
|             } else if(wire.isType(Value::NIL)) { | ||||
|                 buffer << "*, "; | ||||
|             } else { | ||||
|                 if (wire.isType(Value::WIRE_REFERENCE)) { | ||||
|                     buffer << wireNames[connection->bus->name + "." + wire.asReference()] << ", "; | ||||
|                 } else if (wire.isType(Value::NIL)) { | ||||
|                     buffer << "*, "; | ||||
|                 } else { | ||||
|                     buffer << wire.stringify() << ", "; | ||||
|                 } | ||||
|                 buffer << wire.stringify() << ", "; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| } // domain
 | ||||
| } // domain
 | ||||
| @ -7,9 +7,9 @@ | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
|     void generate_schema(std::string &librarySource, Schema *schema, std::ostream &buffer); | ||||
| void generateSchemaFile(std::string& librarySource, Schema *schema, std::ostream &buffer); | ||||
| 
 | ||||
|     void generate_comdel(Schema *schema, Library &library, std::ostream &buffer); | ||||
| void generateComdelFile(Schema *schema, Library &library, std::ostream &buffer); | ||||
| 
 | ||||
| } // domain
 | ||||
| 
 | ||||
|  | ||||
| @ -1,240 +0,0 @@ | ||||
| #include <set> | ||||
| #include "comdel_validator.h" | ||||
| #include "library.h" | ||||
| #include "message_source.h" | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
|     std::vector<ValidationError> ComdelValidator::validateSchema(Schema &schema, ValidationContext context) { | ||||
|         std::vector<ValidationError> errors; | ||||
| 
 | ||||
|         context.instance = nullptr; | ||||
|         context.attribute = nullptr; | ||||
| 
 | ||||
|         for (auto &instance: schema.componentInstances) { | ||||
|             auto result = validateComponent(instance.get(), context); | ||||
|             errors.insert(errors.end(), result.begin(), result.end()); | ||||
|         } | ||||
|         return errors; | ||||
|     } | ||||
| 
 | ||||
|     std::vector<ValidationError> | ||||
|     ComdelValidator::validateInstanceCount(Schema &schema, Library &library, ValidationContext context) { | ||||
|         std::vector<ValidationError> errors; | ||||
| 
 | ||||
|         // validate instance count
 | ||||
|         std::map<std::string, int> instanceMap; | ||||
|         for (auto &inst: schema.componentInstances) { | ||||
|             instanceMap[inst->component.getName()]++; | ||||
|         } | ||||
| 
 | ||||
|         for (auto comp: library.getComponents()) { | ||||
|             int count = instanceMap[comp.getName()]; | ||||
| 
 | ||||
|             context.attributes["componentName"] = Value::fromString(comp.getDisplayName()); | ||||
|             context.attributes["min"] = Value::fromInt(comp.getCount().first); | ||||
|             context.attributes["max"] = Value::fromInt(comp.getCount().second); | ||||
|             context.attributes["count"] = Value::fromInt(count); | ||||
| 
 | ||||
|             if (count < comp.getCount().first) { | ||||
|                 auto message = MESSAGE_PARAM("msg_validators_component_min_count", context.map()); | ||||
|                 errors.emplace_back(Action::ERROR, message); | ||||
|             } else if (count > comp.getCount().second) { | ||||
|                 auto message = MESSAGE_PARAM("msg_validators_component_max_count", context.map()); | ||||
|                 errors.emplace_back(Action::ERROR, message); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // validate bus instance count
 | ||||
|         std::map<std::string, int> busInstanceMap; | ||||
|         for (auto &inst: schema.busInstances) { | ||||
|             busInstanceMap[inst->bus.getName()]++; | ||||
|         } | ||||
| 
 | ||||
|         for (auto bus: library.getBuses()) { | ||||
|             int count = busInstanceMap[bus.getName()]; | ||||
| 
 | ||||
|             context.attributes["busName"] = Value::fromString(bus.getDisplayName()); | ||||
|             context.attributes["min"] = Value::fromInt(bus.getCount().first); | ||||
|             context.attributes["max"] = Value::fromInt(bus.getCount().second); | ||||
|             context.attributes["count"] = Value::fromInt(count); | ||||
| 
 | ||||
|             if (count < bus.getCount().first) { | ||||
|                 auto message = MESSAGE_PARAM("msg_validators_bus_min_count", context.map()); | ||||
|                 errors.emplace_back(Action::ERROR, message); | ||||
|             } else if (count > bus.getCount().second) { | ||||
|                 auto message = MESSAGE_PARAM("msg_validators_bus_max_count", context.map()); | ||||
|                 errors.emplace_back(Action::ERROR, message); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return errors; | ||||
|     } | ||||
| 
 | ||||
|     std::vector<ValidationError> | ||||
|     ComdelValidator::validatePinConnections(Schema &schema, Library &library, ValidationContext context) { | ||||
|         std::vector<ValidationError> errors; | ||||
| 
 | ||||
|         for (auto &inst: schema.componentInstances) { | ||||
|             for (auto &pin: inst->component.getPins()) { | ||||
|                 if (pin.getConnection().has_value()) { | ||||
|                     if (!connectionExists(schema, inst, pin)) { | ||||
|                         context.instance = inst.get(); | ||||
|                         auto message = MESSAGE_PARAM(pin.getConnection().value(), context.map()); | ||||
|                         errors.emplace_back(context.instance, nullptr, Action::ERROR, message); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return errors; | ||||
|     } | ||||
| 
 | ||||
|     std::vector<ValidationError> | ||||
|     ComdelValidator::validateComponent(ComponentInstance *instance, ValidationContext context) { | ||||
|         std::vector<ValidationError> errors; | ||||
| 
 | ||||
|         context.instance = instance; | ||||
|         context.attributes.clear(); | ||||
| 
 | ||||
|         for (auto &attribute: instance->attributes) { | ||||
|             context.attributes[attribute.name] = attribute.value; | ||||
|         } | ||||
| 
 | ||||
|         for (auto &rule: instance->component.getRules()) { | ||||
|             auto result = validateRule(rule, context); | ||||
|             if (result) { | ||||
|                 errors.push_back(*result); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         for (auto &attribute: instance->attributes) { | ||||
|             auto result = validateAttribute(&attribute, context); | ||||
|             errors.insert(errors.end(), result.begin(), result.end()); | ||||
|         } | ||||
| 
 | ||||
|         return errors; | ||||
|     } | ||||
| 
 | ||||
|     std::vector<ValidationError> | ||||
|     ComdelValidator::validateAttribute(InstanceAttribute *attribute, ValidationContext context) { | ||||
|         std::vector<ValidationError> errors; | ||||
|         if (attribute->attribute.getPopup()) { | ||||
|             Popup popup = *attribute->attribute.getPopup(); | ||||
|             context.attribute = attribute; | ||||
|             context.attributes = std::map<std::string, Value>{{attribute->name, attribute->value}}; | ||||
| 
 | ||||
|             for (auto &rule: popup.getRules()) { | ||||
|                 auto result = validateRule(rule, context); | ||||
|                 if (result) { | ||||
|                     errors.push_back(*result); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return errors; | ||||
|     } | ||||
| 
 | ||||
|     std::optional<ValidationError> ComdelValidator::validateRule(Rule rule, ValidationContext context) { | ||||
|         RuleContext ruleContext; | ||||
|         ruleContext.addressSpaces = context.addressSpaces; | ||||
|         ruleContext.attributes = context.attributes; | ||||
|         ruleContext.function = validators; | ||||
|         auto action = rule.evaluate(ruleContext); | ||||
|         if (action) { | ||||
|             auto message = MESSAGE_PARAM(action->getMessage(), context.map()); | ||||
|             return ValidationError{context.instance, context.attribute, action->getType(), message}; | ||||
|         } | ||||
|         return nullopt; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     std::vector<ValidationError> | ||||
|     ComdelValidator::validateMemoryReferences(Schema &schema, Library &library, ValidationContext context) { | ||||
|         std::set<std::string> memoryInstances; | ||||
|         for(auto& component: schema.componentInstances) { | ||||
|             if(component->component.getType() == Component::MEMORY) { | ||||
|                 memoryInstances.insert(component->name); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         std::vector<ValidationError> errors; | ||||
|         for(auto& component: schema.componentInstances) { | ||||
|             if(component->component.getType() == Component::PROCESSOR) { | ||||
|                 for(auto& attribute: component->attributes) { | ||||
|                     if(attribute.value.isType(Value::MEMORY_REFERENCE)) { | ||||
|                         auto memoryReference = attribute.value.asMemoryReference(); | ||||
|                         if(memoryReference != nullopt) { | ||||
|                             if(memoryInstances.count(*memoryReference) == 0) { | ||||
|                                 context.attributes["memoryReference"] = domain::Value::fromString(memoryReference.value()); | ||||
|                                 auto message = MESSAGE_PARAM("msg_validators_memory_not_found", context.map()); | ||||
|                                 errors.emplace_back(component.get(), nullptr, Action::ERROR, message); | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return errors; | ||||
|     } | ||||
| 
 | ||||
|     std::vector<ValidationError> | ||||
|     ComdelValidator::validateInstanceNames(Schema &schema, Library &library, ValidationContext context) { | ||||
|         std::set<std::string> names; | ||||
|         std::vector<ValidationError> errors; | ||||
| 
 | ||||
|         for(auto& component: schema.componentInstances) { | ||||
|             if(names.find(component->name) != names.end()) { | ||||
|                 context.instance = component.get(); | ||||
|                 auto message = MESSAGE_PARAM("msg_validators_duplicates_found", context.map()); | ||||
|                 errors.emplace_back(Action::ERROR, message); | ||||
|             } | ||||
|             names.insert(component->name); | ||||
|         } | ||||
|         return errors; | ||||
|     } | ||||
| 
 | ||||
|     bool ComdelValidator::connectionExists(Schema &schema, shared_ptr<ComponentInstance> &component, Pin &pin) { | ||||
|         for (auto conn: schema.connections) { | ||||
|             auto busConnection = dynamic_cast<BusConnectionInstance *>(conn.get()); | ||||
|             if (busConnection != nullptr) { | ||||
|                 if (busConnection->instance->name == component->name && | ||||
|                     busConnection->connection.getComponent().pin == pin.getName()) { | ||||
|                     return true; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             auto directConnection = dynamic_cast<DirectConnectionInstance *>(conn.get()); | ||||
|             if (directConnection != nullptr) { | ||||
|                 if ((directConnection->instance->name == component->name && directConnection->connection.getComponent().pin == pin.getName()) || | ||||
|                     (directConnection->secondInstance->name == component->name) && directConnection->connection.getSecondComponent()->pin == pin.getName()) { | ||||
|                     return directConnection->connection.isConnecting({component->component.getName(), pin.getName()}); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     ComdelValidator::ComdelValidator(std::vector<FunctionValidator *> validators) { | ||||
|         for (auto *validator: validators) { | ||||
|             validator->clear(); | ||||
|             this->validators.insert(std::make_pair(validator->getName(), validator)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     std::map<std::string, std::string> ValidationContext::map() { | ||||
|         std::map<std::string, std::string> parametars; | ||||
|         if(instance != nullptr) { | ||||
|             parametars["instanceName"] = instance->name; | ||||
|             parametars["componentName"] = instance->component.getDisplayName(); | ||||
|         } | ||||
|         if(attribute != nullptr) { | ||||
|             parametars["attributeName"] = attribute->name; | ||||
|             parametars["attribute"] = attribute->value.string(); | ||||
|         } | ||||
|         for(auto [key, value]: attributes) { | ||||
|             parametars[key] = value.string(); | ||||
|         } | ||||
|         return parametars; | ||||
|     } | ||||
| } | ||||
| @ -1,57 +0,0 @@ | ||||
| #ifndef COMDEL_VALIDATOR_H | ||||
| #define COMDEL_VALIDATOR_H | ||||
| 
 | ||||
| #include "instance.h" | ||||
| #include "schema.h" | ||||
| #include "library.h" | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
|     struct ValidationError { | ||||
|         ComponentInstance *instance; | ||||
|         InstanceAttribute *attribute; | ||||
|         Action::ActionType type; | ||||
|         std::string message; | ||||
| 
 | ||||
|         ValidationError(Action::ActionType type, std::string message): instance(nullptr), attribute(nullptr), type(type), message(message) {} | ||||
| 
 | ||||
|         ValidationError(ComponentInstance* instance, InstanceAttribute* attribute, Action::ActionType type, std::string message): instance(instance), attribute(attribute), type(type), message(message) {} | ||||
|     }; | ||||
| 
 | ||||
|     struct ValidationContext { | ||||
|         ComponentInstance *instance; | ||||
|         InstanceAttribute *attribute; | ||||
|         std::map<std::string, AddressSpace> addressSpaces; | ||||
|         std::map<std::string, Value> attributes; | ||||
| 
 | ||||
|         std::map<std::string, std::string> map(); | ||||
|     }; | ||||
| 
 | ||||
|     class ComdelValidator { | ||||
|     public: | ||||
|         std::vector<ValidationError> validateSchema(Schema &schema, ValidationContext context); | ||||
| 
 | ||||
|         std::vector<ValidationError> validateComponent(ComponentInstance *instance, ValidationContext context); | ||||
| 
 | ||||
|         std::vector<ValidationError> validateAttribute(InstanceAttribute *attribute, ValidationContext context); | ||||
| 
 | ||||
|         std::optional<ValidationError> validateRule(Rule rule, ValidationContext context); | ||||
| 
 | ||||
|         std::vector<ValidationError> validateMemoryReferences(Schema &schema, Library &library, ValidationContext context); | ||||
| 
 | ||||
|         std::vector<ValidationError> validateInstanceNames(Schema &schema, Library &library, ValidationContext context); | ||||
| 
 | ||||
|         std::vector<ValidationError> validateInstanceCount(Schema &schema, Library &library, ValidationContext context); | ||||
| 
 | ||||
|         std::vector<ValidationError> validatePinConnections(Schema &schema, Library &library, ValidationContext context); | ||||
| 
 | ||||
|         ComdelValidator(std::vector<FunctionValidator *> validators); | ||||
| 
 | ||||
|     private: | ||||
|         std::map<std::string, FunctionValidator *> validators; | ||||
| 
 | ||||
|         bool connectionExists(Schema &schema, shared_ptr<ComponentInstance> &component, Pin &pin); | ||||
|     }; | ||||
| 
 | ||||
| } | ||||
| #endif //COMDEL_VALIDATOR_H
 | ||||
							
								
								
									
										92
									
								
								comdel/domain/comdelvalidator.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								comdel/domain/comdelvalidator.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,92 @@ | ||||
| #include "comdelvalidator.h" | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
| std::vector<ValidationError> ComdelValidator::validateSchema(Schema &schema, ValidationContext context) { | ||||
|     std::vector<ValidationError> errors; | ||||
| 
 | ||||
|     context.instance = nullptr; | ||||
|     context.attribute = nullptr; | ||||
| 
 | ||||
|     for(auto &instance: schema.componentInstances) { | ||||
|         auto result = validateComponent(instance.get(), context); | ||||
|         errors.insert(errors.end(), result.begin(), result.end()); | ||||
|     } | ||||
|     return errors; | ||||
| } | ||||
| 
 | ||||
| std::vector<ValidationError> ComdelValidator::validateComponent(ComponentInstance* instance, ValidationContext context) { | ||||
|     std::vector<ValidationError> errors; | ||||
| 
 | ||||
|     context.instance = instance; | ||||
|     context.attributes.clear(); | ||||
| 
 | ||||
|     for(auto &attribute: instance->attributes) { | ||||
|         context.attributes[attribute.name] = attribute.value; | ||||
|     } | ||||
| 
 | ||||
|     for(auto &rule: instance->component.getRules()) { | ||||
|         auto result = validateRule(rule, context); | ||||
|         if(result) { | ||||
|             errors.push_back(*result); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     for(auto &attribute: instance->attributes) { | ||||
|         auto result = validateAttribute(&attribute, context); | ||||
|         errors.insert(errors.end(), result.begin(), result.end()); | ||||
|     } | ||||
| 
 | ||||
|     return errors; | ||||
| } | ||||
| 
 | ||||
| std::vector<ValidationError> ComdelValidator::validateAttribute(InstanceAttribute *attribute, ValidationContext context) { | ||||
|     std::vector<ValidationError> errors; | ||||
|     if(attribute->attribute.getPopup()) { | ||||
|         Popup popup = *attribute->attribute.getPopup(); | ||||
|         context.attribute = attribute; | ||||
|         context.attributes = std::map<std::string, Value>{{attribute->name, attribute->value}}; | ||||
| 
 | ||||
|         for(auto &rule: popup.getRules()) { | ||||
|             auto result = validateRule(rule, context); | ||||
|             if(result) { | ||||
|                 errors.push_back(*result); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     return errors; | ||||
| } | ||||
| 
 | ||||
| std::optional<ValidationError> ComdelValidator::validateRule(Rule rule, ValidationContext context) { | ||||
|     RuleContext ruleContext; | ||||
|     ruleContext.addressSpaces = context.addressSpaces; | ||||
|     ruleContext.attributes = context.attributes; | ||||
|     ruleContext.function = validators; | ||||
|     auto action = rule.evaluate(ruleContext); | ||||
|     if (action) { | ||||
|         std::string message = this->populateMessage(action->getMessage(), context); | ||||
|         return ValidationError{context.instance, context.attribute, action->getType(), message}; | ||||
|     } | ||||
|     return nullopt; | ||||
| } | ||||
| 
 | ||||
| std::string ComdelValidator::populateMessage(string source, ValidationContext context) { | ||||
|     for(auto &[key, value]: context.attributes) { | ||||
|         source = replacePlaceholder(source, key, value); | ||||
|     } | ||||
|     return source; | ||||
| } | ||||
| 
 | ||||
| string ComdelValidator::replacePlaceholder(string source, string key, Value value) { | ||||
|     key = "{" + key + "}"; | ||||
|     auto placeholderValue = value.string(); | ||||
| 
 | ||||
|     auto found = source.find(key); | ||||
|     while(found != string::npos) { | ||||
|         source.replace(found, key.length(), placeholderValue); | ||||
|         found = source.find(key); | ||||
|     } | ||||
|     return source; | ||||
| } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										48
									
								
								comdel/domain/comdelvalidator.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								comdel/domain/comdelvalidator.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,48 @@ | ||||
| #ifndef COMDEL_VALIDATOR_H | ||||
| #define COMDEL_VALIDATOR_H | ||||
| 
 | ||||
| #include "instance.h" | ||||
| #include "schema.h" | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
| struct ValidationError | ||||
| { | ||||
|     ComponentInstance *instance; | ||||
|     InstanceAttribute *attribute; | ||||
|     Action::ActionType type; | ||||
|     std::string message; | ||||
| }; | ||||
| 
 | ||||
| struct ValidationContext { | ||||
|     ComponentInstance *instance; | ||||
|     InstanceAttribute *attribute; | ||||
|     std::map<std::string, AddressSpace> addressSpaces; | ||||
|     std::map<std::string, Value> attributes; | ||||
| }; | ||||
| 
 | ||||
| class ComdelValidator | ||||
| { | ||||
| public: | ||||
|     std::vector<ValidationError> validateSchema(Schema& schema, ValidationContext context); | ||||
|     std::vector<ValidationError> validateComponent(ComponentInstance *instance, ValidationContext context); | ||||
|     std::vector<ValidationError> validateAttribute(InstanceAttribute *attribute, ValidationContext context); | ||||
|     std::optional<ValidationError> validateRule(Rule rule, ValidationContext context); | ||||
| 
 | ||||
|     ComdelValidator(std::vector<FunctionValidator*> validators) { | ||||
|         for(auto* validator: validators) { | ||||
|             validator->clear(); | ||||
|             this->validators.insert(std::make_pair(validator->getName(), validator)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     std::map<std::string, FunctionValidator*> validators; | ||||
| 
 | ||||
|     std::string populateMessage(string message, ValidationContext context); | ||||
| 
 | ||||
|     string replacePlaceholder(string message, const string name, Value value); | ||||
| }; | ||||
| 
 | ||||
| } | ||||
| #endif //COMDEL_VALIDATOR_H
 | ||||
| @ -1,105 +1,85 @@ | ||||
| #include "component.h" | ||||
| #include <stdexcept> | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
|     Component::Component(string name, optional<string> displayName, string tooltip, string source, ComponentType type, | ||||
|                          vector<Rule> rules, string instanceName, pair<int, int> count, Display display, | ||||
|                          vector<Pin> pins, vector<Attribute> attributes) | ||||
|             : name(name), displayName(displayName), tooltip(tooltip), source(source), type(type), rules(rules), instanceName(instanceName), | ||||
|               count(count), display(display), pins(pins), attributes(attributes) {} | ||||
| Component::Component(string name, string tooltip, string source, ComponentType type, | ||||
|           vector<Rule> rules, string instanceName, pair<int, int> count, Display display, | ||||
|           vector<Pin> pins, vector<Attribute> attributes) | ||||
|     : name(name), tooltip(tooltip), source(source), type(type), rules(rules), instanceName(instanceName), count(count), display(display), pins(pins), attributes(attributes) | ||||
| {} | ||||
| 
 | ||||
|     std::string Component::getName() { | ||||
|         return name; | ||||
|     } | ||||
| std::string Component::getName() { | ||||
|     return name; | ||||
| } | ||||
| std::string Component::getTooltip() { | ||||
|     return tooltip; | ||||
| } | ||||
| std::string Component::getSource() { | ||||
|     return source; | ||||
| } | ||||
| Component::ComponentType Component::getType() { | ||||
|     return type; | ||||
| } | ||||
| std::vector<Rule> Component::getRules() { | ||||
|     return rules; | ||||
| } | ||||
| std::string Component::getInstanceName() { | ||||
|     return instanceName; | ||||
| } | ||||
| std::pair<int, int> Component::getCount() { | ||||
|     return count; | ||||
| } | ||||
| Display Component::getDisplay() { | ||||
|     return display; | ||||
| } | ||||
| 
 | ||||
|     std::string Component::getDisplayName() { | ||||
|         if(displayName.has_value()) { | ||||
|             return displayName.value(); | ||||
| std::vector<Pin> Component::getPins() { | ||||
|     return pins; | ||||
| } | ||||
| Pin Component::getPin(std::string pin) { | ||||
|     for(uint i=0; i<pins.size(); i++) { | ||||
|         if(pins[i].getName() == pin) { | ||||
|             return pins[i]; | ||||
|         } | ||||
|         return name; | ||||
|     } | ||||
|     throw std::exception(); | ||||
| } | ||||
| 
 | ||||
|     std::string Component::getTooltip() { | ||||
|         return tooltip; | ||||
|     } | ||||
| 
 | ||||
|     std::string Component::getSource() { | ||||
|         return source; | ||||
|     } | ||||
| 
 | ||||
|     Component::ComponentType Component::getType() { | ||||
|         return type; | ||||
|     } | ||||
| 
 | ||||
|     std::vector<Rule> Component::getRules() { | ||||
|         return rules; | ||||
|     } | ||||
| 
 | ||||
|     std::string Component::getInstanceName() { | ||||
|         return instanceName; | ||||
|     } | ||||
| 
 | ||||
|     std::pair<int, int> Component::getCount() { | ||||
|         return count; | ||||
|     } | ||||
| 
 | ||||
|     Display Component::getDisplay() { | ||||
|         return display; | ||||
|     } | ||||
| 
 | ||||
|     std::vector<Pin> Component::getPins() { | ||||
|         return pins; | ||||
|     } | ||||
| 
 | ||||
|     Pin Component::getPin(std::string pin) { | ||||
|         for (auto & p: pins) { | ||||
|             if (p.getName() == pin) { | ||||
|                 return p; | ||||
|             } | ||||
| bool Component::hasPin(std::string name) { | ||||
|     for(auto pin: pins) { | ||||
|         if(pin.getName() == name) { | ||||
|             return true; | ||||
|         } | ||||
|         throw std::runtime_error("no pin with name '" + pin + "'"); | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
|     bool Component::hasPin(std::string name) { | ||||
|         for (auto pin: pins) { | ||||
|             if (pin.getName() == name) { | ||||
|                 return true; | ||||
|             } | ||||
| std::vector<Attribute> Component::getAttributes() { | ||||
|     return attributes; | ||||
| } | ||||
| Attribute Component::getAttribute(std::string attribute) { | ||||
|     for(uint i=0; i<attributes.size(); i++) { | ||||
|         if(attributes[i].getName() == attribute) { | ||||
|             return attributes[i]; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     std::vector<Attribute>& Component::getAttributes() { | ||||
|         return attributes; | ||||
|     } | ||||
| 
 | ||||
|     Attribute Component::getAttribute(std::string attribute) { | ||||
|         for (auto & attr : attributes) { | ||||
|             if (attr.getName() == attribute) { | ||||
|                 return attr; | ||||
|             } | ||||
|     throw std::exception(); | ||||
| } | ||||
| bool Component::hasAttribute(std::string name, Value::ValueType type) { | ||||
|     for(uint i=0; i<attributes.size(); i++) { | ||||
|         if(attributes[i].getName() == name && attributes[i].getDefault().getType() == type) { | ||||
|             return true; | ||||
|         } | ||||
|         throw std::runtime_error("no attribute with name '" + attribute + "'"); | ||||
|     } | ||||
| 
 | ||||
|     bool Component::hasAttribute(std::string name, Value::ValueType type) { | ||||
|         for (auto & attribute : attributes) { | ||||
|             if (attribute.getName() == name && attribute.getDefault().getType() == type) { | ||||
|                 return true; | ||||
|             } | ||||
|             if (attribute.getName() == name && (type == Value::NIL && | ||||
|                                                     (attribute.getDefault().getType() == Value::MEMORY_REFERENCE || | ||||
|                                                      attribute.getDefault().getType() == Value::WIRE_REFERENCE))) { | ||||
|                 return true; | ||||
|             } | ||||
|             if (attribute.getName() == name && (type == Value::UNDEFINED && | ||||
|                                                     (attribute.getDefault().getType() == Value::MEMORY_REFERENCE || | ||||
|                                                      attribute.getDefault().getType() == Value::WIRE_REFERENCE))) { | ||||
|                 return true; | ||||
|             } | ||||
|         if(attributes[i].getName() == name && (type == Value::NIL && (attributes[i].getDefault().getType() == Value::MEMORY_REFERENCE || attributes[i].getDefault().getType() == Value::WIRE_REFERENCE))) { | ||||
|             return true; | ||||
|         } | ||||
|         if(attributes[i].getName() == name && (type == Value::UNDEFINED && (attributes[i].getDefault().getType() == Value::MEMORY_REFERENCE || attributes[i].getDefault().getType() == Value::WIRE_REFERENCE))) { | ||||
|             return true; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| } // namespace domain
 | ||||
|  | ||||
| @ -11,68 +11,56 @@ | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
|     using namespace std; | ||||
| 
 | ||||
|     class Component { | ||||
|     public: | ||||
|         enum ComponentType { | ||||
|             OTHER, | ||||
|             PROCESSOR, | ||||
|             MEMORY | ||||
|         }; | ||||
| 
 | ||||
|     private: | ||||
|         std::string name; | ||||
|         std::optional<std::string> displayName; | ||||
|         std::string tooltip; | ||||
|         std::string source; | ||||
|         ComponentType type; | ||||
|         std::vector<Rule> rules; | ||||
|         std::string instanceName; | ||||
|         std::pair<int, int> count; | ||||
|         Display display; | ||||
| 
 | ||||
|         std::vector<Pin> pins; | ||||
|         std::vector<Attribute> attributes; | ||||
| 
 | ||||
|     public: | ||||
| 
 | ||||
|         Component(string name, optional<string> displayName, string tooltip, string source, ComponentType type, | ||||
|                   vector<Rule> rules, string instanceName, pair<int, int> count, Display display, | ||||
|                   vector<Pin> pins, vector<Attribute> attributes); | ||||
| 
 | ||||
|         std::string getName(); | ||||
| 
 | ||||
|         std::string getDisplayName(); | ||||
| 
 | ||||
|         std::string getTooltip(); | ||||
| 
 | ||||
|         std::string getSource(); | ||||
| 
 | ||||
|         ComponentType getType(); | ||||
| 
 | ||||
|         std::vector<Rule> getRules(); | ||||
| 
 | ||||
|         std::string getInstanceName(); | ||||
| 
 | ||||
|         std::pair<int, int> getCount(); | ||||
| 
 | ||||
|         Display getDisplay(); | ||||
| 
 | ||||
|         std::vector<Pin> getPins(); | ||||
| 
 | ||||
|         Pin getPin(std::string pin); | ||||
| 
 | ||||
|         std::vector<Attribute>& getAttributes(); | ||||
| 
 | ||||
|         Attribute getAttribute(std::string attribute); | ||||
| 
 | ||||
|         bool hasAttribute(std::string name, Value::ValueType type); | ||||
| 
 | ||||
|         bool hasPin(std::string name); | ||||
| using namespace std; | ||||
| 
 | ||||
| class Component | ||||
| { | ||||
| public: | ||||
|     enum ComponentType { | ||||
|         OTHER, | ||||
|         PROCESSOR, | ||||
|         MEMORY | ||||
|     }; | ||||
| 
 | ||||
| private: | ||||
|     std::string name; | ||||
|     std::string tooltip; | ||||
|     std::string source; | ||||
|     ComponentType type; | ||||
|     std::vector<Rule> rules; | ||||
|     std::string instanceName; | ||||
|     std::pair<int, int> count; | ||||
|     Display display; | ||||
| 
 | ||||
|     std::vector<Pin> pins; | ||||
|     std::vector<Attribute> attributes; | ||||
| 
 | ||||
| public: | ||||
| 
 | ||||
|     Component(string name, string tooltip, string source, ComponentType type, | ||||
|               vector<Rule> rules, string instanceName, pair<int, int> count, Display display, | ||||
|               vector<Pin> pins, vector<Attribute> attributes); | ||||
| 
 | ||||
|     std::string getName(); | ||||
|     std::string getTooltip(); | ||||
|     std::string getSource(); | ||||
|     ComponentType getType(); | ||||
|     std::vector<Rule> getRules(); | ||||
|     std::string getInstanceName(); | ||||
|     std::pair<int, int> getCount(); | ||||
|     Display getDisplay(); | ||||
| 
 | ||||
|     std::vector<Pin> getPins(); | ||||
|     Pin getPin(std::string pin); | ||||
| 
 | ||||
|     std::vector<Attribute> getAttributes(); | ||||
|     Attribute getAttribute(std::string attribute); | ||||
|     bool hasAttribute(std::string name, Value::ValueType type); | ||||
| 
 | ||||
|     bool hasPin(std::string name); | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| } // namespace domain
 | ||||
| 
 | ||||
| #endif // DOMAIN_COMPONENT_H
 | ||||
|  | ||||
| @ -1,80 +1,66 @@ | ||||
| #include "connection.h" | ||||
| #include <stdexcept> | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
|     Connection::Connection(ConnectionComponent first, std::optional<ConnectionComponent> second, | ||||
|                            std::string bus, std::vector<Attribute> attributes, | ||||
|                            std::vector<Value> firstWires, std::optional<std::vector<Value>> secondWires) | ||||
|             : first(first), second(second), bus(bus), attributes(attributes), firstWires(firstWires), | ||||
|               secondWires(secondWires) {} | ||||
| Connection::Connection(ConnectionComponent first, std::optional<ConnectionComponent> second, | ||||
|             std::string bus, std::vector<Attribute> attributes, | ||||
|             std::vector<Value> firstWires, std::optional<std::vector<Value>> secondWires) | ||||
|     : first(first), second(second), bus(bus), attributes(attributes), firstWires(firstWires), secondWires(secondWires) | ||||
| {} | ||||
| 
 | ||||
|     ConnectionComponent Connection::getComponent() { | ||||
|         return first; | ||||
|     } | ||||
| ConnectionComponent Connection::getComponent() { | ||||
|     return first; | ||||
| } | ||||
| std::optional<ConnectionComponent> Connection::getSecondComponent() { | ||||
|     return second; | ||||
| } | ||||
| 
 | ||||
|     std::optional<ConnectionComponent> Connection::getSecondComponent() { | ||||
|         return second; | ||||
|     } | ||||
| std::string Connection::getBus() { | ||||
|     return bus; | ||||
| } | ||||
| 
 | ||||
|     std::string &Connection::getBus() { | ||||
|         return bus; | ||||
|     } | ||||
| std::vector<Attribute> Connection::getAttributes() { | ||||
|     return attributes; | ||||
| } | ||||
| std::vector<Value> Connection::getWires() { | ||||
|     return firstWires; | ||||
| } | ||||
| std::optional<std::vector<Value>> Connection::getSecondWires() { | ||||
|     return secondWires; | ||||
| } | ||||
| 
 | ||||
|     std::vector<Attribute>& Connection::getAttributes() { | ||||
|         return attributes; | ||||
|     } | ||||
| 
 | ||||
|     std::vector<Value> Connection::getWires() { | ||||
|         return firstWires; | ||||
|     } | ||||
| 
 | ||||
|     std::optional<std::vector<Value>> Connection::getSecondWires() { | ||||
|         return secondWires; | ||||
|     } | ||||
| 
 | ||||
|     Attribute Connection::getAttribute(std::string name) { | ||||
|         for (unsigned int i = 0; i < attributes.size(); i++) { | ||||
|             if (attributes[i].getName() == name) { | ||||
|                 return attributes[i]; | ||||
|             } | ||||
| Attribute Connection::getAttribute(std::string name) { | ||||
|     for(unsigned int i=0; i<attributes.size(); i++) { | ||||
|         if(attributes[i].getName() == name) { | ||||
|             return attributes[i]; | ||||
|         } | ||||
|         throw std::runtime_error("no attribute with name '" + name + "'"); | ||||
|     } | ||||
|     throw std::exception(); | ||||
| } | ||||
| 
 | ||||
|     bool Connection::hasAttribute(std::string name) { | ||||
|         for (unsigned int i = 0; i < attributes.size(); i++) { | ||||
|             if (attributes[i].getName() == name) { | ||||
|                 return true; | ||||
|             } | ||||
| bool Connection::hasAttribute(std::string name) { | ||||
|     for(unsigned int i=0; i<attributes.size(); i++) { | ||||
|         if(attributes[i].getName() == name) { | ||||
|             return true; | ||||
|         } | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| bool Connection::isConnecting(ConnectionComponent component) { | ||||
|     return first == component || (second.has_value() && *second == component); | ||||
| } | ||||
| 
 | ||||
| bool Connection::isConnecting(ConnectionComponent component, std::string bus) { | ||||
|     return this->bus == bus && (first == component || (second.has_value() && *second == component)); | ||||
| } | ||||
| 
 | ||||
| bool Connection::isConnecting(ConnectionComponent component, std::string bus, ConnectionComponent secondComponent) { | ||||
|     if(!second.has_value()) { | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     bool Connection::isConnecting(ConnectionComponent component) { | ||||
|         return first == component || (second.has_value() && *second == component); | ||||
|     } | ||||
| 
 | ||||
|     bool Connection::isConnecting(ConnectionComponent component, std::string bus) { | ||||
|         return this->bus == bus && (first == component || (second.has_value() && *second == component)); | ||||
|     } | ||||
| 
 | ||||
|     bool Connection::isConnecting(ConnectionComponent component, std::string bus, ConnectionComponent secondComponent) { | ||||
|         if (!second.has_value()) { | ||||
|             return false; | ||||
|         } | ||||
|         return (this->first == component && this->bus == bus && this->second == secondComponent) || | ||||
|                (this->first == secondComponent && this->bus == bus && this->second == component); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     bool Connection::isConnecting(ConnectionComponent component, ConnectionComponent secondComponent) { | ||||
|         if (!second.has_value()) { | ||||
|             return false; | ||||
|         } | ||||
|         return (this->first == component && this->second == secondComponent) || | ||||
|                (this->first == secondComponent && this->second == component); | ||||
|     } | ||||
| 
 | ||||
|     return  (this->first == component && this->bus == bus && this->second == secondComponent) || | ||||
|             (this->first == secondComponent && this->bus == bus && this->second == component); | ||||
| } | ||||
| 
 | ||||
| } // namespace domain
 | ||||
|  | ||||
| @ -8,71 +8,53 @@ | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
|     struct ConnectionComponent { | ||||
|         std::string component; | ||||
|         std::string pin; | ||||
| struct ConnectionComponent | ||||
| { | ||||
|     std::string component; | ||||
|     std::string pin; | ||||
| 
 | ||||
|         bool operator==(const ConnectionComponent &rhs) const { | ||||
|             return (component == rhs.component) && (pin == rhs.pin); | ||||
|         } | ||||
|     bool operator==(const ConnectionComponent& rhs) const | ||||
|     { | ||||
|         return (component == rhs.component) && (pin == rhs.pin); | ||||
|     } | ||||
|     bool operator!=(const ConnectionComponent& rhs) const | ||||
|     { | ||||
|         return !operator==(rhs); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
|         bool operator!=(const ConnectionComponent &rhs) const { | ||||
|             return !operator==(rhs); | ||||
|         } | ||||
| class Connection | ||||
| { | ||||
|     ConnectionComponent first; | ||||
|     std::optional<ConnectionComponent> second; | ||||
|     std::string bus; | ||||
|     std::vector<Attribute> attributes; | ||||
| 
 | ||||
|         bool operator<(const ConnectionComponent &rhs) const { | ||||
|             if (component < rhs.component) { | ||||
|                 return true; | ||||
|             } else if (component == rhs.component) { | ||||
|                 if (pin < rhs.pin) { | ||||
|                     return true; | ||||
|                 } | ||||
|             } | ||||
|             return false; | ||||
|         } | ||||
|     }; | ||||
|     std::vector<Value> firstWires; | ||||
|     std::optional<std::vector<Value>> secondWires; | ||||
| public: | ||||
|     Connection(ConnectionComponent first, std::optional<ConnectionComponent> second, | ||||
|                std::string bus, std::vector<Attribute> attributes, | ||||
|                std::vector<Value> firstWires, std::optional<std::vector<Value>> secondWires); | ||||
| 
 | ||||
|     class Connection { | ||||
|         ConnectionComponent first; | ||||
|         std::optional<ConnectionComponent> second; | ||||
|         std::string bus; | ||||
|         std::vector<Attribute> attributes; | ||||
|     bool isConnecting(ConnectionComponent first); | ||||
|     bool isConnecting(ConnectionComponent first, std::string bus); | ||||
|     bool isConnecting(ConnectionComponent first, std::string bus, ConnectionComponent second); | ||||
| 
 | ||||
|         std::vector<Value> firstWires; | ||||
|         std::optional<std::vector<Value>> secondWires; | ||||
|     public: | ||||
|         Connection(ConnectionComponent first, std::optional<ConnectionComponent> second, | ||||
|                    std::string bus, std::vector<Attribute> attributes, | ||||
|                    std::vector<Value> firstWires, std::optional<std::vector<Value>> secondWires); | ||||
| 
 | ||||
|         bool isConnecting(ConnectionComponent first); | ||||
|     ConnectionComponent getComponent(); | ||||
|     std::optional<ConnectionComponent> getSecondComponent(); | ||||
| 
 | ||||
|         bool isConnecting(ConnectionComponent first, std::string bus); | ||||
|     std::string getBus(); | ||||
| 
 | ||||
|         bool isConnecting(ConnectionComponent first, std::string bus, ConnectionComponent second); | ||||
|     std::vector<Attribute> getAttributes(); | ||||
| 
 | ||||
|         bool isConnecting(ConnectionComponent first, ConnectionComponent second); | ||||
|     std::vector<Value> getWires(); | ||||
|     std::optional<std::vector<Value>> getSecondWires(); | ||||
| 
 | ||||
|         bool operator==(const Connection& connection) { | ||||
|             return (first == connection.first && bus == connection.bus && second == connection.second); | ||||
|         } | ||||
| 
 | ||||
|         ConnectionComponent getComponent(); | ||||
| 
 | ||||
|         std::optional<ConnectionComponent> getSecondComponent(); | ||||
| 
 | ||||
|         std::string &getBus(); | ||||
| 
 | ||||
|         std::vector<Attribute>& getAttributes(); | ||||
| 
 | ||||
|         std::vector<Value> getWires(); | ||||
| 
 | ||||
|         std::optional<std::vector<Value>> getSecondWires(); | ||||
| 
 | ||||
|         Attribute getAttribute(std::string name); | ||||
| 
 | ||||
|         bool hasAttribute(std::string name); | ||||
|     }; | ||||
|     Attribute getAttribute(std::string name); | ||||
|     bool hasAttribute(std::string name); | ||||
| }; | ||||
| 
 | ||||
| } // namespace domain
 | ||||
| 
 | ||||
|  | ||||
| @ -1,49 +0,0 @@ | ||||
| #include "connection_instance.h" | ||||
| #include <stdexcept> | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
| 
 | ||||
|     ConnectionInstance::ConnectionInstance(ComponentInstance *instance, std::vector<InstanceAttribute> attributes, | ||||
|                                            Connection connection) | ||||
|             : instance(instance), attributes(attributes), connection(connection) {} | ||||
| 
 | ||||
|     InstanceAttribute ConnectionInstance::getAttribute(string attribute) { | ||||
|         for (auto &attr: attributes) { | ||||
|             if (attr.name == attribute) { | ||||
|                 return attr; | ||||
|             } | ||||
|         } | ||||
|         throw std::runtime_error("no attribute with name '" + attribute + "'"); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     BusConnectionInstance::BusConnectionInstance(ComponentInstance *instance, std::vector<InstanceAttribute> attributes, | ||||
|                                                  BusInstance *bus, Connection connection) | ||||
|             : ConnectionInstance(instance, attributes, connection), bus(bus) {} | ||||
| 
 | ||||
|     DirectConnectionInstance::DirectConnectionInstance(ComponentInstance *instance, ComponentInstance *secondInstance, | ||||
|                                                        std::vector<InstanceAttribute> attributes, BusInstance *bus, | ||||
|                                                        Connection connection) | ||||
|             : ConnectionInstance(instance, attributes, connection), secondInstance(secondInstance), bus(bus) {} | ||||
| 
 | ||||
|     int DirectConnectionInstance::getSelected(ConnectionComponent conn) { | ||||
|         if(this->instance->name == conn.component) { | ||||
|             auto selected = attributes[0].value.asString(); | ||||
|             for(int i=0; i<connection.getWires().size(); i++) { | ||||
|                 if(connection.getWires()[i].isType(Value::STRING) && connection.getWires()[i].asString() == selected) { | ||||
|                     return i; | ||||
|                 } | ||||
|             } | ||||
|         } else { | ||||
|             auto selected = attributes[1].value.asString(); | ||||
|             for(int i=0; i<connection.getSecondWires()->size(); i++) { | ||||
|                 if(connection.getSecondWires().value()[i].isType(Value::STRING) && connection.getSecondWires().value()[i].asString() == selected) { | ||||
|                     return i; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
| } // namespace domain
 | ||||
| @ -1,51 +0,0 @@ | ||||
| #ifndef DOMAIN_CONNECTION_INSTANCE_H | ||||
| #define DOMAIN_CONNECTION_INSTANCE_H | ||||
| 
 | ||||
| #include "connection.h" | ||||
| #include "instance.h" | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
|     class ConnectionInstance { | ||||
|     public: | ||||
|         ComponentInstance *instance; | ||||
|         Connection connection; | ||||
| 
 | ||||
|         virtual ~ConnectionInstance() = default; | ||||
| 
 | ||||
|         std::vector<InstanceAttribute> attributes; | ||||
| 
 | ||||
|         std::pair<int, int> start; | ||||
|         std::pair<int, int> end; | ||||
| 
 | ||||
|         ConnectionInstance(ComponentInstance *instance, std::vector<InstanceAttribute> attributes, | ||||
|                            Connection connection); | ||||
| 
 | ||||
|         InstanceAttribute getAttribute(string attribute); | ||||
|     }; | ||||
| 
 | ||||
| 
 | ||||
|     class BusConnectionInstance : public ConnectionInstance { | ||||
|     public: | ||||
|         BusInstance *bus; | ||||
| 
 | ||||
|         BusConnectionInstance(ComponentInstance *instance, std::vector<InstanceAttribute> attributes, BusInstance *bus, | ||||
|                               Connection connection); | ||||
|     }; | ||||
| 
 | ||||
| 
 | ||||
|     class DirectConnectionInstance : public ConnectionInstance { | ||||
|     public: | ||||
|         BusInstance *bus; | ||||
|         ComponentInstance *secondInstance; | ||||
| 
 | ||||
|         DirectConnectionInstance(ComponentInstance *instance, ComponentInstance *secondsInstance, | ||||
|                                  std::vector<InstanceAttribute> attributes, BusInstance *bus, Connection connection); | ||||
| 
 | ||||
|         int getSelected(ConnectionComponent connection); | ||||
|     }; | ||||
| 
 | ||||
| 
 | ||||
| } // namespace domain
 | ||||
| 
 | ||||
| #endif // DOMAIN_CONNECTIONINSTANCE_H
 | ||||
							
								
								
									
										28
									
								
								comdel/domain/connectioninstance.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								comdel/domain/connectioninstance.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | ||||
| #include "connectioninstance.h" | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
| 
 | ||||
| ConnectionInstance::ConnectionInstance(ComponentInstance *instance, std::vector<InstanceAttribute> attributes, Connection connection) | ||||
|     : instance(instance), attributes(attributes), connection(connection) | ||||
| {} | ||||
| 
 | ||||
| InstanceAttribute ConnectionInstance::getAttribute(string attribute) { | ||||
|     for(auto& attr: attributes) { | ||||
|         if(attr.name == attribute) { | ||||
|             return attr; | ||||
|         } | ||||
|     } | ||||
|     throw std::exception(); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| BusConnectionInstance::BusConnectionInstance(ComponentInstance *instance, std::vector<InstanceAttribute> attributes, BusInstance *bus, Connection connection) | ||||
|     : ConnectionInstance(instance, attributes, connection), bus(bus) | ||||
| {} | ||||
| 
 | ||||
| DirectConnectionInstance::DirectConnectionInstance(ComponentInstance *instance, ComponentInstance *secondInstance, std::vector<InstanceAttribute> attributes, BusInstance *bus, Connection connection) | ||||
|     : ConnectionInstance(instance, attributes, connection), secondInstance(secondInstance), bus(bus) | ||||
| {} | ||||
| 
 | ||||
| } // namespace domain
 | ||||
							
								
								
									
										49
									
								
								comdel/domain/connectioninstance.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								comdel/domain/connectioninstance.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,49 @@ | ||||
| #ifndef DOMAIN_CONNECTION_INSTANCE_H | ||||
| #define DOMAIN_CONNECTION_INSTANCE_H | ||||
| 
 | ||||
| #include "connection.h" | ||||
| #include "instance.h" | ||||
| #include "wireinstance.h" | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
| class ConnectionInstance | ||||
| { | ||||
| public: | ||||
|     ComponentInstance *instance; | ||||
|     Connection connection; | ||||
| 
 | ||||
|     virtual ~ConnectionInstance() = default; | ||||
| 
 | ||||
|     std::vector<InstanceAttribute> attributes; | ||||
| 
 | ||||
|     ConnectionInstance(ComponentInstance *instance, std::vector<InstanceAttribute> attributes, Connection connection); | ||||
| 
 | ||||
|     InstanceAttribute getAttribute(string attribute); | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| class BusConnectionInstance: public ConnectionInstance | ||||
| { | ||||
| public: | ||||
|     BusInstance *bus; | ||||
| 
 | ||||
|     BusConnectionInstance(ComponentInstance *instance, std::vector<InstanceAttribute> attributes, BusInstance *bus, Connection connection); | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| class DirectConnectionInstance: public ConnectionInstance | ||||
| { | ||||
| public: | ||||
|     BusInstance *bus; | ||||
|     ComponentInstance *secondInstance; | ||||
| 
 | ||||
|     DirectConnectionInstance(ComponentInstance *instance, ComponentInstance *secondsInstance, std::vector<InstanceAttribute> attributes, BusInstance *bus, Connection connection); | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| } // namespace domain
 | ||||
| 
 | ||||
| #endif // DOMAIN_CONNECTIONINSTANCE_H
 | ||||
| @ -1,265 +1,7 @@ | ||||
| #include "display.h" | ||||
| 
 | ||||
| #include <QBrush> | ||||
| #include <QPen> | ||||
| #include <QFont> | ||||
| 
 | ||||
| #include "comdel/domain/instance.h" | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
|     Display::Display(std::vector<ui::Item> items) : items(items) {} | ||||
| Display::Display(std::vector<ui::Item> items): items(items) {} | ||||
| 
 | ||||
|     void Display::render(QGraphicsItemGroup *group, ui::DisplayContext context) { | ||||
|         for (auto &item: items) { | ||||
|             item.render(group, context); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void Display::comdel(std::ostream &buffer, int x, int y, int size) { | ||||
|         for (auto &item: items) { | ||||
|             item.comdel(buffer, x, y, size); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void ui::Text::render(QGraphicsItemGroup *group, ui::DisplayContext context) { | ||||
|         auto formattedText = context.populateMessage(text); | ||||
| 
 | ||||
|         auto content = new QGraphicsTextItem(QString::fromStdString(formattedText)); | ||||
|         content->setDefaultTextColor(color); | ||||
|         content->setPos(x, y); | ||||
|         content->setFont(QFont("arial", 8)); | ||||
|         group->addToGroup(content); | ||||
|     } | ||||
| 
 | ||||
|     void ui::Text::comdel(std::ostream &buffer, int x, int y) { | ||||
|         // TODO
 | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     void ui::Rect::render(QGraphicsItemGroup *group) { | ||||
|         auto rect = new QGraphicsRectItem(x, y, w, h); | ||||
|         rect->setPen(QPen(config.lineColor)); | ||||
|         rect->setBrush(QBrush(config.fillColor)); | ||||
|         group->addToGroup(rect); | ||||
|     } | ||||
| 
 | ||||
|     void ui::Rect::comdel(std::ostream &buffer, int x, int y) { | ||||
|         buffer << "\t\trectangle {\n"; | ||||
|         buffer << "\t\t\tx: " << (this->x + x) << "; y: " << (this->y + y) << ";\n"; | ||||
|         buffer << "\t\t\twidth: " << w << "; height: " << h << ";\n"; | ||||
|         buffer << "\t\t\tfill_color: " << this->config.fillColor.name().toStdString() << ";\n"; | ||||
|         buffer << "\t\t\tline_color: " << this->config.lineColor.name().toStdString() << ";\n"; | ||||
|         buffer << "\t\t}\n\n"; | ||||
|     } | ||||
| 
 | ||||
|     void ui::Ellipse::render(QGraphicsItemGroup *group) { | ||||
|         auto ellipse = new QGraphicsEllipseItem(x, y, w, h); | ||||
|         ellipse->setPen(QPen(config.lineColor)); | ||||
|         ellipse->setBrush(QBrush(config.fillColor)); | ||||
|         group->addToGroup(ellipse); | ||||
|     } | ||||
| 
 | ||||
|     void ui::Ellipse::comdel(std::ostream &buffer, int x, int y) { | ||||
|         buffer << "\t\tellipse {\n"; | ||||
|         buffer << "\t\t\tx: " << (this->x + x) << "; y: " << (this->y + y) << ";\n"; | ||||
|         buffer << "\t\t\twidth: " << w << "; height: " << h << ";\n"; | ||||
|         buffer << "\t\t}\n\n"; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     void ui::Line::render(QGraphicsItemGroup *group) { | ||||
|         auto line = new QGraphicsLineItem(x1, y1, x2, y2); | ||||
|         line->setPen(QPen(config.lineColor)); | ||||
|         group->addToGroup(line); | ||||
|     } | ||||
| 
 | ||||
|     void ui::Line::comdel(std::ostream &buffer, int x, int y) { | ||||
|         buffer << "\t\tpath {\n"; | ||||
|         buffer << "\t\t\tx:0; y:0;\n"; | ||||
|         buffer << "\t\t\tpoints: ("; | ||||
|         buffer << "(" << (x1 + x) << ", " << (y1 + y) << "),"; | ||||
|         buffer << "(" << (x2 - x1) << "," << (y2 - y1) << "));\n"; | ||||
|         buffer << "\t\t}" << std::endl; | ||||
|     } | ||||
| 
 | ||||
|     void ui::Bus::render(QGraphicsItemGroup *group, int size) { | ||||
|         int _w = w, _h = h; | ||||
|         if (orientation == HORIZONTAL) { | ||||
|             _w = size; | ||||
|         } else { | ||||
|             _h = size; | ||||
|         } | ||||
|         auto rect = new QGraphicsRectItem(x, y, _w, _h); | ||||
|         rect->setBrush(QBrush(config.fillColor)); | ||||
|         rect->setPen(QPen(config.lineColor)); | ||||
|         group->addToGroup(rect); | ||||
|     } | ||||
| 
 | ||||
|     int ui::Bus::getDefaultSize() { | ||||
|         if (orientation == HORIZONTAL) { | ||||
|             return w; | ||||
|         } else { | ||||
|             return h; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void ui::Bus::comdel(std::ostream &buffer, int x, int y, int size) { | ||||
|         buffer << "\t\trectangle {\n"; | ||||
|         buffer << "\t\t\tx: " << (this->x + x) << "; y: " << (this->y + y) << ";\n"; | ||||
|         if (orientation == HORIZONTAL) { | ||||
|             buffer << "\t\t\twidth: " << size << "; height: " << h << ";\n"; | ||||
|         } else { | ||||
|             buffer << "\t\t\twidth: " << w << "; height: " << size << ";\n"; | ||||
|         } | ||||
|         buffer << "\t\t\tfill_color: " << this->config.fillColor.name().toStdString() << ";\n"; | ||||
|         buffer << "\t\t\tline_color: " << this->config.lineColor.name().toStdString() << ";\n"; | ||||
|         buffer << "\t\t}\n\n"; | ||||
|     } | ||||
| 
 | ||||
|     void ui::Pin::renderIn(QGraphicsItemGroup *group) { | ||||
|         QPolygon polygon; | ||||
| 
 | ||||
|         switch (orientation) { | ||||
|             case PinOrientation::TOP: | ||||
|                 polygon << QPoint(x, y) << QPoint(x, y + h) << QPoint(x + w, y + h) << QPoint(x + w, y) | ||||
|                         << QPoint(x + w / 2, y + h / 2); | ||||
|                 break; | ||||
|             case PinOrientation::BOTTOM: | ||||
|                 polygon << QPoint(x, y) << QPoint(x, y + h) << QPoint(x + w / 2, y + h / 2) | ||||
|                         << QPoint(x + w, y + h) << QPoint(x + w, y); | ||||
|                 break; | ||||
|             case PinOrientation::LEFT: | ||||
|                 polygon << QPoint(x, y) << QPoint(x + w / 2, y + h / 2) << QPoint(x, y + h) | ||||
|                         << QPoint(x + w, y + h) << QPoint(x + w, y); | ||||
|                 break; | ||||
|             case PinOrientation::RIGHT: | ||||
|                 polygon << QPoint(x, y) << QPoint(x, y + h) << QPoint(x + w, y + h) | ||||
|                         << QPoint(x + w / 2, y + h / 2) << QPoint(x + w, y); | ||||
|                 break; | ||||
|         } | ||||
|         auto item = new QGraphicsPolygonItem(polygon); | ||||
|         item->setFillRule(Qt::OddEvenFill); | ||||
|         item->setBrush(QBrush(config.fillColor)); | ||||
|         item->setPen(QPen(config.lineColor)); | ||||
|         group->addToGroup(item); | ||||
|     } | ||||
| 
 | ||||
|     void ui::Pin::renderOut(QGraphicsItemGroup *group) { | ||||
|         QPolygon polygon; | ||||
| 
 | ||||
|         switch (orientation) { | ||||
|             case PinOrientation::TOP: | ||||
|                 polygon << QPoint(x, y + h / 2) << QPoint(x, y + h) << QPoint(x + w, y + h) | ||||
|                         << QPoint(x + w, y + h / 2) << QPoint(x + w / 2, y); | ||||
|                 break; | ||||
|             case PinOrientation::BOTTOM: | ||||
|                 polygon << QPoint(x, y) << QPoint(x, y + h / 2) << QPoint(x + w / 2, y + h) | ||||
|                         << QPoint(x + w, y + h / 2) << QPoint(x + w, y); | ||||
|                 break; | ||||
|             case PinOrientation::LEFT: | ||||
|                 polygon << QPoint(x + w, y) << QPoint(x + w / 2, y) << QPoint(x, y + h / 2) | ||||
|                         << QPoint(x + w / 2, y + h) << QPoint(x + w, y + w); | ||||
|                 break; | ||||
|             case PinOrientation::RIGHT: | ||||
|                 polygon << QPoint(x, y) << QPoint(x, y + h) << QPoint(x + w / 2, y + h) | ||||
|                         << QPoint(x + w, y + h / 2) << QPoint(x + w / 2, y); | ||||
|                 break; | ||||
|         } | ||||
|         auto item = new QGraphicsPolygonItem(polygon); | ||||
|         item->setFillRule(Qt::OddEvenFill); | ||||
|         item->setBrush(QBrush(config.fillColor)); | ||||
|         item->setPen(QPen(config.lineColor)); | ||||
|         group->addToGroup(item); | ||||
|     } | ||||
| 
 | ||||
|     void ui::Pin::renderInOut(QGraphicsItemGroup *group) { | ||||
|         auto rect = new QGraphicsRectItem(x, y, w, h); | ||||
|         rect->setBrush(QBrush(config.fillColor)); | ||||
|         rect->setPen(QPen(config.lineColor)); | ||||
|         group->addToGroup(rect); | ||||
|     } | ||||
| 
 | ||||
|     void ui::Pin::render(QGraphicsItemGroup *group) { | ||||
|         switch (pinType) { | ||||
|             case PinType::IN: | ||||
|                 renderIn(group); | ||||
|                 break; | ||||
|             case PinType::OUT: | ||||
|                 renderOut(group); | ||||
|                 break; | ||||
|             case PinType::IN_OUT: | ||||
|                 renderInOut(group); | ||||
|                 break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     int ui::Pin::getConnectionX() { | ||||
|         switch (orientation) { | ||||
|             case ui::PinOrientation::TOP: | ||||
|             case ui::PinOrientation::BOTTOM: | ||||
|                 return x + w / 2; | ||||
|             case ui::PinOrientation::LEFT: | ||||
|                 return x; | ||||
|             case ui::PinOrientation::RIGHT: | ||||
|                 return x + w; | ||||
|         } | ||||
|         return 0; | ||||
|     } | ||||
| 
 | ||||
|     int ui::Pin::getConnectionY() { | ||||
|         switch (orientation) { | ||||
|             case ui::PinOrientation::LEFT: | ||||
|             case ui::PinOrientation::RIGHT: | ||||
|                 return y + h / 2; | ||||
|             case ui::PinOrientation::TOP: | ||||
|                 return y; | ||||
|             case ui::PinOrientation::BOTTOM: | ||||
|                 return y + h; | ||||
|         } | ||||
|         return 0; | ||||
|     } | ||||
| 
 | ||||
|     void ui::Item::render(QGraphicsItemGroup *group, ui::DisplayContext context, int size) { | ||||
|         if (rect) rect->render(group); | ||||
|         if (line) line->render(group); | ||||
|         if (pin) pin->render(group); | ||||
|         if (bus) bus->render(group, size); | ||||
|         if (text) text->render(group, context); | ||||
|         if (ellipse) ellipse->render(group); | ||||
|     } | ||||
| 
 | ||||
|     void ui::Item::comdel(std::ostream &buffer, int x, int y, int size) { | ||||
|         if (rect) rect->comdel(buffer, x, y); | ||||
|         if (line) line->comdel(buffer, x, y); | ||||
|         // pins aren't exported
 | ||||
|         if (bus) bus->comdel(buffer, x, y, size); | ||||
|         // text currently isn't exported TODO
 | ||||
|     } | ||||
| 
 | ||||
|     ui::DisplayContext::DisplayContext(ComponentInstance *instance) { | ||||
|         for(auto attr: instance->attributes) { | ||||
|             this->values[attr.name] = attr.value; | ||||
|         } | ||||
|         this->values["instanceName"] = Value::fromString(instance->name); | ||||
|     } | ||||
| 
 | ||||
|     string replacePlaceholder(string source, string key, Value value) { | ||||
|         key = "{" + key + "}"; | ||||
|         auto placeholderValue = value.string(); | ||||
| 
 | ||||
|         auto found = source.find(key); | ||||
|         while (found != string::npos) { | ||||
|             source.replace(found, key.length(), placeholderValue); | ||||
|             found = source.find(key); | ||||
|         } | ||||
|         return source; | ||||
|     } | ||||
| 
 | ||||
|     std::string ui::DisplayContext::populateMessage(std::string source) { | ||||
|         for (auto &[key, value]: values) { | ||||
|             source = replacePlaceholder(source, key, value); | ||||
|         } | ||||
|         return source; | ||||
|     } | ||||
| } // namespace domain
 | ||||
|  | ||||
| @ -5,168 +5,113 @@ | ||||
| #include <optional> | ||||
| 
 | ||||
| #include <ostream> | ||||
| #include "comdel/parser/color.h" | ||||
| #include "value.h" | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
|     namespace ui { | ||||
| namespace ui { | ||||
| 
 | ||||
|         class DisplayContext { | ||||
|             std::map<std::string, domain::Value> values; | ||||
| class Rect { | ||||
| public: | ||||
|     int x, y, w, h; | ||||
| 
 | ||||
|         public: | ||||
|             explicit DisplayContext(ComponentInstance *instance); | ||||
|             std::string populateMessage(std::string message); | ||||
|         }; | ||||
| 
 | ||||
|         struct DisplayConfig { | ||||
|             QColor lineColor; | ||||
|             QColor fillColor; | ||||
| 
 | ||||
|             DisplayConfig(Color lineColor, Color fillColor) { | ||||
|                 this->lineColor = QColor::fromRgb(lineColor.r, lineColor.g, lineColor.b, lineColor.a); | ||||
|                 this->fillColor = QColor::fromRgb(fillColor.r, fillColor.g, fillColor.b, fillColor.a); | ||||
|             } | ||||
|         }; | ||||
| 
 | ||||
|         class Text { | ||||
|         public: | ||||
|             int x, y, w, h; | ||||
|             QColor color; | ||||
|             std::string text; | ||||
| 
 | ||||
|             Text(int x, int y, int w, int h, std::string text, Color color) : x(x), y(y), w(w), h(h), text(text), | ||||
|                 color(QColor::fromRgb(color.r, color.g, color.b, color.a)) {} | ||||
| 
 | ||||
|             void render(QGraphicsItemGroup *group, ui::DisplayContext context); | ||||
| 
 | ||||
|             void comdel(std::ostream &buffer, int x, int y); | ||||
| 
 | ||||
|         }; | ||||
| 
 | ||||
|         class Rect { | ||||
|         public: | ||||
|             int x, y, w, h; | ||||
|             DisplayConfig config; | ||||
| 
 | ||||
|             Rect(int x, int y, int w, int h, DisplayConfig config) : x(x), y(y), w(w), h(h), config(config) {} | ||||
| 
 | ||||
|             void render(QGraphicsItemGroup *group); | ||||
| 
 | ||||
|             void comdel(std::ostream &buffer, int x, int y); | ||||
| 
 | ||||
|         }; | ||||
| 
 | ||||
|         class Ellipse { | ||||
|         public: | ||||
|             int x, y, w, h; | ||||
|             DisplayConfig config; | ||||
| 
 | ||||
|             Ellipse(int x, int y, int w, int h, DisplayConfig config) : x(x), y(y), w(w), h(h), config(config) {} | ||||
| 
 | ||||
|             void render(QGraphicsItemGroup *group); | ||||
| 
 | ||||
|             void comdel(std::ostream &buffer, int x, int y); | ||||
| 
 | ||||
|         }; | ||||
| 
 | ||||
|         class Line { | ||||
|         public: | ||||
|             int x1, y1, x2, y2; | ||||
|             DisplayConfig config; | ||||
| 
 | ||||
|             Line(int x1, int y1, int x2, int y2, DisplayConfig config) : x1(x1), y1(y1), x2(x2), y2(y2), config(config) {} | ||||
| 
 | ||||
|             void render(QGraphicsItemGroup *group); | ||||
| 
 | ||||
|             void comdel(std::ostream &buffer, int x, int y); | ||||
|         }; | ||||
| 
 | ||||
|         enum PinType { | ||||
|             IN, OUT, IN_OUT | ||||
|         }; | ||||
|         enum PinOrientation { | ||||
|             LEFT, RIGHT, TOP, BOTTOM | ||||
|         }; | ||||
|         enum BusOrientation { | ||||
|             VERTICAL, HORIZONTAL | ||||
|         }; | ||||
| 
 | ||||
|         class Bus { | ||||
|         public: | ||||
|             int x, y, w, h; | ||||
|             BusOrientation orientation; | ||||
|             DisplayConfig config; | ||||
| 
 | ||||
|             Bus(int x, int y, int w, int h, BusOrientation orientation, DisplayConfig config) : x(x), y(y), w(w), h(h), | ||||
|                                                                           orientation(orientation), | ||||
|                                                                           config(config) {} | ||||
| 
 | ||||
|             void render(QGraphicsItemGroup *group, int size); | ||||
| 
 | ||||
|             int getDefaultSize(); | ||||
| 
 | ||||
|             void comdel(std::ostream &buffer, int x, int y, int size); | ||||
| 
 | ||||
|         }; | ||||
| 
 | ||||
|         class Pin { | ||||
|         public: | ||||
|             PinOrientation orientation; | ||||
|             PinType pinType; | ||||
|             int x, y, w, h; | ||||
|             DisplayConfig config; | ||||
| 
 | ||||
|             Pin(int x, int y, int w, int h, PinOrientation orientation, PinType pinType, DisplayConfig config) | ||||
|                 : x(x), y(y), w(w), h(h), orientation(orientation), pinType(pinType), config(config) {} | ||||
| 
 | ||||
|             Pin(): config(DisplayConfig(Color(), Color())) {}; | ||||
| 
 | ||||
|         public: | ||||
|             void render(QGraphicsItemGroup *group); | ||||
| 
 | ||||
|             int getConnectionX(); | ||||
|             int getConnectionY(); | ||||
| 
 | ||||
|         private: | ||||
|             void renderIn(QGraphicsItemGroup *group); | ||||
|             void renderOut(QGraphicsItemGroup *group); | ||||
|             void renderInOut(QGraphicsItemGroup *group); | ||||
|         }; | ||||
| 
 | ||||
| 
 | ||||
|         class Item { | ||||
|         public: | ||||
|             Item() : rect(std::nullopt), line(std::nullopt), pin(std::nullopt), bus(std::nullopt) {} | ||||
| 
 | ||||
|             std::optional<Rect> rect = std::nullopt; | ||||
|             std::optional<Line> line = std::nullopt; | ||||
|             std::optional<Pin> pin = std::nullopt; | ||||
|             std::optional<Bus> bus = std::nullopt; | ||||
|             std::optional<Text> text = std::nullopt; | ||||
|             std::optional<Ellipse> ellipse = std::nullopt; | ||||
| 
 | ||||
|             void render(QGraphicsItemGroup *group, ui::DisplayContext context, int size = 0); | ||||
|             void comdel(std::ostream &buffer, int x, int y, int size = 0); | ||||
|         }; | ||||
|     Rect(int x, int y, int w, int h): x(x), y(y), w(w), h(h) {} | ||||
| 
 | ||||
|     void render(QGraphicsItemGroup *group) { | ||||
|         group->addToGroup(new QGraphicsRectItem(x,y,w,h)); | ||||
|     } | ||||
| 
 | ||||
|     class Display { | ||||
|     public: | ||||
|     void comdel(std::ostream &buffer, int x, int y, int size) { | ||||
|         buffer << "\t\trectangle {\n"; | ||||
|         buffer << "\t\t\tx: " << (this->x + x) << "; y: " << (this->y + y) << ";\n"; | ||||
|         buffer << "\t\t\tw: " << w << "; h: " << h << ";\n"; | ||||
|         buffer << "\t\t}\n\n"; | ||||
|     } | ||||
| 
 | ||||
|         Display(std::vector<ui::Item> items); | ||||
| }; | ||||
| 
 | ||||
|         void render(QGraphicsItemGroup *group, ui::DisplayContext context); | ||||
| class Line { | ||||
| public: | ||||
|     int x1, y1, x2, y2; | ||||
| 
 | ||||
|         void comdel(std::ostream &buffer, int x, int y, int size = 0); | ||||
|     Line(int x1, int y1, int x2, int y2): x1(x1), y1(y1), x2(x2), y2(y2) {} | ||||
| 
 | ||||
|         std::vector<ui::Item> &getItems() { return items; } | ||||
|     void render(QGraphicsItemGroup *group) { | ||||
|         group->addToGroup(new QGraphicsLineItem(x1, y1, x2, y2)); | ||||
|     } | ||||
| 
 | ||||
|     private: | ||||
|         std::vector<ui::Item> items; | ||||
|     }; | ||||
|     void comdel(std::ostream &buffer, int x, int y, int size) { | ||||
|         buffer << "\t\tline {\n"; | ||||
|         buffer << "\t\t\tx1: " << (x1 + x) << "; y1: " << (y1 + y) << ";\n"; | ||||
|         buffer << "\t\t\tx2: " << (x2 + x) << "; y2: " << (y2 + y) << ";\n"; | ||||
|         buffer << "\t\t}\n\n"; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| enum Orientation { | ||||
|     LEFT, RIGHT, TOP, BOTTOM | ||||
| }; | ||||
| 
 | ||||
| enum PinType { | ||||
|     IN, OUT, IN_OUT | ||||
| }; | ||||
| 
 | ||||
| class Pin { | ||||
| public: | ||||
|     Orientation orientation; | ||||
|     PinType pinType; | ||||
|     int x, y, w, h; | ||||
| 
 | ||||
|     Pin(int x, int y, int w, int h): x(x), y(y), w(w), h(h) {} | ||||
| 
 | ||||
|     void render(QGraphicsItemGroup *group) { | ||||
|         group->addToGroup(new QGraphicsRectItem(x,y,w,h)); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| class Item { | ||||
| public: | ||||
|     Item(): rect(std::nullopt), line(std::nullopt), pin(std::nullopt) {} | ||||
| 
 | ||||
|     void render(QGraphicsItemGroup *group) { | ||||
|         if(rect) rect->render(group); | ||||
|         if(line) line->render(group); | ||||
|         if(pin) pin->render(group); | ||||
|     } | ||||
| 
 | ||||
|     std::optional<Rect> rect = std::nullopt; | ||||
|     std::optional<Line> line = std::nullopt; | ||||
|     std::optional<Pin> pin = std::nullopt; | ||||
| 
 | ||||
|     void comdel(std::ostream &buffer, int x, int y, int size) { | ||||
|         if(rect) rect->comdel(buffer, x, y, size); | ||||
|         if(line) line->comdel(buffer, x, y, size); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| class Display | ||||
| { | ||||
| public: | ||||
| 
 | ||||
|     Display(std::vector<ui::Item> items); | ||||
| 
 | ||||
|     void render(QGraphicsItemGroup *group) { | ||||
|         for(auto &item: items) { | ||||
|             item.render(group); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void comdel(std::ostream &buffer, int x, int y, int size) { | ||||
|         for(auto &item: items) { | ||||
|             item.comdel(buffer, x, y, size); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     std::vector<ui::Item> items; | ||||
| }; | ||||
| 
 | ||||
| } // namespace domain
 | ||||
| 
 | ||||
|  | ||||
| @ -1,166 +0,0 @@ | ||||
| #include <map> | ||||
| #include <utility> | ||||
| #include "function_signature.h" | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
|     class DivisibleValidator : public FunctionValidator { | ||||
|     public: | ||||
|         DivisibleValidator() : FunctionValidator("divisible", {Value::INT, Value::INT}) {} | ||||
| 
 | ||||
|         bool validate(std::vector<Value> values) override { | ||||
|             if (validateSignature(values)) { | ||||
|                 long long first = values[0].asInt(); | ||||
|                 long long second = values[1].asInt(); | ||||
|                 return (first % second) == 0; | ||||
|             } | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         void clear() override {} | ||||
|     }; | ||||
| 
 | ||||
|     class LessThenValidator : public FunctionValidator { | ||||
|     public: | ||||
|         LessThenValidator() : FunctionValidator("less_then", {Value::INT, Value::INT}) {} | ||||
| 
 | ||||
|         bool validate(std::vector<Value> values) override { | ||||
|             if (validateSignature(values)) { | ||||
|                 long long first = values[0].asInt(); | ||||
|                 long long second = values[1].asInt(); | ||||
|                 return first < second; | ||||
|             } | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         void clear() override {} | ||||
|     }; | ||||
| 
 | ||||
|     class GreaterThenValidator : public FunctionValidator { | ||||
|     public: | ||||
|         GreaterThenValidator() : FunctionValidator("greater_then", {Value::INT, Value::INT}) {} | ||||
| 
 | ||||
|         bool validate(std::vector<Value> values) override { | ||||
|             if (validateSignature(values)) { | ||||
|                 long long first = values[0].asInt(); | ||||
|                 long long second = values[1].asInt(); | ||||
|                 return first > second; | ||||
|             } | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         void clear() override {} | ||||
|     }; | ||||
| 
 | ||||
| 
 | ||||
|     class ContainsAddressValidator : public FunctionValidator { | ||||
|     public: | ||||
|         ContainsAddressValidator() : FunctionValidator("contains_address", {Value::ADDRESS_SPACE, Value::INT}) {} | ||||
| 
 | ||||
|         bool validate(std::vector<Value> values) override { | ||||
|             if (validateSignature(values)) { | ||||
|                 AddressSpace space = values[0].asAddressSpace(); | ||||
|                 long long address = values[1].asInt(); | ||||
|                 return space.contains(address); | ||||
|             } | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         void clear() override {} | ||||
|     }; | ||||
| 
 | ||||
| 
 | ||||
|     class ContainsValidator : public FunctionValidator { | ||||
|     public: | ||||
|         ContainsValidator() : FunctionValidator("contains", {Value::ADDRESS_SPACE, Value::INT, Value::INT}) {} | ||||
| 
 | ||||
|         bool validate(std::vector<Value> values) override { | ||||
|             if (validateSignature(values)) { | ||||
|                 AddressSpace space = values[0].asAddressSpace(); | ||||
|                 long long start = values[1].asInt(); | ||||
|                 long long size = values[1].asInt(); | ||||
|                 return space.contains(start, start + size); | ||||
|             } | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         void clear() override {} | ||||
|     }; | ||||
| 
 | ||||
| 
 | ||||
|     class UniqueValidator : public FunctionValidator { | ||||
| 
 | ||||
|     private: | ||||
|         std::map<std::string, std::vector<std::pair<long long int, long long int>>> spaces; | ||||
| 
 | ||||
|         bool overlaps(long long int start1, long long int end1, long long int start2, long long int end2) { | ||||
|             return std::max((long long int) 0, std::min(end1, end2) - std::max(start1, start2)) > 0; | ||||
|         } | ||||
| 
 | ||||
|     public: | ||||
|         UniqueValidator() : FunctionValidator("unique", {Value::ADDRESS_SPACE, Value::INT, Value::INT}) {} | ||||
| 
 | ||||
|         bool validate(std::vector<Value> values) override { | ||||
|             if (validateSignature(values)) { | ||||
|                 std::string space = values[0].asAddressSpace().getName(); | ||||
|                 long long int start = values[1].asInt(); | ||||
|                 long long int end = start + values[2].asInt(); | ||||
|                 if (spaces.count(space) == 0) { | ||||
|                     spaces.insert(std::make_pair(space, std::vector<std::pair<long long int, long long int>>{})); | ||||
|                 } | ||||
|                 for (auto &s: spaces[space]) { | ||||
|                     if (overlaps(s.first, s.second, start, end)) { | ||||
|                         return false; | ||||
|                     } | ||||
|                 } | ||||
|                 spaces[space].push_back(std::make_pair(start, end)); | ||||
|                 return true; | ||||
|             } | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         void clear() override { | ||||
|             spaces.clear(); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
| 
 | ||||
|     std::vector<FunctionValidator *> getSupportedValidators() { | ||||
|         std::vector<FunctionValidator *> validators; | ||||
| 
 | ||||
|         validators.push_back(new DivisibleValidator()); | ||||
|         validators.push_back(new LessThenValidator()); | ||||
|         validators.push_back(new GreaterThenValidator()); | ||||
|         validators.push_back(new ContainsAddressValidator()); | ||||
|         validators.push_back(new ContainsValidator()); | ||||
|         validators.push_back(new UniqueValidator()); | ||||
| 
 | ||||
|         return validators; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     FunctionValidator::FunctionValidator(std::string name, std::vector<Value::ValueType> signature) | ||||
|         : name(std::move(name)), signature(std::move(signature)) {} | ||||
| 
 | ||||
|     std::string FunctionValidator::getName() { | ||||
|         return name; | ||||
|     } | ||||
| 
 | ||||
|     std::vector<Value::ValueType> FunctionValidator::getSignature() { | ||||
|         return signature; | ||||
|     } | ||||
| 
 | ||||
|     bool FunctionValidator::validateSignature(std::vector<Value> _signature) { | ||||
|         if (this->signature.size() != _signature.size()) { | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         for (int i = 0; i < this->signature.size(); i++) { | ||||
|             if (this->signature[i] != _signature[i].getType()) { | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
| } // namespace domain
 | ||||
| @ -1,36 +0,0 @@ | ||||
| #ifndef DOMAIN_FUNCTION_VALIDATOR_H | ||||
| #define DOMAIN_FUNCTION_VALIDATOR_H | ||||
| 
 | ||||
| #include<functional> | ||||
| #include<vector> | ||||
| 
 | ||||
| #include "value.h" | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
|     class FunctionValidator { | ||||
|     private: | ||||
|         std::string name; | ||||
|         std::vector<Value::ValueType> signature; | ||||
| 
 | ||||
|     protected: | ||||
|         FunctionValidator(std::string name, std::vector<Value::ValueType> signature); | ||||
| 
 | ||||
|     public: | ||||
| 
 | ||||
|         std::string getName(); | ||||
| 
 | ||||
|         std::vector<Value::ValueType> getSignature(); | ||||
| 
 | ||||
|         bool validateSignature(std::vector<Value> signature); | ||||
| 
 | ||||
|         virtual bool validate(std::vector<Value> values) = 0; | ||||
| 
 | ||||
|         virtual void clear() = 0; | ||||
|     }; | ||||
| 
 | ||||
|     std::vector<FunctionValidator *> getSupportedValidators(); | ||||
| 
 | ||||
| } // namespace domain
 | ||||
| 
 | ||||
| #endif // DOMAIN_FUNCTION_VALIDATOR_H
 | ||||
							
								
								
									
										138
									
								
								comdel/domain/functionsignature.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								comdel/domain/functionsignature.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,138 @@ | ||||
| #include <map> | ||||
| #include "functionsignature.h" | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
| class DivisibleValidator: public FunctionValidator { | ||||
| public: | ||||
|     DivisibleValidator(): FunctionValidator("divisible", {Value::INT, Value::INT}) {} | ||||
| 
 | ||||
|     bool validate(std::vector<Value> values) override { | ||||
|         if(validateSignature(values)) { | ||||
|             long long first = values[0].asInt(); | ||||
|             long long second = values[1].asInt(); | ||||
|             return (first % second) == 0; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|     void clear() override {} | ||||
| }; | ||||
| 
 | ||||
| class LessThenValidator: public FunctionValidator { | ||||
| public: | ||||
|     LessThenValidator(): FunctionValidator("less_then", {Value::INT, Value::INT}) {} | ||||
| 
 | ||||
|     bool validate(std::vector<Value> values) override { | ||||
|         if(validateSignature(values)) { | ||||
|             long long first = values[0].asInt(); | ||||
|             long long second = values[1].asInt(); | ||||
|             return first < second; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|     void clear() override {} | ||||
| }; | ||||
| 
 | ||||
| class GreaterThenValidator: public FunctionValidator { | ||||
| public: | ||||
|     GreaterThenValidator(): FunctionValidator("greater_then", {Value::INT, Value::INT}) {} | ||||
| 
 | ||||
|     bool validate(std::vector<Value> values) override { | ||||
|         if(validateSignature(values)) { | ||||
|             long long first = values[0].asInt(); | ||||
|             long long second = values[1].asInt(); | ||||
|             return first > second; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|     void clear() override {} | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| class ContainsAddressValidator: public FunctionValidator { | ||||
| public: | ||||
|     ContainsAddressValidator(): FunctionValidator("contains_address", {Value::ADDRESS_SPACE, Value::INT}) {} | ||||
| 
 | ||||
|     bool validate(std::vector<Value> values) override { | ||||
|         if(validateSignature(values)) { | ||||
|             AddressSpace space = values[0].asAddressSpace(); | ||||
|             long long address = values[1].asInt(); | ||||
|             return space.contains(address); | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|     void clear() override {} | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| class ContainsValidator: public FunctionValidator { | ||||
| public: | ||||
|     ContainsValidator(): FunctionValidator("contains", {Value::ADDRESS_SPACE, Value::INT, Value::INT}) {} | ||||
| 
 | ||||
|     bool validate(std::vector<Value> values) override { | ||||
|         if(validateSignature(values)) { | ||||
|             AddressSpace space = values[0].asAddressSpace(); | ||||
|             long long start = values[1].asInt(); | ||||
|             long long size = values[1].asInt(); | ||||
|             return space.contains(start, start + size); | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|     void clear() override {} | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| class UniqueValidator: public FunctionValidator { | ||||
| 
 | ||||
| private: | ||||
|     std::map<std::string, std::vector<std::pair<long long int, long long int>>> spaces; | ||||
| 
 | ||||
|     bool overlaps(long long int start1, long long int end1, long long int start2, long long int end2) { | ||||
|         return std::max((long long int)0, std::min(end1, end2) - std::max(start1, start2)) > 0; | ||||
|     } | ||||
| 
 | ||||
| public: | ||||
|     UniqueValidator(): FunctionValidator("unique", {Value::ADDRESS_SPACE, Value::INT, Value::INT}) {} | ||||
| 
 | ||||
|     bool validate(std::vector<Value> values) override { | ||||
|         if(validateSignature(values)) { | ||||
|             std::string space = values[0].asAddressSpace().getName(); | ||||
|             long long int start = values[1].asInt(); | ||||
|             long long int end = start + values[2].asInt(); | ||||
|             if(spaces.count(space) == 0) { | ||||
|                 spaces.insert(std::make_pair(space, std::vector<std::pair<long long int, long long int>>{})); | ||||
|             } | ||||
|             for(auto& s: spaces[space]) { | ||||
|                 if(overlaps(s.first, s.second, start, end)) { | ||||
|                     return false; | ||||
|                 } | ||||
|             } | ||||
|             spaces[space].push_back(std::make_pair(start, end)); | ||||
|             return true; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|     void clear() override { | ||||
|         spaces.clear(); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| std::vector<FunctionValidator*> getSupportedValidators() { | ||||
|     std::vector<FunctionValidator*> validators; | ||||
| 
 | ||||
|     validators.push_back(new DivisibleValidator()); | ||||
|     validators.push_back(new LessThenValidator()); | ||||
|     validators.push_back(new GreaterThenValidator()); | ||||
|     validators.push_back(new ContainsAddressValidator()); | ||||
|     validators.push_back(new ContainsValidator()); | ||||
|     validators.push_back(new UniqueValidator()); | ||||
| 
 | ||||
|     return validators; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| } // namespace domain
 | ||||
							
								
								
									
										53
									
								
								comdel/domain/functionsignature.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								comdel/domain/functionsignature.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,53 @@ | ||||
| #ifndef DOMAIN_FUNCTION_VALIDATOR_H | ||||
| #define DOMAIN_FUNCTION_VALIDATOR_H | ||||
| 
 | ||||
| #include<functional> | ||||
| #include<vector> | ||||
| 
 | ||||
| #include "value.h" | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
| class FunctionValidator { | ||||
| private: | ||||
|     std::string name; | ||||
|     std::vector<Value::ValueType> signature; | ||||
| 
 | ||||
| protected: | ||||
|     FunctionValidator(std::string name, std::vector<Value::ValueType> signature) { | ||||
|         this->name = name; | ||||
|         this->signature = signature; | ||||
|     } | ||||
| 
 | ||||
| public: | ||||
| 
 | ||||
|     std::string getName() { | ||||
|         return name; | ||||
|     } | ||||
| 
 | ||||
|     std::vector<Value::ValueType> getSignature() { | ||||
|         return signature; | ||||
|     } | ||||
| 
 | ||||
|     bool validateSignature(std::vector<Value> signature) { | ||||
|         if(this->signature.size() != signature.size()) { | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         for(int i=0; i<this->signature.size(); i++) { | ||||
|             if(this->signature[i] != signature[i].getType()) { | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     virtual bool validate(std::vector<Value> values) = 0; | ||||
|     virtual void clear() = 0; | ||||
| }; | ||||
| 
 | ||||
| std::vector<FunctionValidator*> getSupportedValidators(); | ||||
| 
 | ||||
| } // namespace domain
 | ||||
| 
 | ||||
| #endif // DOMAIN_FUNCTION_VALIDATOR_H
 | ||||
| @ -2,18 +2,12 @@ | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
|     BusInstance::BusInstance(std::string name, std::pair<int, int> position, Bus bus, int size) | ||||
|             : name(name), position(position), bus(bus), size(size) { | ||||
|         if (size < 0 && bus.getDisplayBus().has_value()) { | ||||
|             this->size = bus.getDisplayBus()->getDefaultSize(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     BusInstance::BusInstance(std::string name, Bus bus) : name(name), bus(bus), position(0, 0), size(0) {} | ||||
| 
 | ||||
|     ComponentInstance::ComponentInstance(std::string name, std::vector<InstanceAttribute> attributes, | ||||
|                                          std::pair<int, int> position, Component component) | ||||
|             : name(name), attributes(std::move(attributes)), position(position), component(component) {} | ||||
| BusInstance::BusInstance(std::string name, std::pair<int, int> position, Bus bus, int size) | ||||
|     : name(name), position(position), bus(bus), size(size) | ||||
| {} | ||||
| ComponentInstance::ComponentInstance(std::string name, std::vector<InstanceAttribute> attributes, std::pair<int, int> position, Component component) | ||||
|     : name(name), attributes(std::move(attributes)), position(position), component(component) | ||||
| {} | ||||
| 
 | ||||
| 
 | ||||
| } // namespace domain
 | ||||
|  | ||||
| @ -3,41 +3,42 @@ | ||||
| 
 | ||||
| #include "bus.h" | ||||
| #include "component.h" | ||||
| #include "instance_attribute.h" | ||||
| #include "instanceattribute.h" | ||||
| 
 | ||||
| #include <string> | ||||
| #include <vector> | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
|     class BusInstance { | ||||
|     public: | ||||
|         std::string name; | ||||
|         std::pair<int, int> position; | ||||
| class BusInstance | ||||
| { | ||||
| public: | ||||
|     std::string name; | ||||
|     std::pair<int, int> position; | ||||
| 
 | ||||
|         Bus bus; | ||||
|         int size; | ||||
|     Bus bus; | ||||
|     int size; | ||||
| 
 | ||||
|         BusInstance(std::string name, Bus bus); | ||||
|     BusInstance(std::string name, std::pair<int, int> position, Bus bus, int size); | ||||
| 
 | ||||
|         BusInstance(std::string name, std::pair<int, int> position, Bus bus, int size = -1); | ||||
|     virtual ~BusInstance() = default; | ||||
| }; | ||||
| 
 | ||||
|         virtual ~BusInstance() = default; | ||||
|     }; | ||||
| class ComponentInstance | ||||
| { | ||||
| public: | ||||
|     std::string name; | ||||
|     std::vector<InstanceAttribute> attributes; | ||||
|     std::pair<int, int> position; | ||||
| 
 | ||||
|     class ComponentInstance { | ||||
|     public: | ||||
|         std::string name; | ||||
|         std::vector<InstanceAttribute> attributes; | ||||
|         std::pair<int, int> position; | ||||
|     Component component; | ||||
| 
 | ||||
|         Component component; | ||||
|     ComponentInstance(std::string name, std::vector<InstanceAttribute> attributes, std::pair<int, int> position, Component component); | ||||
| 
 | ||||
|         ComponentInstance(std::string name, std::vector<InstanceAttribute> attributes, std::pair<int, int> position, Component component); | ||||
| 
 | ||||
|         virtual ~ComponentInstance() = default; | ||||
|     }; | ||||
|     virtual ~ComponentInstance() = default; | ||||
| }; | ||||
| 
 | ||||
| } // namespace domain
 | ||||
| 
 | ||||
|  | ||||
| @ -1,8 +0,0 @@ | ||||
| #include "instance_attribute.h" | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
|     InstanceAttribute::InstanceAttribute(std::string name, Value value, Attribute attribute) | ||||
|             : name(name), value(value), attribute(attribute) {} | ||||
| 
 | ||||
| } // namespace domain
 | ||||
| @ -1,25 +0,0 @@ | ||||
| #ifndef DOMAIN_INSTANCE_ATTRIBUTE_H | ||||
| #define DOMAIN_INSTANCE_ATTRIBUTE_H | ||||
| 
 | ||||
| #include "attribute.h" | ||||
| #include "value.h" | ||||
| 
 | ||||
| #include <string> | ||||
| 
 | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
|     class InstanceAttribute { | ||||
|     public: | ||||
|         InstanceAttribute(std::string name, Value value, Attribute attribute); | ||||
| 
 | ||||
|         std::string name; | ||||
|         Value value; | ||||
|         Attribute attribute; | ||||
| 
 | ||||
|         ~InstanceAttribute() = default; | ||||
|     }; | ||||
| 
 | ||||
| } // namespace domain
 | ||||
| 
 | ||||
| #endif // DOMAIN_INSTANCE_ATTRIBUTE_H
 | ||||
							
								
								
									
										9
									
								
								comdel/domain/instanceattribute.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								comdel/domain/instanceattribute.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
| #include "instanceattribute.h" | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
| InstanceAttribute::InstanceAttribute(std::string name, Value value, Attribute attribute) | ||||
|     : name(name), value(value), attribute(attribute) | ||||
| {} | ||||
| 
 | ||||
| } // namespace domain
 | ||||
							
								
								
									
										27
									
								
								comdel/domain/instanceattribute.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								comdel/domain/instanceattribute.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,27 @@ | ||||
| #ifndef DOMAIN_INSTANCE_ATTRIBUTE_H | ||||
| #define DOMAIN_INSTANCE_ATTRIBUTE_H | ||||
| 
 | ||||
| #include "attribute.h" | ||||
| #include "value.h" | ||||
| 
 | ||||
| #include <string> | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
| class InstanceAttribute | ||||
| { | ||||
| public: | ||||
|     InstanceAttribute(std::string name, Value value, Attribute attribute); | ||||
| 
 | ||||
|     std::string name = ""; | ||||
|     Value value; | ||||
|     Attribute attribute; | ||||
| 
 | ||||
|     ~InstanceAttribute() = default; | ||||
| }; | ||||
| 
 | ||||
| } // namespace domain
 | ||||
| 
 | ||||
| #endif // DOMAIN_INSTANCE_ATTRIBUTE_H
 | ||||
| @ -1,146 +1,116 @@ | ||||
| #include "library.h" | ||||
| #include <stdexcept> | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
|     Library::Library(string name, string libraryInfo, string header, string componentDirectory, | ||||
|                      std::optional<std::string> componentHeader, | ||||
|                      vector<AddressSpace> addressSpaces, vector<Component> components, vector<Bus> buses, | ||||
|                      vector<Connection> connections, map<string, string> messages) | ||||
|             : name(name), libraryInfo(libraryInfo), header(header), componentDirectory(componentDirectory), | ||||
|               componentHeader(componentHeader), addressSpaces(addressSpaces), | ||||
|               components(components), buses(buses), connections(connections), messages(messages) {} | ||||
| Library::Library(string name, string libraryInfo, string header, string componentDirectory, std::optional<std::string> componentHeader, | ||||
|         vector<AddressSpace> addressSpaces, vector<Component> components, vector<Bus> buses, vector<Connection> connections, map<string, string> messages) | ||||
|     : name(name), libraryInfo(libraryInfo), header(header), componentDirectory(componentDirectory), componentHeader(componentHeader), addressSpaces(addressSpaces), | ||||
|       components(components), buses(buses), connections(connections), messages(messages) | ||||
| {} | ||||
| 
 | ||||
|     std::string Library::getName() { | ||||
|         return name; | ||||
|     } | ||||
| std::string Library::getName() { | ||||
|     return name; | ||||
| } | ||||
| std::string Library::getLibraryInfo() { | ||||
|     return libraryInfo; | ||||
| } | ||||
| std::string Library::getHeader() { | ||||
|     return header; | ||||
| } | ||||
| std::string Library::getComponentDirectory() { | ||||
|     return componentDirectory; | ||||
| } | ||||
| std::optional<std::string> Library::getComponentHeader() { | ||||
|     return componentHeader; | ||||
| } | ||||
| 
 | ||||
|     std::string Library::getLibraryInfo() { | ||||
|         return libraryInfo; | ||||
|     } | ||||
| std::vector<AddressSpace> Library::getAddressSpaces() { | ||||
|     return addressSpaces; | ||||
| } | ||||
| std::vector<Component> Library::getComponents() { | ||||
|     return components; | ||||
| } | ||||
| std::vector<Bus> Library::getBuses() { | ||||
|     return buses; | ||||
| } | ||||
| std::vector<Connection> Library::getConnections() { | ||||
|     return connections; | ||||
| } | ||||
| 
 | ||||
|     std::string Library::getHeader() { | ||||
|         return header; | ||||
|     } | ||||
| std::map<std::string, std::string> Library::getMessages() { | ||||
|     return messages; | ||||
| } | ||||
| 
 | ||||
|     std::string Library::getComponentDirectory() { | ||||
|         return componentDirectory; | ||||
|     } | ||||
| 
 | ||||
|     std::optional<std::string> Library::getComponentHeader() { | ||||
|         return componentHeader; | ||||
|     } | ||||
| 
 | ||||
|     std::vector<AddressSpace> Library::getAddressSpaces() { | ||||
|         return addressSpaces; | ||||
|     } | ||||
| 
 | ||||
|     std::vector<Component> Library::getComponents() { | ||||
|         return components; | ||||
|     } | ||||
| 
 | ||||
|     std::vector<Bus> Library::getBuses() { | ||||
|         return buses; | ||||
|     } | ||||
| 
 | ||||
|     std::vector<Connection> Library::getConnections() { | ||||
|         return connections; | ||||
|     } | ||||
| 
 | ||||
|     std::map<std::string, std::string> Library::getMessages() { | ||||
|         return messages; | ||||
|     } | ||||
| 
 | ||||
|     bool Library::hasComponent(std::string name) { | ||||
|         for (unsigned int i = 0; i < components.size(); i++) { | ||||
|             if (components[i].getName() == name) { | ||||
|                 return true; | ||||
|             } | ||||
| bool Library::hasComponent(std::string name) { | ||||
|     for(uint i=0; i<components.size(); i++) { | ||||
|         if(components[i].getName() == name) { | ||||
|             return true; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     bool Library::hasBus(std::string name) { | ||||
|         for (unsigned int i = 0; i < buses.size(); i++) { | ||||
|             if (buses[i].getName() == name) { | ||||
|                 return true; | ||||
|             } | ||||
|     return false; | ||||
| } | ||||
| bool Library::hasBus(std::string name) { | ||||
|     for(uint i=0; i<buses.size(); i++) { | ||||
|         if(buses[i].getName() == name) { | ||||
|             return true; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|     AddressSpace &Library::getAddressSpace(std::string addressSpace) { | ||||
|         for (unsigned int i = 0; i < addressSpaces.size(); i++) { | ||||
|             if (addressSpaces[i].getName() == addressSpace) { | ||||
|                 return addressSpaces[i]; | ||||
|             } | ||||
| AddressSpace &Library::getAddressSpace(std::string addressSpace) { | ||||
|     for(uint i=0; i<addressSpaces.size(); i++) { | ||||
|         if(addressSpaces[i].getName() == addressSpace) { | ||||
|             return addressSpaces[i]; | ||||
|         } | ||||
|         throw std::runtime_error("no address space with name '" + addressSpace + "'"); | ||||
|     } | ||||
| 
 | ||||
|     Component &Library::getComponent(std::string component) { | ||||
|         for (unsigned int i = 0; i < components.size(); i++) { | ||||
|             if (components[i].getName() == component) { | ||||
|                 return components[i]; | ||||
|             } | ||||
|     throw std::exception(); | ||||
| } | ||||
| Component &Library::getComponent(std::string component) { | ||||
|     for(uint i=0; i<components.size(); i++) { | ||||
|         if(components[i].getName() == component) { | ||||
|             return components[i]; | ||||
|         } | ||||
|         throw std::runtime_error("no component with name '" + component + "'"); | ||||
|     } | ||||
| 
 | ||||
|     Bus &Library::getBus(std::string bus) { | ||||
|         for (unsigned int i = 0; i < buses.size(); i++) { | ||||
|             if (buses[i].getName() == bus) { | ||||
|                 return buses[i]; | ||||
|             } | ||||
|     throw std::exception(); | ||||
| } | ||||
| Bus &Library::getBus(std::string bus) { | ||||
|     for(uint i=0; i<buses.size(); i++) { | ||||
|         if(buses[i].getName() == bus) { | ||||
|             return buses[i]; | ||||
|         } | ||||
|         throw std::runtime_error("no bus with name '" + bus + "'"); | ||||
| 
 | ||||
|     } | ||||
|     throw std::exception(); | ||||
| 
 | ||||
|     bool Library::hasConnection(ConnectionComponent component, std::string bus) { | ||||
|         return getConnection(component, bus).has_value(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|     std::optional<Connection> Library::getConnection(ConnectionComponent component, std::string bus) { | ||||
|         for (unsigned int i = 0; i < connections.size(); i++) { | ||||
|             if (connections[i].isConnecting(component, bus)) { | ||||
|                 return connections[i]; | ||||
|             } | ||||
| bool Library::hasConnection(ConnectionComponent component, std::string bus) { | ||||
|     return getConnection(component, bus).has_value(); | ||||
| } | ||||
| std::optional<Connection> Library::getConnection(ConnectionComponent component, std::string bus) { | ||||
|     for(uint i=0; i<connections.size(); i++) { | ||||
|         if(connections[i].isConnecting(component, bus)) { | ||||
|             return connections[i]; | ||||
|         } | ||||
|         return nullopt; | ||||
|     } | ||||
|     return nullopt; | ||||
| } | ||||
| 
 | ||||
|     bool Library::hasConnection(ConnectionComponent component, std::string bus, ConnectionComponent secondComponent) { | ||||
|         return getConnection(component, bus, secondComponent).has_value(); | ||||
|     } | ||||
| 
 | ||||
|     std::optional<Connection> | ||||
|     Library::getConnection(ConnectionComponent component, std::string bus, ConnectionComponent secondComponent) { | ||||
|         for (unsigned int i = 0; i < connections.size(); i++) { | ||||
|             if (connections[i].isConnecting(component, bus, secondComponent)) { | ||||
|                 return connections[i]; | ||||
|             } | ||||
| bool Library::hasConnection(ConnectionComponent component, std::string bus, ConnectionComponent secondComponent) { | ||||
|     return getConnection(component, bus, secondComponent).has_value(); | ||||
| } | ||||
| std::optional<Connection> Library::getConnection(ConnectionComponent component, std::string bus, ConnectionComponent secondComponent) { | ||||
|     for(uint i=0; i<connections.size(); i++) { | ||||
|         if(connections[i].isConnecting(component, bus, secondComponent)) { | ||||
|             return connections[i]; | ||||
|         } | ||||
|         return nullopt; | ||||
|     } | ||||
|     return nullopt; | ||||
| } | ||||
| 
 | ||||
|     std::string Library::getMessage(std::string key) { | ||||
|         return messages[key]; | ||||
|     } | ||||
| 
 | ||||
|     bool Library::hasConnection(ConnectionComponent component, ConnectionComponent secondComponent) { | ||||
|         return getConnection(component, secondComponent).has_value(); | ||||
|     } | ||||
| 
 | ||||
|     std::optional<Connection> | ||||
|     Library::getConnection(ConnectionComponent component, ConnectionComponent secondComponent) { | ||||
|         for (auto &connection: connections) { | ||||
|             if (connection.isConnecting(component, secondComponent)) { | ||||
|                 return connection; | ||||
|             } | ||||
|         } | ||||
|         return nullopt; | ||||
|     } | ||||
| std::string Library::getMessage(std::string key) { | ||||
|     return messages[key]; | ||||
| } | ||||
| 
 | ||||
| } // namespace domain
 | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| #ifndef DOMAIN_LIBRARY_H | ||||
| #define DOMAIN_LIBRARY_H | ||||
| 
 | ||||
| #include "address_space.h" | ||||
| #include "addressspace.h" | ||||
| #include "bus.h" | ||||
| #include "component.h" | ||||
| #include "connection.h" | ||||
| @ -10,75 +10,57 @@ | ||||
| #include <vector> | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
|     using namespace std; | ||||
| using namespace std; | ||||
| 
 | ||||
|     class Library { | ||||
|         std::string name; | ||||
|         std::string libraryInfo; | ||||
|         std::string header; | ||||
|         std::string componentDirectory; | ||||
|         std::optional<std::string> componentHeader; | ||||
| class Library | ||||
| { | ||||
|     std::string name; | ||||
|     std::string libraryInfo; | ||||
|     std::string header; | ||||
|     std::string componentDirectory; | ||||
|     std::optional<std::string> componentHeader; | ||||
| 
 | ||||
|         std::vector<AddressSpace> addressSpaces; | ||||
|         std::vector<Component> components; | ||||
|         std::vector<Bus> buses; | ||||
|         std::vector<Connection> connections; | ||||
|     std::vector<AddressSpace> addressSpaces; | ||||
|     std::vector<Component> components; | ||||
|     std::vector<Bus> buses; | ||||
|     std::vector<Connection> connections; | ||||
| 
 | ||||
|         std::map<std::string, std::string> messages; | ||||
|     std::map<std::string, std::string> messages; | ||||
| 
 | ||||
|     public: | ||||
|         Library(string name, string libraryInfo, string header, string componentDirectory, | ||||
|                 std::optional<string> componentHeader, | ||||
|                 vector<AddressSpace> addressSpaces, vector<Component> components, vector<Bus> buses, | ||||
|                 vector<Connection> connection, map<string, string> messages); | ||||
| public: | ||||
|     Library(string name, string libraryInfo, string header, string componentDirectory, std::optional<string> componentHeader, | ||||
|             vector<AddressSpace> addressSpaces, vector<Component> components, vector<Bus> buses, vector<Connection> connection, map<string, string> messages); | ||||
| 
 | ||||
|         std::string getName(); | ||||
|     std::string getName(); | ||||
|     std::string getLibraryInfo(); | ||||
|     std::string getHeader(); | ||||
|     std::string getComponentDirectory(); | ||||
|     std::optional<std::string> getComponentHeader(); | ||||
| 
 | ||||
|         std::string getLibraryInfo(); | ||||
|     std::vector<AddressSpace> getAddressSpaces(); | ||||
|     std::vector<Component> getComponents(); | ||||
|     std::vector<Bus> getBuses(); | ||||
|     std::vector<Connection> getConnections(); | ||||
| 
 | ||||
|         std::string getHeader(); | ||||
|     bool hasComponent(std::string name); | ||||
|     bool hasBus(std::string name); | ||||
| 
 | ||||
|         std::string getComponentDirectory(); | ||||
|     std::map<std::string, std::string> getMessages(); | ||||
| 
 | ||||
|         std::optional<std::string> getComponentHeader(); | ||||
|     AddressSpace &getAddressSpace(std::string name); | ||||
|     Component &getComponent(std::string name); | ||||
|     Bus &getBus(std::string bus); | ||||
|     std::string getMessage(std::string key); | ||||
| 
 | ||||
|         std::vector<AddressSpace> getAddressSpaces(); | ||||
|     bool hasConnection(ConnectionComponent component, std::string bus); | ||||
|     std::optional<Connection> getConnection(ConnectionComponent component, std::string bus); | ||||
| 
 | ||||
|         std::vector<Component> getComponents(); | ||||
| 
 | ||||
|         std::vector<Bus> getBuses(); | ||||
| 
 | ||||
|         std::vector<Connection> getConnections(); | ||||
| 
 | ||||
|         bool hasComponent(std::string name); | ||||
| 
 | ||||
|         bool hasBus(std::string name); | ||||
| 
 | ||||
|         std::map<std::string, std::string> getMessages(); | ||||
| 
 | ||||
|         AddressSpace &getAddressSpace(std::string name); | ||||
| 
 | ||||
|         Component &getComponent(std::string name); | ||||
| 
 | ||||
|         Bus &getBus(std::string bus); | ||||
| 
 | ||||
|         std::string getMessage(std::string key); | ||||
| 
 | ||||
|         bool hasConnection(ConnectionComponent component, std::string bus); | ||||
| 
 | ||||
|         std::optional<Connection> getConnection(ConnectionComponent component, std::string bus); | ||||
| 
 | ||||
|         bool hasConnection(ConnectionComponent component, std::string bus, ConnectionComponent secondComponent); | ||||
| 
 | ||||
|         std::optional<Connection> getConnection(ConnectionComponent component, std::string bus, ConnectionComponent secondComponent); | ||||
| 
 | ||||
|         bool hasConnection(ConnectionComponent component, ConnectionComponent secondComponent); | ||||
| 
 | ||||
|         std::optional<Connection> getConnection(ConnectionComponent component, ConnectionComponent secondComponent); | ||||
| 
 | ||||
|     }; | ||||
|     bool hasConnection(ConnectionComponent component, std::string bus, ConnectionComponent secondComponent); | ||||
|     std::optional<Connection> getConnection(ConnectionComponent component, std::string bus, ConnectionComponent secondComponent); | ||||
| }; | ||||
| 
 | ||||
| } // namespace domain
 | ||||
| 
 | ||||
|  | ||||
| @ -2,33 +2,40 @@ | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
|     Pin::Pin(std::string name, PinType type, std::string tooltip, std::optional<std::string> connection, domain::ui::Pin pin, | ||||
|              std::optional<std::vector<Value>> wires) | ||||
|             : name(name), type(type), tooltip(tooltip), connection(connection), displayPin(pin), wires(wires) {} | ||||
| PinConnection::PinConnection(std::string message, ConnectionType type) | ||||
|     : message(message), type(type) | ||||
| {} | ||||
| 
 | ||||
|     std::string &Pin::getName() { | ||||
|         return name; | ||||
|     } | ||||
| PinConnection::ConnectionType PinConnection::getType() { | ||||
|     return type; | ||||
| } | ||||
| std::string PinConnection::getMessage() { | ||||
|     return message; | ||||
| } | ||||
| 
 | ||||
|     Pin::PinType Pin::getType() { | ||||
|         return type; | ||||
|     } | ||||
| 
 | ||||
|     std::string Pin::getTooltip() { | ||||
|         return tooltip; | ||||
|     } | ||||
| Pin::Pin(std::string name, PinType type, std::string tooltip, PinConnection connection, Display display, std::optional<std::vector<Value>> wires) | ||||
|     : name(name), type(type), tooltip(tooltip), connection(connection), display(display), wires(wires) | ||||
| {} | ||||
| 
 | ||||
|     ui::Pin &Pin::getDisplayPin() { | ||||
|         return displayPin; | ||||
|     } | ||||
| 
 | ||||
|     std::optional<std::string> Pin::getConnection() { | ||||
|         return connection; | ||||
|     } | ||||
| 
 | ||||
|     std::optional<std::vector<Value>> &Pin::getWires() { | ||||
|         return wires; | ||||
|     } | ||||
| std::string &Pin::getName() { | ||||
|     return name; | ||||
| } | ||||
| Pin::PinType Pin::getType() { | ||||
|     return type; | ||||
| } | ||||
| std::string Pin::getTooltip() { | ||||
|     return tooltip; | ||||
| } | ||||
| Display &Pin::getDisplay() { | ||||
|     return display; | ||||
| } | ||||
| PinConnection &Pin::getConnection() { | ||||
|     return connection; | ||||
| } | ||||
| std::optional<std::vector<Value>> &Pin::getWires() { | ||||
|     return wires; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| } // namespace domain
 | ||||
|  | ||||
| @ -7,42 +7,57 @@ | ||||
| #include <string> | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
|     class Pin { | ||||
|     public: | ||||
|         enum PinType { | ||||
|             IN_OUT, | ||||
|             IN, | ||||
|             OUT | ||||
|         }; | ||||
| 
 | ||||
|     private: | ||||
|         std::string name; | ||||
|         PinType type; | ||||
|         std::string tooltip; | ||||
|         std::optional<std::string> connection; | ||||
|         domain::ui::Pin displayPin; | ||||
| 
 | ||||
|         std::optional<std::vector<Value>> wires; | ||||
| 
 | ||||
|     public: | ||||
|         Pin(std::string name, PinType type, std::string tooltip, std::optional<std::string> connection, domain::ui::Pin pin, | ||||
|             std::optional<std::vector<Value>> wires); | ||||
| 
 | ||||
|         std::string &getName(); | ||||
| 
 | ||||
|         PinType getType(); | ||||
| 
 | ||||
|         std::string getTooltip(); | ||||
| 
 | ||||
|         ui::Pin &getDisplayPin(); | ||||
| 
 | ||||
|         std::optional<std::string> getConnection(); | ||||
| 
 | ||||
|         std::optional<std::vector<Value>> &getWires(); | ||||
| class PinConnection | ||||
| { | ||||
| public: | ||||
|     enum ConnectionType { | ||||
|         REQUIRED, | ||||
|         OPTIONAL | ||||
|     }; | ||||
| 
 | ||||
| private: | ||||
|     std::string message; | ||||
|     ConnectionType type; | ||||
| 
 | ||||
| public: | ||||
|     PinConnection(std::string message, ConnectionType type); | ||||
| 
 | ||||
|     ConnectionType getType(); | ||||
|     std::string getMessage(); | ||||
| }; | ||||
| 
 | ||||
| class Pin | ||||
| { | ||||
| public: | ||||
|     enum PinType { | ||||
|         IN_OUT, | ||||
|         IN, | ||||
|         OUT | ||||
|     }; | ||||
| 
 | ||||
| private: | ||||
|     std::string name; | ||||
|     PinType type; | ||||
|     std::string tooltip; | ||||
|     PinConnection connection; | ||||
|     Display display; | ||||
| 
 | ||||
|     std::optional<std::vector<Value>> wires; | ||||
| 
 | ||||
| public: | ||||
|     Pin(std::string name, PinType type, std::string tooltip, PinConnection connection, Display display, std::optional<std::vector<Value>> wires); | ||||
| 
 | ||||
|     std::string &getName(); | ||||
|     PinType getType(); | ||||
|     std::string getTooltip(); | ||||
|     Display &getDisplay(); | ||||
|     PinConnection &getConnection(); | ||||
|     std::optional<std::vector<Value>> &getWires(); | ||||
| }; | ||||
| 
 | ||||
| } // namespace domain
 | ||||
| 
 | ||||
| #endif // DOMAIN_PIN_H
 | ||||
|  | ||||
| @ -1,61 +1,62 @@ | ||||
| #include "rule.h" | ||||
| 
 | ||||
| #include <utility> | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
|     Condition::Condition(std::string function, std::vector<Value> params, bool negated) | ||||
|             : negated(negated), function(std::move(function)), params(std::move(params)) {} | ||||
| Condition::Condition(std::string function, std::vector<Value> params, bool negated) | ||||
|     : negated(negated), function(function), params(params) | ||||
| {} | ||||
| 
 | ||||
|     bool Condition::evaluate(RuleContext &context) { | ||||
|         std::vector<Value> request; | ||||
|         for (auto & param : params) { | ||||
|             if (param.isType(Value::ADDRESS_SPACE_REFERENCE)) { | ||||
|                 request.push_back(Value::fromAddressSpace(context.addressSpaces.at(param.asReference()))); | ||||
|             } else if (param.isType(Value::ATTRIBUTE_REFERENCE)) { | ||||
|                 request.push_back(context.attributes[param.asReference()]); | ||||
|             } else { | ||||
|                 request.push_back(param); | ||||
|             } | ||||
| bool Condition::evaluate(RuleContext &context) { | ||||
|     std::vector<Value> request; | ||||
|     for(unsigned int i=0; i<params.size(); i++) { | ||||
|         if(params[i].isType(Value::ADDRESS_SPACE_REFERENCE)) { | ||||
|             request.push_back(Value::fromAddressSpace(context.addressSpaces.at(params[i].asReference()))); | ||||
|         } else if(params[i].isType(Value::ATTRIBUTE_REFERENCE)) { | ||||
|             request.push_back(context.attributes[params[i].asReference()]); | ||||
|         } else { | ||||
|             request.push_back(params[i]); | ||||
|         } | ||||
|         bool result = context.function[function]->validate(request); | ||||
|         return negated ? !result : result; | ||||
|     } | ||||
|     bool result = context.function[function]->validate(request); | ||||
|     return negated ? !result : result; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|     Action::Action(ActionType type, std::string message) | ||||
|             : type(type), message(std::move(message)) {} | ||||
| Action::Action(ActionType type, std::string message) | ||||
|     : type(type), message(message) | ||||
| {} | ||||
| 
 | ||||
|     Action::ActionType Action::getType() { | ||||
|         return type; | ||||
| Action::ActionType Action::getType() { | ||||
|     return type; | ||||
| } | ||||
| std::string Action::getMessage() { | ||||
|     return message; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| IfStatement::IfStatement(Condition condition, Action action) | ||||
|     : condition(condition), action(action) | ||||
| {} | ||||
| 
 | ||||
| std::optional<Action> IfStatement::evaluate(RuleContext &context) { | ||||
|     if(condition.evaluate(context)) { | ||||
|         return action; | ||||
|     } | ||||
|     return std::nullopt; | ||||
| } | ||||
| 
 | ||||
|     std::string Action::getMessage() { | ||||
|         return message; | ||||
|     } | ||||
| Rule::Rule(std::vector<IfStatement> statements) | ||||
|     : statements(statements) | ||||
| {} | ||||
| 
 | ||||
| 
 | ||||
|     IfStatement::IfStatement(Condition condition, Action action) | ||||
|             : condition(std::move(condition)), action(std::move(action)) {} | ||||
| 
 | ||||
|     std::optional<Action> IfStatement::evaluate(RuleContext &context) { | ||||
|         if (condition.evaluate(context)) { | ||||
|             return action; | ||||
| std::optional<Action> Rule::evaluate(RuleContext &context) { | ||||
|     for(unsigned int i=0; i<statements.size(); i++) { | ||||
|         auto response = statements[i].evaluate(context); | ||||
|         if(response) { | ||||
|             return response; | ||||
|         } | ||||
|         return std::nullopt; | ||||
|     } | ||||
| 
 | ||||
|     Rule::Rule(std::vector<IfStatement> statements) | ||||
|             : statements(std::move(statements)) {} | ||||
| 
 | ||||
|     std::optional<Action> Rule::evaluate(RuleContext &context) { | ||||
|         for (auto & statement : statements) { | ||||
|             auto response = statement.evaluate(context); | ||||
|             if (response) { | ||||
|                 return response; | ||||
|             } | ||||
|         } | ||||
|         return std::nullopt; | ||||
|     } | ||||
|     return std::nullopt; | ||||
| } | ||||
| 
 | ||||
| } // namespace domain
 | ||||
|  | ||||
| @ -1,9 +1,9 @@ | ||||
| #ifndef DOMAIN_RULE_H | ||||
| #define DOMAIN_RULE_H | ||||
| 
 | ||||
| #include "address_space.h" | ||||
| #include "addressspace.h" | ||||
| #include "value.h" | ||||
| #include "function_signature.h" | ||||
| #include "functionsignature.h" | ||||
| 
 | ||||
| #include <map> | ||||
| #include <string> | ||||
| @ -12,58 +12,58 @@ | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
|     struct RuleContext { | ||||
|         std::map<std::string, AddressSpace> addressSpaces; | ||||
|         std::map<std::string, Value> attributes; | ||||
|         std::map<std::string, FunctionValidator *> function; | ||||
| struct RuleContext { | ||||
|     std::map<std::string, AddressSpace> addressSpaces; | ||||
|     std::map<std::string, Value> attributes; | ||||
|     std::map<std::string, FunctionValidator*> function; | ||||
| }; | ||||
| 
 | ||||
| class Condition { | ||||
|     bool negated; | ||||
|     std::string function; | ||||
|     std::vector<Value> params; | ||||
| 
 | ||||
| public: | ||||
|     Condition(std::string function, std::vector<Value> params, bool negated); | ||||
| 
 | ||||
|     bool evaluate(RuleContext &context); | ||||
| }; | ||||
| 
 | ||||
| class Action { | ||||
| public: | ||||
|     enum ActionType { | ||||
|         ERROR, | ||||
|         WARNING | ||||
|     }; | ||||
| 
 | ||||
|     class Condition { | ||||
|         bool negated; | ||||
|         std::string function; | ||||
|         std::vector<Value> params; | ||||
| private: | ||||
|     ActionType type; | ||||
|     std::string message; | ||||
| 
 | ||||
|     public: | ||||
|         Condition(std::string function, std::vector<Value> params, bool negated); | ||||
| public: | ||||
|     Action(ActionType type, std::string message); | ||||
| 
 | ||||
|         bool evaluate(RuleContext &context); | ||||
|     }; | ||||
|     ActionType getType(); | ||||
|     std::string getMessage(); | ||||
| }; | ||||
| 
 | ||||
|     class Action { | ||||
|     public: | ||||
|         enum ActionType { | ||||
|             ERROR, | ||||
|             WARNING | ||||
|         }; | ||||
| class IfStatement { | ||||
|     Condition condition; | ||||
|     Action action; | ||||
| public: | ||||
|     IfStatement(Condition condition, Action action); | ||||
| 
 | ||||
|     private: | ||||
|         ActionType type; | ||||
|         std::string message; | ||||
|     std::optional<Action> evaluate(RuleContext &context); | ||||
| }; | ||||
| 
 | ||||
|     public: | ||||
|         Action(ActionType type, std::string message); | ||||
| class Rule | ||||
| { | ||||
|     std::vector<IfStatement> statements; | ||||
| public: | ||||
|     Rule(std::vector<IfStatement> statements); | ||||
| 
 | ||||
|         ActionType getType(); | ||||
| 
 | ||||
|         std::string getMessage(); | ||||
|     }; | ||||
| 
 | ||||
|     class IfStatement { | ||||
|         Condition condition; | ||||
|         Action action; | ||||
|     public: | ||||
|         IfStatement(Condition condition, Action action); | ||||
| 
 | ||||
|         std::optional<Action> evaluate(RuleContext &context); | ||||
|     }; | ||||
| 
 | ||||
|     class Rule { | ||||
|         std::vector<IfStatement> statements; | ||||
|     public: | ||||
|         explicit Rule(std::vector<IfStatement> statements); | ||||
| 
 | ||||
|         std::optional<Action> evaluate(RuleContext &context); | ||||
|     }; | ||||
|     std::optional<Action> evaluate(RuleContext &context); | ||||
| }; | ||||
| 
 | ||||
| } // namespace domain
 | ||||
| 
 | ||||
|  | ||||
| @ -2,114 +2,27 @@ | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
|     bool Schema::hasConnection(string &component, string &pin) { | ||||
|         return getConnection(component, pin) != nullptr; | ||||
|     } | ||||
| Schema::Schema() | ||||
| { | ||||
| } | ||||
| 
 | ||||
|     ConnectionInstance *Schema::getConnection(string &component, string &pin) { | ||||
|         auto pinConnections = getConnections(component, pin); | ||||
|         if(pinConnections.empty()) { | ||||
|             return nullptr; | ||||
|         } else { | ||||
|             return pinConnections[0]; | ||||
| bool Schema::hasConnection(string& component, string& pin) { | ||||
|     return getConnection(component, pin) != nullptr; | ||||
| } | ||||
| 
 | ||||
| ConnectionInstance* Schema::getConnection(string& component, string& pin) { | ||||
|     for(auto& conn: connections) { | ||||
|         if(conn->instance->name == component && conn->connection.getComponent().pin == pin) { | ||||
|             return conn.get(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     std::vector<ConnectionInstance*> Schema::getConnections(string &component, string &pin) { | ||||
|         std::vector<ConnectionInstance*> pinConnections; | ||||
|         for (auto &conn: connections) { | ||||
|             if (conn->instance->name == component && conn->connection.getComponent().pin == pin) { | ||||
|                 pinConnections.push_back(conn.get()); | ||||
|             } | ||||
|             auto dirConn = dynamic_cast<DirectConnectionInstance *>(conn.get()); | ||||
|             if (dirConn != nullptr) { | ||||
|                 if (dirConn->secondInstance->name == component && conn->connection.getSecondComponent()->pin == pin) { | ||||
|                     pinConnections.push_back(conn.get()); | ||||
|                 } | ||||
|         auto dirConn = dynamic_cast<DirectConnectionInstance*>(conn.get()); | ||||
|         if(dirConn != nullptr) { | ||||
|             if(dirConn->secondInstance->name == component && conn->connection.getSecondComponent()->pin == pin) { | ||||
|                 return dirConn; | ||||
|             } | ||||
|         } | ||||
|         return pinConnections; | ||||
|     } | ||||
| 
 | ||||
|     BusInstance *Schema::getBusInstance(string &name) { | ||||
|         for (auto &instance: busInstances) { | ||||
|             if (instance->name == name) { | ||||
|                 return instance.get(); | ||||
|             } | ||||
|         } | ||||
|         return nullptr; | ||||
|     } | ||||
| 
 | ||||
|     ComponentInstance *Schema::getComponentInstance(string &name) { | ||||
|         for (auto &instance: componentInstances) { | ||||
|             if (instance->name == name) { | ||||
|                 return instance.get(); | ||||
|             } | ||||
|         } | ||||
|         return nullptr; | ||||
|     } | ||||
| 
 | ||||
|     std::vector<ConnectionEntry> Schema::availableConnections(std::string instanceName, std::string pinName, bool onlyConnectable) { | ||||
|         std::vector<ConnectionEntry> entries; | ||||
| 
 | ||||
|         auto instance = getComponentInstance(instanceName); | ||||
| 
 | ||||
|         ConnectionComponent connectionComponent{instance->component.getName(), pinName}; | ||||
|         for(auto &conn: library.getConnections()) { | ||||
|             if(conn.isConnecting(connectionComponent)) { | ||||
|                 if(library.getBus(conn.getBus()).getType() == Bus::REGULAR) { | ||||
|                     for(auto& bus: busInstances) { | ||||
|                         if(bus->bus.getName() == conn.getBus()) { | ||||
|                             entries.push_back({ConnectionEntry::BUS, bus.get(), nullopt, nullopt, conn}); | ||||
|                         } | ||||
|                     } | ||||
|                 } else { | ||||
|                     for(auto& component: componentInstances) { | ||||
|                         for(auto& pin: component->component.getPins()) { | ||||
|                             if(conn.isConnecting(connectionComponent, {component->component.getName(), pin.getName()})) { | ||||
|                                 ConnectionEntry entry{ConnectionEntry::COMPONENT, nullopt, component.get(), pin, conn}; | ||||
|                                 entries.emplace_back(entry); | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if(onlyConnectable) { | ||||
|             entries.erase( | ||||
|                     std::remove_if( | ||||
|                             entries.begin(), | ||||
|                             entries.end(), | ||||
|                             [this, instance](ConnectionEntry &entry) { | ||||
|                                 auto& bus = this->library.getBus(entry.connection.getBus()); | ||||
|                                 // we allow duplicates of single automatic connections
 | ||||
|                                 if(bus.getType() == Bus::SINGLE_AUTOMATIC) { | ||||
|                                     return false; | ||||
|                                 } | ||||
|                                 for(auto& conn: this->connections) { | ||||
|                                     if(conn->connection == entry.connection) { | ||||
|                                         if(bus.getType() == Bus::REGULAR) { | ||||
|                                             auto busConnection = dynamic_cast<BusConnectionInstance*>(conn.get()); | ||||
|                                             if(busConnection->instance == instance && busConnection->bus == entry.busInstance.value()) { | ||||
|                                                 return true; | ||||
|                                             } | ||||
|                                         } else { | ||||
|                                             auto directConnection = dynamic_cast<DirectConnectionInstance*>(conn.get()); | ||||
|                                             if(directConnection->instance == instance && directConnection->secondInstance == entry.componentInstance.value() || | ||||
|                                                directConnection->secondInstance == instance && directConnection->instance == entry.componentInstance.value()) { | ||||
|                                                 return true; | ||||
|                                             } | ||||
|                                         } | ||||
|                                     } | ||||
|                                 } | ||||
|                                 return false; | ||||
|                             }), | ||||
|                     entries.end() | ||||
|             ); | ||||
|         } | ||||
|         return entries; | ||||
| 
 | ||||
|     } | ||||
|     return nullptr; | ||||
| } | ||||
| 
 | ||||
| } // namespace domain
 | ||||
|  | ||||
| @ -1,50 +1,44 @@ | ||||
| #ifndef DOMAIN_SCHEMA_H | ||||
| #define DOMAIN_SCHEMA_H | ||||
| 
 | ||||
| #include "connection_instance.h" | ||||
| #include "connectioninstance.h" | ||||
| #include "instance.h" | ||||
| #include "library.h" | ||||
| #include "wireinstance.h" | ||||
| 
 | ||||
| #include <utility> | ||||
| #include <vector> | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
|     struct ConnectionEntry { | ||||
|         enum Type { | ||||
|             BUS, | ||||
|             COMPONENT | ||||
|         }; | ||||
| class Schema | ||||
| { | ||||
| public: | ||||
|     Schema(); | ||||
| 
 | ||||
|         Type type; | ||||
|     std::vector<shared_ptr<BusInstance>> busInstances; | ||||
|     std::vector<shared_ptr<ComponentInstance>> componentInstances; | ||||
| 
 | ||||
|         std::optional<BusInstance*> busInstance; | ||||
|         std::optional<ComponentInstance*> componentInstance; | ||||
|         std::optional<Pin> pin; | ||||
|     std::vector<shared_ptr<ConnectionInstance>> connections; | ||||
| 
 | ||||
|         Connection connection; | ||||
|     }; | ||||
|     BusInstance *getBusInstance(std::string& name) { | ||||
|         for(auto& instance: busInstances) { | ||||
|             if (instance->name == name) { | ||||
|                 return instance.get(); | ||||
|             } | ||||
|         } | ||||
|         return nullptr; | ||||
|     } | ||||
|     ComponentInstance *getComponentInstance(std::string& name) { | ||||
|         for(auto& instance: componentInstances) { | ||||
|             if (instance->name == name) { | ||||
|                 return instance.get(); | ||||
|             } | ||||
|         } | ||||
|         return nullptr; | ||||
|     } | ||||
| 
 | ||||
|     class Schema { | ||||
|     private: | ||||
|         Library library; | ||||
|     public: | ||||
|         Schema(Library library): library(std::move(library)) {} | ||||
| 
 | ||||
|         std::vector<shared_ptr<BusInstance>> busInstances; | ||||
|         std::vector<shared_ptr<ComponentInstance>> componentInstances; | ||||
| 
 | ||||
|         std::vector<shared_ptr<ConnectionInstance>> connections; | ||||
| 
 | ||||
|         BusInstance *getBusInstance(std::string &name); | ||||
|         ComponentInstance *getComponentInstance(std::string &name); | ||||
|         bool hasConnection(string &component, string &pin); | ||||
|         ConnectionInstance *getConnection(string &component, string &pin); | ||||
| 
 | ||||
|         std::vector<ConnectionEntry> availableConnections(std::string instance, std::string pin, bool onlyConnectable); | ||||
| 
 | ||||
|         vector<ConnectionInstance *> getConnections(string &component, string &pin); | ||||
|     }; | ||||
|     bool hasConnection(string& component, string& pin); | ||||
|     ConnectionInstance* getConnection(string& component, string& pin); | ||||
| }; | ||||
| 
 | ||||
| } // namespace domain
 | ||||
| 
 | ||||
|  | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -1,92 +0,0 @@ | ||||
| #ifndef DOMAIN_COMDEL_GENERATOR_H | ||||
| #define DOMAIN_COMDEL_GENERATOR_H | ||||
| 
 | ||||
| #include "library.h" | ||||
| #include "schema.h" | ||||
| 
 | ||||
| #include <set> | ||||
| #include <utility> | ||||
| 
 | ||||
| #include <comdel/parser/ast_nodes.h> | ||||
| #include <comdel/parser/parse_context.h> | ||||
| #include <comdel/parser/presult.h> | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
|     /** Context used for loading model */ | ||||
|     struct ComdelContext { | ||||
|         std::vector<Attribute> attributes; | ||||
|         std::vector<std::string> wires; | ||||
|         std::string name; | ||||
|         bool inComponent; | ||||
|         bool inConnection; | ||||
|         bool inSingleAutomaticConnection; | ||||
| 
 | ||||
|         ComdelContext(std::string name, bool inComponent, bool inConnection, bool inSingleAutomaticConnection); | ||||
| 
 | ||||
|         bool doesAttributeExists(std::string name, Value::ValueType type); | ||||
|         bool doesWireExists(std::string name); | ||||
| 
 | ||||
|     }; | ||||
| 
 | ||||
|     class SchemaCreator { | ||||
| 
 | ||||
|     public: | ||||
|         explicit SchemaCreator(std::vector<FunctionValidator *> validators); | ||||
| 
 | ||||
|         std::vector<SourceError> getErrors(); | ||||
| 
 | ||||
|         std::optional<Library> loadLibrary(LibraryNode node); | ||||
|         Schema *loadSchema(SchemaNode node, Library &library); | ||||
| 
 | ||||
|     private: | ||||
|         std::vector<ComdelContext> context; | ||||
| 
 | ||||
|         std::string name; | ||||
|         std::string libraryInfo; | ||||
|         std::string header; | ||||
|         std::string componentDirectory; | ||||
|         std::optional<std::string> componentHeader = nullopt; | ||||
|         std::vector<AddressSpace> addressSpaces; | ||||
|         std::vector<Component> components; | ||||
|         std::vector<Bus> buses; | ||||
|         std::vector<Connection> connections; | ||||
|         std::map<std::string, std::string> messages; | ||||
| 
 | ||||
|         std::vector<SourceError> errors; | ||||
|         std::vector<FunctionValidator *> validators; | ||||
| 
 | ||||
| 
 | ||||
|         std::optional<AddressSpace> loadAddressSpace(AddressSpaceNode node); | ||||
|         std::optional<Component> loadComponent(ComponentNode node); | ||||
|         std::optional<Attribute> loadAttribute(AttributeNode node); | ||||
|         std::optional<Rule> loadRule(RuleNode node); | ||||
|         std::optional<Condition> loadCondition(ConditionNode node); | ||||
|         std::optional<Popup> loadPopup(PopupNode node, std::string name, Value::ValueType type); | ||||
|         std::optional<Display> loadDisplay(DisplayNode node); | ||||
|         std::optional<Wire> loadWire(WireNode node); | ||||
|         std::optional<Pin> loadPin(PinNode pins); | ||||
|         std::optional<Connection> loadConnection(ConnectionNode node); | ||||
|         std::optional<Bus> loadBus(BusNode node); | ||||
|         std::shared_ptr<ComponentInstance> loadComponentInstance(InstanceNode instance, Library &library); | ||||
|         std::shared_ptr<BusInstance> loadBusInstance(InstanceNode instance, Library &library); | ||||
| 
 | ||||
|         /** Utility classes */ | ||||
|         std::optional<Bus> getBus(std::string name); | ||||
|         std::optional<Pin> getComponentPin(std::string name, std::string pin); | ||||
|         bool hasAddressSpace(std::string name); | ||||
| 
 | ||||
|         std::optional<Attribute> createMemoryAttribute(); | ||||
|         vector<Enumeration> createWireEnumeration(vector<Value> enumeration); | ||||
|         std::optional<Popup> createMemoryPopup(); | ||||
| 
 | ||||
|         /** Context stack operations */ | ||||
|         void push(ComdelContext context); | ||||
|         void pushAdditional(std::string name); | ||||
|         ComdelContext ¤t(); | ||||
|         void pop(); | ||||
|     }; | ||||
| 
 | ||||
| } // namespace domain
 | ||||
| 
 | ||||
| #endif // DOMAIN_COMDEL_GENERATOR_H
 | ||||
							
								
								
									
										956
									
								
								comdel/domain/schemacreator.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										956
									
								
								comdel/domain/schemacreator.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,956 @@ | ||||
| #include "schemacreator.h" | ||||
| 
 | ||||
| #include<set> | ||||
| #include <utility> | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
| Component::ComponentType toType(ComponentNode::ComponentType type) { | ||||
|     if(type == ComponentNode::MEMORY) { | ||||
|         return Component::MEMORY; | ||||
|     } else if(type == ComponentNode::PROCESSOR) { | ||||
|         return Component::PROCESSOR; | ||||
|     } | ||||
|     return Component::OTHER; | ||||
| } | ||||
| 
 | ||||
| Action::ActionType toType(ActionNode::ActionType type) { | ||||
|     if(type == ActionNode::ERROR) { | ||||
|         return Action::ERROR; | ||||
|     } | ||||
|     return Action::WARNING; | ||||
| } | ||||
| 
 | ||||
| Wire::WireType toType(WireNode::WireType type) { | ||||
|     switch (type) { | ||||
|     case WireNode::R_WIRE: | ||||
|         return Wire::R_WIRE; | ||||
|     case WireNode::WIRE: | ||||
|         return Wire::WIRE_DEFAULT; | ||||
|     case WireNode::WIRED_AND: | ||||
|         return Wire::WIRED_AND; | ||||
|     case WireNode::WIRED_OR: | ||||
|         return Wire::WIRED_OR; | ||||
|     default: | ||||
|         return Wire::WIRE_DEFAULT; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| Value::ValueType toType(ValueNode::ValueType type) { | ||||
|     switch (type) { | ||||
|     case ValueNode::BOOL: | ||||
|         return Value::BOOL; | ||||
|     case ValueNode::MEMORY: | ||||
|         return Value::MEMORY_REFERENCE; | ||||
|     case ValueNode::WIRE: | ||||
|         return Value::WIRE_REFERENCE; | ||||
|     case ValueNode::STRING: | ||||
|         return Value::STRING; | ||||
|     case ValueNode::INT: | ||||
|         return Value::INT; | ||||
|     case ValueNode::NIL: | ||||
|         return Value::NIL; | ||||
|     default: | ||||
|         return Value::UNDEFINED; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| Value toType(ValueNode node, Value::ValueType type = Value::ValueType::UNDEFINED) { | ||||
|     if(type == Value::MEMORY_REFERENCE) { | ||||
|         if(node.getType() == ValueNode::NIL) { | ||||
|             return Value::fromMemoryReference(nullopt); | ||||
|         } else { | ||||
|             return Value::fromMemoryReference(node.asIdentifier()); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if(node.getType() == ValueNode::BOOL) { | ||||
|         return Value::fromBool(node.asBool()); | ||||
|     } else if(node.getType() == ValueNode::INT) { | ||||
|         return Value::fromInt(node.asInt()); | ||||
|     } else if(node.getType() == ValueNode::STRING) { | ||||
|         return Value::fromString(node.asString()); | ||||
|     } else if(node.getType() == ValueNode::NIL) { | ||||
|         return Value::fromNull(); | ||||
|     } | ||||
|     return Value::fromReference(node.asIdentifier(), Value::UNDEFINED); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| Bus::BusType toType(BusNode::BusType type) { | ||||
|     if(type == BusNode::AUTOMATIC) { | ||||
|         return Bus::AUTOMATIC; | ||||
|     } else if(type == BusNode::SINGLE_AUTOMATIC) { | ||||
|         return Bus::SINGLE_AUTOMATIC; | ||||
|     } | ||||
|     return Bus::REGULAR; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| Pin::PinType toType(PinNode::PinType type) { | ||||
|     if(type == PinNode::IN) { | ||||
|         return Pin::IN; | ||||
|     } else if(type == PinNode::OUT) { | ||||
|         return Pin::OUT; | ||||
|     } | ||||
|     return Pin::IN_OUT; | ||||
| } | ||||
| 
 | ||||
| PinConnection::ConnectionType toType(PinConnectionNode::ConnectionType type) | ||||
| { | ||||
|     if(type == PinConnectionNode::OPTIONAL) { | ||||
|         return PinConnection::OPTIONAL; | ||||
|     } | ||||
|     return PinConnection::REQUIRED; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| Popup::PopupType toType(PopupNode::PopupType type) | ||||
| { | ||||
|     if(type == PopupNode::AUTOMATIC) { | ||||
|         return Popup::AUTOMATIC; | ||||
|     } | ||||
|     return Popup::ON_DEMAND; | ||||
| } | ||||
| 
 | ||||
| SchemaCreator::SchemaCreator(std::vector<FunctionValidator*> validators) | ||||
|     : validators(std::move(validators)) | ||||
| {} | ||||
| 
 | ||||
| std::optional<Library> SchemaCreator::loadLibrary(LibraryNode node) | ||||
| { | ||||
|     // library fields
 | ||||
|     if(!node.name) { | ||||
|         errors.emplace_back(node.span, "missing @name"); | ||||
|         return nullopt; | ||||
|     } else { | ||||
|         name = node.name->asString(); | ||||
|     } | ||||
| 
 | ||||
|     if(node.componentHeader.has_value()) { | ||||
|         componentHeader = node.componentHeader->asString(); | ||||
|     } | ||||
| 
 | ||||
|     if(!node.componentDirectory) { | ||||
|         errors.emplace_back(node.span, "missing @componentDirectory"); | ||||
|         return nullopt; | ||||
|     } else { | ||||
|         componentDirectory = node.componentDirectory->asString(); | ||||
|     } | ||||
| 
 | ||||
|     header = node.header ? node.header->asString() : ""; | ||||
| 
 | ||||
|     libraryInfo = node.libraryInfo ? node.libraryInfo->asString() : ""; | ||||
| 
 | ||||
|     for(auto& as: node.addressSpaces) { | ||||
|         addressSpaces.push_back(*loadAddressSpace(as)); | ||||
|     } | ||||
| 
 | ||||
|     for(auto& comp: node.components) { | ||||
|         std::optional<Component> component; | ||||
|         component = loadComponent(comp); | ||||
|         if(component) { | ||||
|             components.push_back(*component); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     for(auto& buse : node.buses) { | ||||
|         auto bus = loadBus(buse); | ||||
|         if(bus) { | ||||
|             buses.push_back(*bus); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     for(auto& connection : node.connections) { | ||||
|         auto conn = loadConnection(connection); | ||||
|         if(conn) { | ||||
|             connections.push_back(*conn); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     for(auto & message : node.messages) { | ||||
|         if(!message.value.is(ValueNode::STRING)) { | ||||
|             errors.emplace_back(message.value.span, "expected `string`"); | ||||
|         } else { | ||||
|             messages[message.key.value] = message.value.asString(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return Library(name, libraryInfo, header, componentDirectory, componentHeader, addressSpaces, components, buses, connections, messages); | ||||
| } | ||||
| 
 | ||||
| std::optional<Bus> SchemaCreator::loadBus(BusNode node) | ||||
| { | ||||
|     std::string name = node.name.value; | ||||
| 
 | ||||
|     auto count = std::make_pair<int, int>(1, 1); | ||||
|     if(node.count) { | ||||
|         count = std::make_pair<int, int>(node.count->first.value, node.count->second.value); | ||||
|     } | ||||
|     if(count.first > count.second || count.first < 0) { | ||||
|         errors.emplace_back(node.count->span, "invalid @size"); | ||||
|         return nullopt; | ||||
|     } | ||||
| 
 | ||||
|     auto type = toType(node.type.value); | ||||
| 
 | ||||
|     if(!node.tooltip && type == Bus::REGULAR) { | ||||
|         errors.emplace_back(node.span, "missing @tooltip"); | ||||
|         return nullopt; | ||||
|     } | ||||
|     std::string tooltip = node.tooltip->asString(); | ||||
| 
 | ||||
|     if(!node.display && type == Bus::REGULAR) { | ||||
|         errors.emplace_back(node.span, "missing @display"); | ||||
|         return nullopt; | ||||
|     } | ||||
|     if(node.display && (type == Bus::AUTOMATIC || type == Bus::SINGLE_AUTOMATIC)) { | ||||
|         errors.emplace_back(node.span, "automatic bus cannot have a @display"); | ||||
|         return nullopt; | ||||
|     } | ||||
| 
 | ||||
|     optional<Display> display; | ||||
|     if(type == Bus::REGULAR) { | ||||
|         display = loadDisplay(*node.display); | ||||
|         if(!display) { | ||||
|             return nullopt; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if(node.wires.size() == 0) { | ||||
|         errors.emplace_back(node.span, "missing @wires"); | ||||
|         return nullopt; | ||||
|     } | ||||
|     std::vector<Wire> wires; | ||||
|     for(auto& _wire: node.wires) { | ||||
|         auto wire = loadWire(_wire); | ||||
|         if(wire) { | ||||
|             wires.push_back(*wire); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if(type == Bus::SINGLE_AUTOMATIC && wires.size() != 1) { | ||||
|         errors.emplace_back(node.span, "singleAutomatic bus must have exactly 1 wire defined"); | ||||
|         return nullopt; | ||||
|     } | ||||
| 
 | ||||
|     return Bus(name, tooltip, type, count, wires, display); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| std::optional<AddressSpace> SchemaCreator::loadAddressSpace(AddressSpaceNode node) | ||||
| { | ||||
|     return AddressSpace(node.name.value, node.start.value, node.end.value); | ||||
| } | ||||
| 
 | ||||
| std::optional<Connection> SchemaCreator::loadConnection(ConnectionNode node) | ||||
| { | ||||
|     push(ComdelContext("connection", false, true, false, false)); | ||||
| 
 | ||||
|     std::string bus = node.bus.value; | ||||
|     auto busInstance = getBus(bus); | ||||
|     if(!busInstance) { | ||||
|         errors.emplace_back(node.span, "bus does not exist"); | ||||
|     } | ||||
| 
 | ||||
|     if(busInstance->getType() == Bus::SINGLE_AUTOMATIC) { | ||||
|         current().inSingleAutomaticConnection = true; | ||||
|     } | ||||
| 
 | ||||
|     if(busInstance->getType() == Bus::REGULAR) { | ||||
|         ConnectionComponent first{node.first.component.value, node.first.pin.value}; | ||||
| 
 | ||||
|         auto componentInstance = getComponentPin(first.component, first.pin); | ||||
|         if(!componentInstance) { | ||||
|             errors.emplace_back(node.span, "pin does not exist"); | ||||
|         } | ||||
| 
 | ||||
|         if(node.second.has_value()) { | ||||
|             errors.emplace_back(node.span, "regular bus doesn't allow direct connections"); | ||||
|         } | ||||
| 
 | ||||
|         std::set<std::string> wireNames; | ||||
|         for(auto &wire: busInstance->getWires()) { | ||||
|             wireNames.insert(wire.getName()); | ||||
|             current().wires.push_back(wire.getName()); | ||||
|         } | ||||
| 
 | ||||
|         std::vector<Attribute> attributes; | ||||
|         for(auto & attribute : node.attributes) { | ||||
|             auto attr = loadAttribute(attribute); | ||||
|             if(!attr) { | ||||
|                 return nullopt; | ||||
|             } | ||||
|             attributes.push_back(*attr); | ||||
|         } | ||||
| 
 | ||||
|         std::set<std::string> attributeNames; | ||||
|         for(auto attribute: attributes) { | ||||
|             attributeNames.insert(attribute.getName()); | ||||
|         } | ||||
| 
 | ||||
|         std::vector<Value> wires; | ||||
|         for(auto & firstWire : node.firstWires) { | ||||
|             if(firstWire.is(ValueNode::NIL)) { | ||||
|                 wires.push_back(Value::fromNull()); | ||||
|             } else if(firstWire.is(ValueNode::INT)) { | ||||
|                 wires.push_back(Value::fromInt(firstWire.asInt())); | ||||
|             } else if(firstWire.is(ValueNode::IDENTIFIER)) { | ||||
|                 if(attributeNames.count(firstWire.asIdentifier())) { | ||||
|                     wires.push_back(Value::fromReference(firstWire.asIdentifier(), Value::ATTRIBUTE_REFERENCE)); | ||||
|                 } else if(wireNames.count(firstWire.asIdentifier())) { | ||||
|                     wires.push_back(Value::fromReference(firstWire.asIdentifier(), Value::WIRE_REFERENCE)); | ||||
|                 } else { | ||||
|                     errors.emplace_back(firstWire.span, "unknown identifier"); | ||||
|                 } | ||||
|             } else { | ||||
|                 errors.emplace_back(firstWire.span, "unknown value type"); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         pop(); | ||||
| 
 | ||||
|         return Connection(first, nullopt, bus, attributes, wires, nullopt); | ||||
|     } else if(busInstance->getType() == Bus::AUTOMATIC || busInstance->getType() == Bus::SINGLE_AUTOMATIC) { | ||||
|         ConnectionComponent first{node.first.component.value, node.first.pin.value}; | ||||
| 
 | ||||
|         if(!node.second.has_value()) { | ||||
|             errors.emplace_back(node.span, "missing second component"); | ||||
|         } | ||||
| 
 | ||||
|         ConnectionComponent second{node.second->component.value, node.second->pin.value}; | ||||
| 
 | ||||
|         auto firstComponentInstance = getComponentPin(first.component, first.pin); | ||||
|         if(!firstComponentInstance) { | ||||
|             errors.emplace_back(node.span, "pin does not exist"); | ||||
|         } | ||||
| 
 | ||||
|         auto secondComponentInstance = getComponentPin(second.component, second.pin); | ||||
|         if(!secondComponentInstance) { | ||||
|             errors.emplace_back(node.span, "pin does not exist"); | ||||
|         } | ||||
| 
 | ||||
|         std::set<std::string> wireNames; | ||||
|         for(auto &wire: busInstance->getWires()) { | ||||
|             wireNames.insert(wire.getName()); | ||||
|             current().wires.push_back(wire.getName()); | ||||
|         } | ||||
| 
 | ||||
|         if(node.attributes.size() != 2 && busInstance->getType() == Bus::SINGLE_AUTOMATIC) { | ||||
|             errors.emplace_back(node.span, "singleAutomatic must contain 2 attributes"); | ||||
|         } | ||||
| 
 | ||||
|         std::vector<Attribute> attributes; | ||||
|         for(auto & attribute : node.attributes) { | ||||
|             auto attr = loadAttribute(attribute); | ||||
|             if(!attr) { | ||||
|                 return nullopt; | ||||
|             } | ||||
|             attributes.push_back(*attr); | ||||
|         } | ||||
| 
 | ||||
|         std::set<std::string> attributeNames; | ||||
|         for(auto attribute: attributes) { | ||||
|             attributeNames.insert(attribute.getName()); | ||||
|         } | ||||
| 
 | ||||
|         std::vector<Value> firstWires; | ||||
|         for(auto & firstWire : node.firstWires) { | ||||
|             if(firstWire.is(ValueNode::NIL)) { | ||||
|                 firstWires.push_back(Value::fromNull()); | ||||
|             } else if(firstWire.is(ValueNode::INT)) { | ||||
|                 firstWires.push_back(Value::fromInt(firstWire.asInt())); | ||||
|             } else if(firstWire.is(ValueNode::STRING) && busInstance->getType() == Bus::SINGLE_AUTOMATIC) { | ||||
|                 firstWires.push_back(Value::fromString(firstWire.asString())); | ||||
|             } else if(firstWire.is(ValueNode::IDENTIFIER) && busInstance->getType() == Bus::AUTOMATIC) { | ||||
|                 if(attributeNames.count(firstWire.asIdentifier())) { | ||||
|                     firstWires.push_back(Value::fromReference(firstWire.asIdentifier(), Value::ATTRIBUTE_REFERENCE)); | ||||
|                 } else if(wireNames.count(firstWire.asIdentifier())) { | ||||
|                     firstWires.push_back(Value::fromReference(firstWire.asIdentifier(), Value::WIRE_REFERENCE)); | ||||
|                 } else { | ||||
|                     errors.emplace_back(firstWire.span, "unknown identifier"); | ||||
|                 } | ||||
|             } else { | ||||
|                 errors.emplace_back(firstWire.span, "unsupported value type"); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         std::vector<Value> secondWires; | ||||
|         for(auto & secondWire : *node.secondWires) { | ||||
|             if(secondWire.is(ValueNode::NIL)) { | ||||
|                 secondWires.push_back(Value::fromNull()); | ||||
|             } else if(secondWire.is(ValueNode::INT)) { | ||||
|                 secondWires.push_back(Value::fromInt(secondWire.asInt())); | ||||
|             } else if(secondWire.is(ValueNode::STRING) && busInstance->getType() == Bus::SINGLE_AUTOMATIC) { | ||||
|                 secondWires.push_back(Value::fromString(secondWire.asString())); | ||||
|             } else if(secondWire.is(ValueNode::IDENTIFIER) && busInstance->getType() == Bus::AUTOMATIC) { | ||||
|                 if(attributeNames.count(secondWire.asIdentifier())) { | ||||
|                     secondWires.push_back(Value::fromReference(secondWire.asIdentifier(), Value::ATTRIBUTE_REFERENCE)); | ||||
|                 } else if(wireNames.count(secondWire.asIdentifier())) { | ||||
|                     secondWires.push_back(Value::fromReference(secondWire.asIdentifier(), Value::WIRE_REFERENCE)); | ||||
|                 } else { | ||||
|                     errors.emplace_back(secondWire.span, "unknown identifier"); | ||||
|                 } | ||||
|             } else { | ||||
|                 errors.emplace_back(secondWire.span, "unsupported value type"); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if(busInstance->getType() == Bus::SINGLE_AUTOMATIC && attributes.size() == 2) { | ||||
|             if(!attributes[0].getPopup().has_value()) { | ||||
|                 errors.emplace_back(node.attributes[0].span, "@popup is required"); | ||||
|             } else if(attributes[0].getDefault().getType() != Value::STRING) { | ||||
|                 errors.emplace_back(node.attributes[0].span, "@attribute must be of type string"); | ||||
|             } else { | ||||
|                 attributes[0].getPopup()->setEnumeration(createWireEnumeration(firstWires)); | ||||
|             } | ||||
| 
 | ||||
|             if(!attributes[1].getPopup().has_value()) { | ||||
|                 errors.emplace_back(node.attributes[1].span, "@popup is required"); | ||||
|             } else if(attributes[1].getDefault().getType() != Value::STRING) { | ||||
|                 errors.emplace_back(node.attributes[1].span, "@attribute must be of type string"); | ||||
|             } else { | ||||
|                 attributes[1].getPopup()->setEnumeration(createWireEnumeration(secondWires)); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         pop(); | ||||
| 
 | ||||
|         return Connection(first, second, bus, attributes, firstWires, secondWires); | ||||
|     } | ||||
|     pop(); | ||||
|     errors.emplace_back(node.span, "unsupported connection type"); | ||||
| 
 | ||||
|     return std::nullopt; | ||||
| } | ||||
| 
 | ||||
| std::optional<Component> SchemaCreator::loadComponent(ComponentNode node) | ||||
| { | ||||
|     push(ComdelContext(node.name.value, true, false, false, false)); | ||||
| 
 | ||||
|     std::string name = node.name.value; | ||||
| 
 | ||||
|     if(!node.tooltip) { | ||||
|         errors.emplace_back(node.span, "missing @tooltip"); | ||||
|         pop(); | ||||
|         return nullopt; | ||||
|     } | ||||
|     std::string tooltip = node.tooltip->asString(); | ||||
| 
 | ||||
|     if(!node.source) { | ||||
|         errors.emplace_back(node.span, "missing @source"); | ||||
|         pop(); | ||||
|         return nullopt; | ||||
|     } | ||||
|     std::string source = node.source->asString(); | ||||
| 
 | ||||
|     Component::ComponentType type = toType(node.type.value); | ||||
| 
 | ||||
|     std::vector<Attribute> attributes; | ||||
|     for(auto& a: node.attributes) { | ||||
|         std::optional<Attribute> attribute = loadAttribute(a); | ||||
|         if(attribute) { | ||||
|             attributes.push_back(*attribute); | ||||
|         } | ||||
|     } | ||||
|     if(type == Component::PROCESSOR) { | ||||
|         attributes.push_back(*createMemoryAttribute()); | ||||
|     } | ||||
| 
 | ||||
|     context[context.size() -1 ].attributes = attributes; | ||||
| 
 | ||||
|     std::vector<Rule> rules; | ||||
|     for(auto& r: node.rules) { | ||||
|         std::optional<Rule> rule = loadRule(r); | ||||
|         if(rule) { | ||||
|             rules.push_back(*rule); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if(!node.instanceName) { | ||||
|         errors.emplace_back(node.span, "missing @instanceName"); | ||||
|         pop(); | ||||
|         return nullopt; | ||||
|     } | ||||
|     std::string instanceName = node.instanceName->asString(); | ||||
| 
 | ||||
|     auto count = std::make_pair<int, int>(1, 1); | ||||
|     if(node.count) { | ||||
|         count = std::make_pair<int, int>(node.count->first.value, node.count->second.value); | ||||
|     } | ||||
|     if(count.first > count.second || count.first < 0) { | ||||
|         errors.emplace_back(node.count->first.span, "invalid @size"); | ||||
|         pop(); | ||||
|         return nullopt; | ||||
|     } | ||||
| 
 | ||||
|     if(!node.display) { | ||||
|         errors.emplace_back(node.span, "missing @display"); | ||||
|         pop(); | ||||
|         return nullopt; | ||||
|     } | ||||
|     optional<Display> display = loadDisplay(*node.display); | ||||
|     if(!display) { | ||||
|         pop(); | ||||
|         return nullopt; | ||||
|     } | ||||
| 
 | ||||
|     std::vector<Pin> pins; | ||||
|     for(auto &p : node.pins) { | ||||
|         auto pin = loadPin(p); | ||||
|         if(!pin) { | ||||
|             pop(); | ||||
|             return nullopt; | ||||
|         } | ||||
|         pins.push_back(*pin); | ||||
|     } | ||||
| 
 | ||||
|     pop(); | ||||
|     return Component(name, tooltip, source, type, rules, instanceName, count, *display, pins, attributes); | ||||
| } | ||||
| 
 | ||||
| std::optional<Wire> SchemaCreator::loadWire(WireNode node) { | ||||
|     return Wire( | ||||
|                 node.name.value, | ||||
|                 toType(node.type.value), | ||||
|                 node.size.value, | ||||
|                 node.hidden, | ||||
|                 node.hasTerminateWith, | ||||
|                 toType(node.terminateWith) | ||||
|     ); | ||||
| } | ||||
| 
 | ||||
| optional<Pin> SchemaCreator::loadPin(PinNode node) | ||||
| { | ||||
|     std::string name = node.name.value; | ||||
|     Pin::PinType type = toType(node.type.value); | ||||
| 
 | ||||
|     if(!node.tooltip) { | ||||
|         errors.emplace_back(node.span, "missing @tooltip"); | ||||
|         return nullopt; | ||||
|     } | ||||
|     std::string tooltip = node.tooltip->asString(); | ||||
| 
 | ||||
|     if(!node.display) { | ||||
|         errors.emplace_back(node.span, "missing @display"); | ||||
|         return nullopt; | ||||
|     } | ||||
|     std::vector<Attribute> attributes; | ||||
|     optional<Display> display = loadDisplay(*node.display); | ||||
|     if(!display) { | ||||
|         return nullopt; | ||||
|     } | ||||
| 
 | ||||
|     if(!node.connection) { | ||||
|         errors.emplace_back(node.span, "missing @connection"); | ||||
|         return nullopt; | ||||
|     } | ||||
|     auto connection = loadPinConnection(*node.connection); | ||||
| 
 | ||||
|     std::optional<std::vector<Value>> wiresOpt = std::nullopt; | ||||
|     if(node.wires.has_value()) { | ||||
|         auto nodeWires = node.wires.value(); | ||||
|         std::vector<Value> wires; | ||||
|         for(auto &nodeWire : nodeWires) { | ||||
|             if(nodeWire.is(ValueNode::NIL)) { | ||||
|                 wires.push_back(Value::fromNull()); | ||||
|             } else if(nodeWire.is(ValueNode::INT)) { | ||||
|                 wires.push_back(Value::fromInt(nodeWire.asInt())); | ||||
|             } else { | ||||
|                 errors.emplace_back(node.span, "unknown value type"); | ||||
|             } | ||||
|         } | ||||
|         wiresOpt = wires; | ||||
|     } | ||||
| 
 | ||||
|     return Pin(name, type, tooltip, connection, *display, wiresOpt); | ||||
| } | ||||
| 
 | ||||
| int getIntProperty(DisplayItemNode &node, std::string property) { | ||||
|     for(auto& prop: node.values) { | ||||
|         if(prop.key.value == property) { | ||||
|             return prop.value.asInt(); | ||||
|         } | ||||
|     } | ||||
|     throw std::exception(); | ||||
| } | ||||
| 
 | ||||
| std::optional<Display> SchemaCreator::loadDisplay(DisplayNode node) | ||||
| { | ||||
|     std::vector<ui::Item> items; | ||||
|     for(auto &item: node.items) { | ||||
|         ui::Item displayItem; | ||||
|         std::string type = item.type.value; | ||||
|         if(type == "rect") { | ||||
|             int x, y, w, h; | ||||
|             x = getIntProperty(item, "x"); | ||||
|             y = getIntProperty(item, "y"); | ||||
|             w = getIntProperty(item, "w"); | ||||
|             h = getIntProperty(item, "h"); | ||||
|             displayItem.rect = ui::Rect(x, y, w, h); | ||||
|         } else if(type == "line") { | ||||
|             int x1, y1, x2, y2; | ||||
|             x1 = getIntProperty(item, "x1"); | ||||
|             y1 = getIntProperty(item, "y1"); | ||||
|             x2 = getIntProperty(item, "x2"); | ||||
|             y2 = getIntProperty(item, "y2"); | ||||
|             displayItem.line = ui::Line(x1, y1, x2, y2); | ||||
|         } else if(type == "pin") { | ||||
|             int x, y, w, h; | ||||
|             x = getIntProperty(item, "x"); | ||||
|             y = getIntProperty(item, "y"); | ||||
|             w = getIntProperty(item, "w"); | ||||
|             h = getIntProperty(item, "h"); | ||||
|             displayItem.pin = ui::Pin(x, y, w, h); | ||||
|         } else { | ||||
|             errors.emplace_back(item.type.span, "unsupported display type"); | ||||
|         } | ||||
|         items.push_back(displayItem); | ||||
|     } | ||||
|     return Display(items); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| PinConnection SchemaCreator::loadPinConnection(PinConnectionNode node) | ||||
| { | ||||
|     std::string message = node.message.asString(); | ||||
|     PinConnection::ConnectionType type = toType(node.type.value); | ||||
|     return {message, type}; | ||||
| } | ||||
| 
 | ||||
| std::optional<Attribute> SchemaCreator::loadAttribute(AttributeNode node) | ||||
| { | ||||
|     std::string name = node.name.value; | ||||
|     pushAdditional(name); | ||||
|     Value value; | ||||
| 
 | ||||
|     if(current().inComponent) { | ||||
|         if(node.type == ValueNode::INT) { | ||||
|             value = Value::fromInt(node.defaultValue->asInt()); | ||||
|         } else if (node.type == ValueNode::BOOL) { | ||||
|             value = Value::fromBool(node.defaultValue->asBool()); | ||||
|         } else if (node.type == ValueNode::STRING) { | ||||
|             value = Value::fromString(node.defaultValue->asString()); | ||||
|         } else { | ||||
|             errors.emplace_back(node.name.span, "unsupported type"); | ||||
|         } | ||||
|     } | ||||
|     if(current().inConnection && !current().inSingleAutomaticConnection) { // TODO remove identifier
 | ||||
|         if (node.type == ValueNode::WIRE || node.type == ValueNode::IDENTIFIER) { | ||||
|             if(current().doesWireExists(node.defaultValue->asIdentifier())) { | ||||
|                 value = Value::fromReference(node.defaultValue->asIdentifier(), Value::WIRE_REFERENCE); | ||||
|             } else { | ||||
|                 value = Value::fromReference("", Value::WIRE_REFERENCE); | ||||
|                 errors.emplace_back(node.span, "unknown identifier"); | ||||
|             } | ||||
|         } else { | ||||
|             errors.emplace_back(node.name.span, "unsupported type"); | ||||
|         } | ||||
|     } | ||||
|     if(current().inSingleAutomaticConnection) { | ||||
|         if (node.type == ValueNode::STRING) { | ||||
|             value = Value::fromString(node.defaultValue->asString()); | ||||
|         } else { | ||||
|             errors.emplace_back(node.name.span, "unsupported type"); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     current().attributes.emplace_back(name, value); | ||||
| 
 | ||||
|     std::optional<Popup> popup; | ||||
|     if(node.popup) { | ||||
|         popup = loadPopup(*node.popup, name, value.getType()); | ||||
|     } | ||||
| 
 | ||||
|     pop(); | ||||
|     return Attribute(name, value, popup); | ||||
| } | ||||
| 
 | ||||
| std::optional<Popup> SchemaCreator::loadPopup(PopupNode node, std::string name, Value::ValueType type) | ||||
| { | ||||
|     auto popupType = toType(node.type.value().value); | ||||
| 
 | ||||
|     pushAdditional(name); | ||||
| 
 | ||||
|     current().attributes.clear(); | ||||
|     current().attributes.emplace_back(name, Value::ofType(type)); | ||||
| 
 | ||||
|     if(!node.title) { | ||||
|         errors.emplace_back(node.span, "missing @title"); | ||||
|         return nullopt; | ||||
|     } | ||||
|     std::string title = node.title->asString(); | ||||
| 
 | ||||
|     if(!node.text) { | ||||
|         errors.emplace_back(node.span, "missing @text"); | ||||
|         return nullopt; | ||||
|     } | ||||
|     std::string text = node.text->asString(); | ||||
| 
 | ||||
|     std::vector<Rule> rules; | ||||
|     for(auto& r: node.rules) { | ||||
|         std::optional<Rule> rule = loadRule(r); | ||||
|         if(rule) { | ||||
|             rules.push_back(*rule); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     std::vector<Enumeration> enumeration; | ||||
|     if(node.enumerated) { | ||||
|         for(auto& enumNode : node.enumeration) { | ||||
|             if(type == Value::INT || type == Value::STRING || type == Value::BOOL) { | ||||
|                 auto value = toType(enumNode.value); | ||||
|                 if(value.getType() == type) { | ||||
|                     enumeration.emplace_back(enumNode.key.asString(), value); | ||||
|                 } else { | ||||
|                     errors.emplace_back(enumNode.span, "wrong type"); | ||||
|                 } | ||||
|             } else if(type == Value::WIRE_REFERENCE) { | ||||
|                 auto value = toType(enumNode.value); | ||||
|                 if(value.isType(Value::UNDEFINED)) { | ||||
|                     if(current().doesWireExists(value.asReference())) { | ||||
|                         value = Value::fromReference(value.asReference(), Value::WIRE_REFERENCE); | ||||
|                     } else { | ||||
|                         errors.emplace_back(enumNode.span, "unknown wire"); | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 if(value.isType(Value::WIRE_REFERENCE) || value.isType(Value::INT) || value.isType(Value::NIL)) { | ||||
|                     enumeration.emplace_back(enumNode.key.asString(), value); | ||||
|                 } else { | ||||
|                     errors.emplace_back(enumNode.span, "wrong type"); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } else { | ||||
|         if(type == Value::WIRE_REFERENCE && !current().inConnection) { | ||||
|             errors.emplace_back(node.span, "@enumeration is required for attributes of type wire"); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pop(); | ||||
| 
 | ||||
|     return Popup(title, text, popupType, rules, enumeration); | ||||
| } | ||||
| 
 | ||||
| std::optional<Rule> SchemaCreator::loadRule(RuleNode node) | ||||
| { | ||||
|     std::vector<IfStatement> statements; | ||||
| 
 | ||||
|     for(auto& stmt: node.statements) { | ||||
|         auto condition = loadCondition(stmt.condition); | ||||
|         if(condition) { | ||||
|             statements.emplace_back(*condition, Action(toType(stmt.action.type.value), stmt.action.message.asString())); | ||||
|         } else { | ||||
|             return nullopt; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return Rule(statements); | ||||
| } | ||||
| 
 | ||||
| std::optional<Condition> SchemaCreator::loadCondition(ConditionNode node) | ||||
| { | ||||
|     std::string function = node.functionName.value; | ||||
| 
 | ||||
|     for(auto & validator : validators) { | ||||
|         if(validator->getName() == function) { | ||||
|             if(validator->getSignature().size() == node.params.size()) { | ||||
|                 std::vector<Value> params; | ||||
|                 for(uint j=0; j<validator->getSignature().size(); j++) { | ||||
|                     bool exists = false; | ||||
|                     auto type = toType(node.params[j]); | ||||
|                     if (type.getType() == Value::UNDEFINED) { | ||||
|                         if(current().doesAttributeExists(type.asReference(), validator->getSignature()[j])) { | ||||
|                             exists = true; | ||||
|                             type = Value::fromReference(type.asReference(), Value::ATTRIBUTE_REFERENCE); | ||||
|                         } | ||||
|                         if(validator->getSignature()[j] == Value::ADDRESS_SPACE) { | ||||
|                             if(hasAddressSpace(type.asReference())) { | ||||
|                                 exists = true; | ||||
|                                 type = Value::fromReference(type.asReference(), Value::ADDRESS_SPACE_REFERENCE); | ||||
|                             } | ||||
|                         } | ||||
| 
 | ||||
|                         if(!exists) { | ||||
|                             errors.emplace_back(node.functionName.span, "unknown reference " + type.asReference()); | ||||
|                         } | ||||
|                     } | ||||
|                     params.push_back(type); | ||||
|                 } | ||||
|                 return Condition(function, params, node.negated); | ||||
|             } else { | ||||
|                 errors.emplace_back(node.functionName.span, "wrong number of parameters"); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     errors.emplace_back(node.functionName.span, "unknown function name"); | ||||
|     return nullopt; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| Schema* SchemaCreator::loadSchema(SchemaNode node, Library &library) | ||||
| { | ||||
|     auto *schema = new Schema(); | ||||
| 
 | ||||
|     for(auto &instance: node.instances) { | ||||
|         if(library.hasComponent(instance.component.value)) { | ||||
|             schema->componentInstances.push_back(loadComponentInstance(instance, library)); | ||||
|         } | ||||
|         if(library.hasBus(instance.component.value)) { | ||||
|             schema->busInstances.push_back(loadBusInstance(instance, library)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     for(auto &conn: node.connections) { | ||||
|         auto firstComponent = schema->getComponentInstance(conn.first.instance.value); | ||||
|         if(firstComponent == nullptr) { | ||||
|             errors.emplace_back(conn.first.instance.span, "unknown component"); | ||||
|             continue; | ||||
|         } | ||||
|         if(!firstComponent->component.hasPin(conn.first.pin.value)) { | ||||
|             errors.emplace_back(conn.first.pin.span, "unknown pin"); | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         ComponentInstance *secondComponent = nullptr; | ||||
|         if(conn.second.has_value()) { | ||||
|             secondComponent = schema->getComponentInstance(conn.second->instance.value); | ||||
|             if(secondComponent == nullptr) { | ||||
|                 errors.emplace_back(conn.second->instance.span, "unknown component"); | ||||
|                 continue; | ||||
|             } | ||||
|             if(!secondComponent->component.hasPin(conn.second->pin.value)) { | ||||
|                 errors.emplace_back(conn.second->pin.span, "unknown pin"); | ||||
|                 continue; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         auto bus = schema->getBusInstance(conn.bus.value); | ||||
|         if(bus == nullptr) { | ||||
|             errors.emplace_back(conn.bus.span, "unknown bus"); | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         std::optional<Connection> connection = std::nullopt; | ||||
|         if(secondComponent != nullptr) { | ||||
|             ConnectionComponent firstConn{firstComponent->component.getName(), conn.first.pin.value}; | ||||
|             ConnectionComponent secondConn{secondComponent->component.getName(), conn.second->pin.value}; | ||||
| 
 | ||||
|             if(library.hasConnection(firstConn, | ||||
|                                      bus->bus.getName(), | ||||
|                                      secondConn)) { | ||||
|                 connection = *library.getConnection(firstConn, bus->bus.getName(), secondConn); | ||||
|             } else { | ||||
|                 errors.emplace_back(conn.span, "unknown connection"); | ||||
|                 continue; | ||||
|             } | ||||
|         } else { | ||||
|             ConnectionComponent firstConn{firstComponent->component.getName(), conn.first.pin.value}; | ||||
| 
 | ||||
|             if(library.hasConnection(firstConn, | ||||
|                                      bus->bus.getName())) { | ||||
|                 connection = *library.getConnection(firstConn, bus->bus.getName()); | ||||
|             } else { | ||||
|                 errors.emplace_back(conn.span, "unknown connection"); | ||||
|                 continue; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         std::vector<InstanceAttribute> attributes; | ||||
|         for(auto& attr: conn.attributes) { | ||||
|             if(connection->hasAttribute(attr.name.value)) { | ||||
|                 auto attribute = connection->getAttribute(attr.name.value); | ||||
|                 auto value = toType(attr.value); | ||||
| 
 | ||||
|                 for(auto& en: attribute.getPopup()->getEnumeration()) { | ||||
|                     if(en.getValue().asReference() == value.asReference()) { | ||||
|                         value = Value::fromReference(value.asReference(), Value::WIRE_REFERENCE); | ||||
|                     } | ||||
|                 } | ||||
|                 if(value.isType(Value::UNDEFINED)) { | ||||
|                     errors.emplace_back(attr.span, "invalid value"); | ||||
|                 } | ||||
| 
 | ||||
|                 attributes.emplace_back(attribute.getName(), toType(attr.value), attribute); | ||||
|             } else { | ||||
|                 errors.emplace_back(attr.name.span, "unknown attribute"); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if(secondComponent == nullptr) { | ||||
|             schema->connections.push_back(std::make_shared<BusConnectionInstance>(firstComponent, attributes, bus, *connection)); | ||||
|         } else { | ||||
|             schema->connections.push_back(std::make_shared<DirectConnectionInstance>(firstComponent, secondComponent, attributes, bus, *connection)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return schema; | ||||
| } | ||||
| 
 | ||||
| shared_ptr<ComponentInstance> SchemaCreator::loadComponentInstance(InstanceNode instance, Library &library) { | ||||
| 
 | ||||
|     auto name = instance.name.value; | ||||
|     auto position = std::make_pair(instance.position->first.value, instance.position->second.value); | ||||
| 
 | ||||
|     auto component = library.getComponent(instance.component.value); | ||||
| 
 | ||||
|     // validate attributes
 | ||||
|     std::vector<InstanceAttribute> attributes; | ||||
|     for(auto& attr: instance.attributes) { | ||||
|         if(component.hasAttribute(attr.name.value, toType(attr.value.getType()))) { | ||||
|             auto attribute = component.getAttribute(attr.name.value); | ||||
|             attributes.emplace_back(attribute.getName(), toType(attr.value, attribute.getDefault().getType()), attribute); | ||||
|         } else { | ||||
|             errors.emplace_back(SourceError(attr.name.span, "unknown attribute")); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if(attributes.size() < component.getAttributes().size()) { | ||||
|         for(auto& attr: component.getAttributes()) { | ||||
|             if(std::count_if(attributes.begin(), attributes.end(), [&attr](InstanceAttribute& attribute){ return attr.getName() == attribute.name; }) == 0) { | ||||
|                 errors.emplace_back(SourceError(instance.span, "missing attribute '" + attr.getName() + "'")); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return std::make_shared<ComponentInstance>(name, attributes, position, component); | ||||
| } | ||||
| std::shared_ptr<BusInstance> SchemaCreator::loadBusInstance(InstanceNode instance, Library &library) { | ||||
| 
 | ||||
|     auto name = instance.name.value; | ||||
|     auto position = std::make_pair(instance.position->first.value, instance.position->second.value); | ||||
| 
 | ||||
|     auto bus = library.getBus(instance.component.value); | ||||
| 
 | ||||
|     long long size = 0; | ||||
|     if(instance.size) { | ||||
|         size = instance.size->value; | ||||
|     } | ||||
| 
 | ||||
|     return std::make_shared<BusInstance>(name, position, bus, static_cast<int>(size)); | ||||
| } | ||||
| 
 | ||||
| vector<Enumeration> SchemaCreator::createWireEnumeration(vector<Value> wireValues) { | ||||
|     vector<Enumeration> wires; | ||||
|     for(auto& wire: wireValues) { | ||||
|         if(wire.isType(Value::STRING)) { | ||||
|             wires.emplace_back(wire.asString(), wire); | ||||
|         } | ||||
|     } | ||||
|     return wires; | ||||
| } | ||||
| 
 | ||||
| std::optional<Attribute> SchemaCreator::createMemoryAttribute() { | ||||
|     return Attribute("_memory", Value::fromMemoryReference(nullopt), createMemoryPopup()); | ||||
| } | ||||
| 
 | ||||
|     std::optional<Popup> SchemaCreator::createMemoryPopup() { | ||||
|         return Popup("Postavi memoriju", "Postavi memoriju za izabrani procesor", Popup::AUTOMATIC, vector<Rule>{}, vector<Enumeration>{}); | ||||
|     } | ||||
| 
 | ||||
| } // namespace domain
 | ||||
							
								
								
									
										153
									
								
								comdel/domain/schemacreator.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								comdel/domain/schemacreator.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,153 @@ | ||||
| #ifndef DOMAIN_COMDEL_GENERATOR_H | ||||
| #define DOMAIN_COMDEL_GENERATOR_H | ||||
| 
 | ||||
| #include "library.h" | ||||
| #include "schema.h" | ||||
| 
 | ||||
| #include <set> | ||||
| 
 | ||||
| #include <comdel/parser/astnode.h> | ||||
| #include <comdel/parser/parsecontext.h> | ||||
| #include <comdel/parser/presult.h> | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
| struct ComdelContext { | ||||
|     std::vector<Attribute> attributes; | ||||
|     std::vector<std::string> wires; | ||||
|     std::string name; | ||||
|     bool inComponent; | ||||
|     bool inConnection; | ||||
|     bool inSingleAutomaticConnection; | ||||
|     bool inBus; | ||||
| 
 | ||||
|     ComdelContext(std::string name, bool inComponent, bool inConnection, bool inSingleAutomaticConnection, bool inBus) | ||||
|         : name(name), inComponent(inComponent), inConnection(inConnection), inSingleAutomaticConnection(inSingleAutomaticConnection), inBus(inBus) | ||||
|     {} | ||||
| 
 | ||||
|     bool doesAttributeExists(std::string name, Value::ValueType type) { | ||||
|         for(auto &attribute: attributes) { | ||||
|             if(attribute.getDefault().getType() == type && attribute.getName() == name) { | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     bool doesWireExists(std::string name) { | ||||
|         for(auto &w: wires) { | ||||
|             if(w == name) { | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| class SchemaCreator | ||||
| { | ||||
|     std::vector<ComdelContext> context; | ||||
| 
 | ||||
|     std::string name; | ||||
|     std::string libraryInfo; | ||||
|     std::string header; | ||||
|     std::string componentDirectory; | ||||
|     std::optional<std::string> componentHeader = nullopt; | ||||
|     std::vector<AddressSpace> addressSpaces; | ||||
|     std::vector<Component> components; | ||||
|     std::vector<Bus> buses; | ||||
|     std::vector<Connection> connections; | ||||
|     std::map<std::string, std::string> messages; | ||||
| 
 | ||||
| 
 | ||||
|     std::vector<SourceError> errors; | ||||
|     std::vector<FunctionValidator*> validators; | ||||
| 
 | ||||
|     std::optional<AddressSpace> loadAddressSpace(AddressSpaceNode node); | ||||
|     std::optional<Component> loadComponent(ComponentNode node); | ||||
|     std::optional<Attribute> loadAttribute(AttributeNode node); | ||||
|     std::optional<Rule> loadRule(RuleNode node); | ||||
|     std::optional<Condition> loadCondition(ConditionNode node); | ||||
|     std::optional<Popup> loadPopup(PopupNode node, std::string name, Value::ValueType type); | ||||
|     std::optional<Display> loadDisplay(DisplayNode node); | ||||
|     std::optional<Wire> loadWire(WireNode node); | ||||
|     std::optional<Pin> loadPin(PinNode pins); | ||||
|     PinConnection loadPinConnection(PinConnectionNode node); | ||||
|     std::optional<Connection> loadConnection(ConnectionNode node); | ||||
|     std::optional<Bus> loadBus(BusNode node); | ||||
| 
 | ||||
|     std::shared_ptr<ComponentInstance> loadComponentInstance(InstanceNode instance, Library &library); | ||||
|     std::shared_ptr<BusInstance> loadBusInstance(InstanceNode instance, Library &library); | ||||
| 
 | ||||
|     std::optional<Attribute> createMemoryAttribute(); | ||||
| 
 | ||||
|     std::optional<Bus> getBus(std::string name) { | ||||
|         for(auto &bus: buses) { | ||||
|             if(bus.getName() == name) { | ||||
|                 return bus; | ||||
|             } | ||||
|         } | ||||
|         return std::nullopt; | ||||
|     } | ||||
| 
 | ||||
|     std::optional<Pin> getComponentPin(std::string name, std::string pin) { | ||||
|         for(auto &c: components) { | ||||
|             if(c.getName() == name) { | ||||
|                 for(auto &p: c.getPins()) { | ||||
|                     if(p.getName() == pin) { | ||||
|                         return p; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return nullopt; | ||||
|     } | ||||
| 
 | ||||
|     bool hasAddressSpace(std::string name) { | ||||
|         for(auto &as: addressSpaces) { | ||||
|             if(as.getName() == name) { | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     void push(ComdelContext context) { | ||||
|         this->context.push_back(context); | ||||
|     } | ||||
|     void pushAdditional(std::string name) { | ||||
|         if(!this->context.empty()) { | ||||
|             this->context.push_back(current()); | ||||
|             current().name = name; | ||||
|         } else { | ||||
|             ComdelContext con(name, false, false, false, false); | ||||
|             push(con); | ||||
|         } | ||||
|     } | ||||
|     ComdelContext ¤t() { | ||||
|         return this->context[this->context.size() - 1]; | ||||
|     } | ||||
|     void pop() { | ||||
|         this->context.pop_back(); | ||||
|     } | ||||
| 
 | ||||
| public: | ||||
|     SchemaCreator(std::vector<FunctionValidator*> validators); | ||||
| 
 | ||||
|     std::vector<SourceError> getErrors() { | ||||
|         return errors; | ||||
|     } | ||||
| 
 | ||||
|     std::optional<Library> loadLibrary(LibraryNode node); | ||||
| 
 | ||||
|     Schema* loadSchema(SchemaNode node, Library &library); | ||||
| 
 | ||||
|     vector <Enumeration> createWireEnumeration(vector<Value> vector1); | ||||
| 
 | ||||
|     std::optional<Popup> createMemoryPopup(); | ||||
| }; | ||||
| 
 | ||||
| } // namespace domain
 | ||||
| 
 | ||||
| #endif // DOMAIN_COMDEL_GENERATOR_H
 | ||||
| @ -1,194 +1,176 @@ | ||||
| #include "value.h" | ||||
| 
 | ||||
| #include <string> | ||||
| #include <stdexcept> | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
|     std::string Value::string() { | ||||
|         switch (type) { | ||||
|             case INT: | ||||
|                 return std::to_string(intValue); | ||||
|             case BOOL: | ||||
|                 return boolValue ? "true" : "false"; | ||||
|             case STRING: | ||||
|                 return stringValue; | ||||
|             case NIL: | ||||
|                 return "null"; | ||||
|             case UNDEFINED: | ||||
|                 return "undefined"; | ||||
|             case ADDRESS_SPACE: | ||||
|                 return "AddressSpace::" + addressSpace->getName(); | ||||
|             case WIRE_REFERENCE: | ||||
|                 return "Wire::" + reference; | ||||
|             case ADDRESS_SPACE_REFERENCE: | ||||
|                 return "AddressSpace::" + reference; | ||||
|             case ATTRIBUTE_REFERENCE: | ||||
|                 return "Attribute::" + reference; | ||||
|             case MEMORY_REFERENCE: | ||||
|                 if (memoryReference.has_value()) { | ||||
|                     return "Memory::" + *memoryReference; | ||||
|                 } else { | ||||
|                     return "Memory::null"; | ||||
|                 } | ||||
|             default: | ||||
|                 return "unknown"; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     Value::ValueType Value::getType() { | ||||
|         return type; | ||||
|     } | ||||
| 
 | ||||
|     bool Value::isType(Value::ValueType _type) { | ||||
|         return type == _type; | ||||
|     } | ||||
| 
 | ||||
|     std::string Value::getTypename() { | ||||
|         switch (type) { | ||||
|             case Value::BOOL: | ||||
|                 return "bool"; | ||||
|             case Value::INT: | ||||
|                 return "int"; | ||||
|             case Value::STRING: | ||||
|                 return "string"; | ||||
|             case Value::ADDRESS_SPACE: | ||||
|             case Value::ADDRESS_SPACE_REFERENCE: | ||||
|                 return "address space"; | ||||
|             case Value::WIRE_REFERENCE: | ||||
|                 return "wire reference"; | ||||
|             case Value::ATTRIBUTE_REFERENCE: | ||||
|                 return "attribute"; | ||||
|             case Value::NIL: | ||||
|                 return "null"; | ||||
|             case Value::MEMORY: | ||||
|             case Value::MEMORY_REFERENCE: | ||||
|                 return "memory"; | ||||
|             case Value::UNDEFINED: | ||||
|                 return "undefined"; | ||||
|         } | ||||
|         return "unknown"; | ||||
|     } | ||||
| 
 | ||||
|     long long Value::asInt() { | ||||
|         if (isType(Value::INT)) { | ||||
|             return intValue; | ||||
|         } | ||||
|         throw std::runtime_error("expected 'int' but value contains '" + getTypename() + "'"); | ||||
|     } | ||||
| 
 | ||||
|     std::string Value::asString() { | ||||
|         if (isType(Value::STRING)) { | ||||
| std::string Value::string() { | ||||
|     switch (type) { | ||||
|         case INT: | ||||
|             return std::to_string(intValue); | ||||
|         case BOOL: | ||||
|             return boolValue ? "true" : "false"; | ||||
|         case STRING: | ||||
|             return stringValue; | ||||
|         } | ||||
|         throw std::runtime_error("expected 'string' but value contains '" + getTypename() + "'"); | ||||
|         case NIL: | ||||
|             return "null"; | ||||
|         case UNDEFINED: | ||||
|             return "undefined"; | ||||
|         case ADDRESS_SPACE: | ||||
|             return "AddressSpace::" + addressSpace->getName(); | ||||
|         case WIRE_REFERENCE: | ||||
|             return "Wire::" + reference; | ||||
|         case ADDRESS_SPACE_REFERENCE: | ||||
|             return "AddressSpace::" + reference; | ||||
|         case ATTRIBUTE_REFERENCE: | ||||
|             return "Attribute::" + reference; | ||||
|         default: | ||||
|             return "unknown"; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|     bool Value::asBool() { | ||||
|         if (isType(Value::BOOL)) { | ||||
|             return boolValue; | ||||
|         } | ||||
|         throw std::runtime_error("expected 'bool' but value contains '" + getTypename() + "'"); | ||||
|     } | ||||
| 
 | ||||
|     AddressSpace Value::asAddressSpace() { | ||||
|         if (isType(Value::ADDRESS_SPACE)) { | ||||
|             return *addressSpace; | ||||
|         } | ||||
|         throw std::runtime_error("expected 'address space' but value contains '" + getTypename() + "'"); | ||||
|     } | ||||
| Value::ValueType Value::getType() { | ||||
|     return type; | ||||
| } | ||||
| bool Value::isType(Value::ValueType type) { | ||||
|     return this->type == type; | ||||
| } | ||||
| 
 | ||||
|     std::string Value::asReference() { | ||||
|         if (isType(Value::WIRE_REFERENCE) || isType(Value::ADDRESS_SPACE_REFERENCE) || | ||||
|             isType(Value::ATTRIBUTE_REFERENCE) || isType(Value::UNDEFINED)) { | ||||
|             return reference; | ||||
|         } | ||||
|         throw std::runtime_error("expected 'reference' but value contains '" + getTypename() + "'"); | ||||
| long long Value::asInt() { | ||||
|     if(isType(Value::INT)) { | ||||
|         return intValue; | ||||
|     } | ||||
|     throw std::exception(); | ||||
| } | ||||
| std::string Value::asString() { | ||||
|     if(isType(Value::STRING)) { | ||||
|         return stringValue; | ||||
|     } | ||||
|     throw std::exception(); | ||||
| } | ||||
| bool Value::asBool() { | ||||
|     if(isType(Value::BOOL)) { | ||||
|         return boolValue; | ||||
|     } | ||||
|     throw std::exception(); | ||||
| } | ||||
| AddressSpace Value::asAddressSpace() { | ||||
|     if(isType(Value::ADDRESS_SPACE)) { | ||||
|         return *addressSpace; | ||||
|     } | ||||
|     throw std::exception(); | ||||
| } | ||||
| std::string Value::asReference() { | ||||
|     if(isType(Value::WIRE_REFERENCE) || isType(Value::ADDRESS_SPACE_REFERENCE) || isType(Value::ATTRIBUTE_REFERENCE) || isType(Value::UNDEFINED)) { | ||||
|         return reference; | ||||
|     } | ||||
|     throw std::exception(); | ||||
| } | ||||
| 
 | ||||
|     std::optional<std::string> Value::asMemoryReference() { | ||||
|         return memoryReference; | ||||
|     } | ||||
| 
 | ||||
| std::optional<std::string> Value::asMemoryReference() { | ||||
|     return memoryReference; | ||||
| } | ||||
| 
 | ||||
|     domain::ComponentInstance *Value::asMemory() { | ||||
|         return memory; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     void Value::setInt(long long value) { | ||||
|         if (isType(Value::INT)) { | ||||
|             this->intValue = value; | ||||
|         } else { | ||||
|             throw std::runtime_error("expected to set 'int' but value contains '" + getTypename() + "'"); | ||||
|         } | ||||
| void Value::setInt(long long value) { | ||||
|     if(isType(Value::INT)) { | ||||
|         this->intValue = value; | ||||
|     } | ||||
| 
 | ||||
|     void Value::setString(std::string value) { | ||||
|         if (isType(Value::STRING)) { | ||||
|             this->stringValue = value; | ||||
|         } else { | ||||
|             throw std::runtime_error("expected to set 'string' but value contains '" + getTypename() + "'"); | ||||
|         } | ||||
|     throw std::exception(); | ||||
| } | ||||
| void Value::setString(std::string value) { | ||||
|     if(isType(Value::STRING)) { | ||||
|         this->stringValue = value; | ||||
|     } | ||||
| 
 | ||||
|     void Value::setBool(bool value) { | ||||
|         if (isType(Value::BOOL)) { | ||||
|             this->boolValue = value; | ||||
|         } else { | ||||
|             throw std::runtime_error("expected to set 'bool' but value contains '" + getTypename() + "'"); | ||||
|         } | ||||
|     throw std::exception(); | ||||
| } | ||||
| void Value::setBool(bool value) { | ||||
|     if(isType(Value::BOOL)) { | ||||
|         this->boolValue = value; | ||||
|     } | ||||
| 
 | ||||
|     void Value::setReference(std::string value) { | ||||
|         if (isType(Value::WIRE_REFERENCE)) { | ||||
|             this->reference = value; | ||||
|         } else { | ||||
|             throw std::runtime_error("expected to set 'wire' but value contains '" + getTypename() + "'"); | ||||
|         } | ||||
|     throw std::exception(); | ||||
| } | ||||
| void Value::setReference(std::string value) { | ||||
|     if(isType(Value::WIRE_REFERENCE)) { | ||||
|         this->reference = value; | ||||
|     } | ||||
|     throw std::exception(); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|     Value Value::fromInt(long long value) { | ||||
|         Value val; | ||||
|         val.type = Value::INT; | ||||
|         val.intValue = value; | ||||
|         return val; | ||||
|     } | ||||
| Value Value::fromInt(long long value) { | ||||
|     Value val; | ||||
|     val.type = Value::INT; | ||||
|     val.intValue = value; | ||||
|     return val; | ||||
| } | ||||
| Value Value::fromString(std::string value) { | ||||
|     Value val; | ||||
|     val.type = Value::STRING; | ||||
|     val.stringValue = value; | ||||
|     return val; | ||||
| } | ||||
| Value Value::fromBool(bool value) { | ||||
|     Value val; | ||||
|     val.type = Value::BOOL; | ||||
|     val.boolValue = value; | ||||
|     return val; | ||||
| } | ||||
| Value Value::fromAddressSpace(AddressSpace addressSpace) { | ||||
|     Value val; | ||||
|     val.type = Value::ADDRESS_SPACE; | ||||
|     val.addressSpace = addressSpace; | ||||
|     return val; | ||||
| } | ||||
| Value Value::fromReference(std::string value, Value::ValueType type) { | ||||
|     Value val; | ||||
|     val.type = type; | ||||
|     val.reference = value; | ||||
|     return val; | ||||
| } | ||||
| 
 | ||||
|     Value Value::fromString(std::string value) { | ||||
|         Value val; | ||||
|         val.type = Value::STRING; | ||||
|         val.stringValue = value; | ||||
|         return val; | ||||
|     } | ||||
| Value Value::ofType(Value::ValueType type) { | ||||
|     Value val; | ||||
|     val.type = type; | ||||
|     return val; | ||||
| } | ||||
| 
 | ||||
|     Value Value::fromBool(bool value) { | ||||
|         Value val; | ||||
|         val.type = Value::BOOL; | ||||
|         val.boolValue = value; | ||||
|         return val; | ||||
|     } | ||||
| Value Value::fromNull() { | ||||
|     Value val; | ||||
|     val.type = Value::NIL; | ||||
|     return val; | ||||
| } | ||||
| 
 | ||||
|     Value Value::fromAddressSpace(AddressSpace addressSpace) { | ||||
|         Value val; | ||||
|         val.type = Value::ADDRESS_SPACE; | ||||
|         val.addressSpace = addressSpace; | ||||
|         return val; | ||||
|     } | ||||
| 
 | ||||
|     Value Value::fromReference(std::string value, Value::ValueType type) { | ||||
|         Value val; | ||||
|         val.type = type; | ||||
|         val.reference = value; | ||||
|         return val; | ||||
|     } | ||||
| 
 | ||||
|     Value Value::fromNull() { | ||||
|         Value val; | ||||
|         val.type = Value::NIL; | ||||
|         return val; | ||||
| std::string Value::stringify() { | ||||
|     switch (type) { | ||||
|         case INT: | ||||
|             return std::to_string(intValue); | ||||
|         case BOOL: | ||||
|             return boolValue ? "true" : "false"; | ||||
|         case STRING: | ||||
|             return "\"" + stringValue + "\""; | ||||
|         case NIL: | ||||
|             return "null"; | ||||
|         case WIRE_REFERENCE: | ||||
|         case ADDRESS_SPACE_REFERENCE: | ||||
|         case ATTRIBUTE_REFERENCE: | ||||
|             return reference; | ||||
|         case MEMORY_REFERENCE: | ||||
|             if(memoryReference->empty()) { | ||||
|                 return "null"; | ||||
|             } else { | ||||
|                 return memoryReference.value(); | ||||
|             } | ||||
|         default: | ||||
|             throw std::exception(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|     Value Value::fromMemoryReference(std::optional<std::string> value) { | ||||
|         Value val; | ||||
| @ -197,62 +179,11 @@ namespace domain { | ||||
|         return val; | ||||
|     } | ||||
| 
 | ||||
|     std::string Value::stringify() { | ||||
|         switch (type) { | ||||
|             case INT: | ||||
|                 return std::to_string(intValue); | ||||
|             case BOOL: | ||||
|                 return boolValue ? "true" : "false"; | ||||
|             case STRING: | ||||
|                 return "\"" + stringValue + "\""; | ||||
|             case NIL: | ||||
|                 return "null"; | ||||
|             case WIRE_REFERENCE: | ||||
|             case ADDRESS_SPACE_REFERENCE: | ||||
|             case ATTRIBUTE_REFERENCE: | ||||
|                 return reference; | ||||
|             case MEMORY_REFERENCE: | ||||
|                 if (memoryReference.has_value()) { | ||||
|                     return memoryReference.value(); | ||||
|                 } else { | ||||
|                     return "null"; | ||||
|                 } | ||||
|             default: | ||||
|                 throw std::runtime_error("unknown type couldn't stringify '" + getTypename() + "'"); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     Value Value::ofType(Value::ValueType type) { | ||||
|     Value Value::fromMemory(domain::ComponentInstance *memory) { | ||||
|         Value val; | ||||
|         val.type = type; | ||||
|         val.type = MEMORY; | ||||
|         val.memory = memory; | ||||
|         return val; | ||||
|     } | ||||
| 
 | ||||
|     bool Value::equals(Value value) { | ||||
|         if (value.getType() == type) { | ||||
|             switch (type) { | ||||
|                 case INT: | ||||
|                     return value.asInt() == intValue; | ||||
|                 case STRING: | ||||
|                     return value.asString() == stringValue; | ||||
|                 case NIL: | ||||
|                 case UNDEFINED: | ||||
|                     return true; | ||||
|                 case WIRE_REFERENCE: | ||||
|                 case ATTRIBUTE_REFERENCE: | ||||
|                 case ADDRESS_SPACE_REFERENCE: | ||||
|                     return value.asReference() == reference; | ||||
|                 case MEMORY_REFERENCE: | ||||
|                     return value.asMemoryReference() == memoryReference; | ||||
|                 case MEMORY: | ||||
|                     return value.asMemory() == memory; | ||||
|                 case BOOL: | ||||
|                     return value.asBool() == boolValue; | ||||
|                 default: | ||||
|                     return false; | ||||
|             } | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
| } // namespace domain
 | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| #ifndef DOMAIN_VALUE_H | ||||
| #define DOMAIN_VALUE_H | ||||
| 
 | ||||
| #include "address_space.h" | ||||
| #include "addressspace.h" | ||||
| 
 | ||||
| #include <string> | ||||
| #include <optional> | ||||
| @ -11,88 +11,99 @@ namespace domain { | ||||
| 
 | ||||
|     class ComponentInstance; | ||||
| 
 | ||||
|     class Value { | ||||
|     public: | ||||
|         enum ValueType { | ||||
|             INT, | ||||
|             STRING, | ||||
|             BOOL, | ||||
|             ADDRESS_SPACE, | ||||
|             ADDRESS_SPACE_REFERENCE, | ||||
|             ATTRIBUTE_REFERENCE, | ||||
|             MEMORY_REFERENCE, | ||||
|             MEMORY, | ||||
|             WIRE_REFERENCE, | ||||
|             NIL, | ||||
|             UNDEFINED, | ||||
|         }; | ||||
| 
 | ||||
|     private: | ||||
|         long long intValue = 0; | ||||
|         std::string stringValue; | ||||
|         bool boolValue = false; | ||||
|         std::optional<AddressSpace> addressSpace = std::nullopt; | ||||
|         std::string reference; | ||||
|         domain::ComponentInstance *memory = nullptr; | ||||
| 
 | ||||
|         std::optional<std::string> memoryReference = std::nullopt; | ||||
| 
 | ||||
|         ValueType type = UNDEFINED; | ||||
| 
 | ||||
|     public: | ||||
| 
 | ||||
|         Value() = default; | ||||
| 
 | ||||
|         bool equals(Value value); | ||||
| 
 | ||||
|         std::string string(); | ||||
|         std::string getTypename(); | ||||
| 
 | ||||
|         ValueType getType(); | ||||
| 
 | ||||
|         bool isType(ValueType type); | ||||
| 
 | ||||
|         long long asInt(); | ||||
| 
 | ||||
|         std::string asString(); | ||||
| 
 | ||||
|         bool asBool(); | ||||
| 
 | ||||
|         std::string asReference(); | ||||
| 
 | ||||
|         std::optional<std::string> asMemoryReference(); | ||||
| 
 | ||||
|         domain::ComponentInstance *asMemory(); | ||||
| 
 | ||||
|         AddressSpace asAddressSpace(); | ||||
| 
 | ||||
|         void setInt(long long intValue); | ||||
| 
 | ||||
|         void setString(std::string value); | ||||
| 
 | ||||
|         void setBool(bool value); | ||||
| 
 | ||||
|         void setReference(std::string value); | ||||
| 
 | ||||
|         std::string stringify(); | ||||
| 
 | ||||
|         static Value fromInt(long long value); | ||||
| 
 | ||||
|         static Value fromString(std::string value); | ||||
| 
 | ||||
|         static Value fromBool(bool value); | ||||
| 
 | ||||
|         static Value fromNull(); | ||||
| 
 | ||||
|         static Value fromAddressSpace(AddressSpace addressSpace); | ||||
| 
 | ||||
|         static Value fromReference(std::string value, ValueType type); | ||||
| 
 | ||||
|         static Value fromMemoryReference(std::optional<std::string> memoryReference); | ||||
| 
 | ||||
|         static Value ofType(ValueType type); | ||||
| class Value | ||||
| { | ||||
| public: | ||||
|     enum ValueType { | ||||
|         INT, | ||||
|         STRING, | ||||
|         BOOL, | ||||
|         ADDRESS_SPACE, | ||||
|         ADDRESS_SPACE_REFERENCE, | ||||
|         ATTRIBUTE_REFERENCE, | ||||
|         MEMORY_REFERENCE, | ||||
|         MEMORY, | ||||
|         WIRE_REFERENCE, | ||||
|         NIL, | ||||
|         UNDEFINED, | ||||
|     }; | ||||
| 
 | ||||
| private: | ||||
|     long long intValue; | ||||
|     std::string stringValue; | ||||
|     bool boolValue; | ||||
|     std::optional<AddressSpace> addressSpace; | ||||
|     std::string reference; | ||||
|     domain::ComponentInstance *memory; | ||||
| 
 | ||||
|     std::optional<std::string> memoryReference; | ||||
| 
 | ||||
|     ValueType type; | ||||
| 
 | ||||
| public: | ||||
| 
 | ||||
|     Value() { | ||||
|         this->type = UNDEFINED; | ||||
|     } | ||||
| 
 | ||||
|     bool equals(Value value) { | ||||
|         if(value.getType() == type) { | ||||
|             switch (type) { | ||||
|                 case INT: | ||||
|                     return value.asInt() == intValue; | ||||
|                 case STRING: | ||||
|                     return value.asString() == stringValue; | ||||
|                 case NIL: | ||||
|                 case UNDEFINED: | ||||
|                     return true; | ||||
|                 case WIRE_REFERENCE: | ||||
|                 case ATTRIBUTE_REFERENCE: | ||||
|                 case ADDRESS_SPACE_REFERENCE: | ||||
|                     return value.asReference() == reference; | ||||
|                 case MEMORY_REFERENCE: | ||||
|                     return value.asMemoryReference() == memoryReference; | ||||
|                 case MEMORY: | ||||
|                     return value.asMemory() == memory; | ||||
|                 case BOOL: | ||||
|                     return value.asBool() == boolValue; | ||||
|                 default: | ||||
|                     return false; | ||||
|             } | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     std::string string(); | ||||
| 
 | ||||
|     ValueType getType(); | ||||
|     bool isType(ValueType type); | ||||
| 
 | ||||
|     long long asInt(); | ||||
|     std::string asString(); | ||||
|     bool asBool(); | ||||
|     std::string asReference(); | ||||
|     std::optional<std::string> asMemoryReference(); | ||||
|     domain::ComponentInstance* asMemory(); | ||||
|     AddressSpace asAddressSpace(); | ||||
| 
 | ||||
|     void setInt(long long intValue); | ||||
|     void setString(std::string value); | ||||
|     void setBool(bool value); | ||||
|     void setReference(std::string value); | ||||
| 
 | ||||
|     std::string stringify(); | ||||
| 
 | ||||
|     static Value fromInt(long long value); | ||||
|     static Value fromString(std::string value); | ||||
|     static Value fromBool(bool value); | ||||
|     static Value fromNull(); | ||||
|     static Value fromAddressSpace(AddressSpace addressSpace); | ||||
|     static Value fromReference(std::string value, ValueType type); | ||||
|     static Value ofType(ValueType type); | ||||
|     static Value fromMemoryReference(std::optional<std::string> memoryReference); | ||||
|     static Value fromMemory(domain::ComponentInstance *memory); | ||||
| }; | ||||
| 
 | ||||
| } // namespace domain
 | ||||
| 
 | ||||
| #endif // DOMAIN_VALUE_H
 | ||||
|  | ||||
							
								
								
									
										10
									
								
								comdel/domain/wireinstance.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								comdel/domain/wireinstance.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | ||||
| #include "wireinstance.h" | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
| WireInstance::WireInstance(std::string name, Display display, std::pair<int, int> position) | ||||
|     : name(name), display(display), position(position) | ||||
| {} | ||||
| 
 | ||||
| 
 | ||||
| } // namespace domain
 | ||||
							
								
								
									
										24
									
								
								comdel/domain/wireinstance.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								comdel/domain/wireinstance.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | ||||
| #ifndef DOMAIN_WIRE_INSTANCE_H | ||||
| #define DOMAIN_WIRE_INSTANCE_H | ||||
| 
 | ||||
| #include "display.h" | ||||
| 
 | ||||
| #include <string> | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| namespace domain { | ||||
| 
 | ||||
| class WireInstance | ||||
| { | ||||
| public: | ||||
|     std::string name; | ||||
|     Display display; | ||||
|     std::pair<int, int> position; | ||||
| 
 | ||||
|     WireInstance(std::string name, Display display, std::pair<int, int> position); | ||||
| }; | ||||
| 
 | ||||
| } // namespace domain
 | ||||
| 
 | ||||
| #endif // DOMAIN_WIREINSTANCE_H
 | ||||
| @ -1,172 +0,0 @@ | ||||
| #include "ast_nodes.h" | ||||
| 
 | ||||
| /*************************** NUMBER NODE ********************************/ | ||||
| 
 | ||||
| NumberNode::NumberNode(const std::string &expression) { | ||||
|     if (expression.size() > 2) { | ||||
|         if (expression.substr(0, 2) == "0x") { | ||||
|             this->value = std::stoll(expression, nullptr, 16); | ||||
|         } else if (expression.substr(0, 2) == "0b") { | ||||
|             this->value = std::stoll(expression, nullptr, 2); | ||||
|         } else { | ||||
|             this->value = std::stoll(expression, nullptr, 10); | ||||
|         } | ||||
|     } else { | ||||
|         this->value = std::stoll(expression, nullptr, 10); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /*************************** COLOR NODE *********************************/ | ||||
| 
 | ||||
| ColorNode::ColorNode(const std::string &expression) { | ||||
|     auto value = expression.substr(1); | ||||
|     color.r = std::stoul(value.substr(0, 2), nullptr, 16); | ||||
|     color.g = std::stoul(value.substr(2, 4), nullptr, 16); | ||||
|     color.b = std::stoul(value.substr(4, 6), nullptr, 16); | ||||
|     color.a = 255; | ||||
|     if(value.length() == 8) { | ||||
|         color.a = std::stoul(value.substr(6,8), nullptr, 16); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /*************************** STRING NODE ********************************/ | ||||
| 
 | ||||
| std::string StringNode::asString() { | ||||
|     return value.substr(1, value.length() - 2); | ||||
| } | ||||
| 
 | ||||
| /*************************** VALUE NODE ********************************/ | ||||
| 
 | ||||
| ValueNode::ValueType ValueNode::getType() const { | ||||
|     return type.value; | ||||
| } | ||||
| 
 | ||||
| long long int ValueNode::asInt() { | ||||
|     if (is(INT)) { | ||||
|         return intValue.value(); | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| std::string ValueNode::asString() { | ||||
|     if (is(STRING)) { | ||||
|         return stringValue.value(); | ||||
|     } | ||||
|     return ""; | ||||
| } | ||||
| 
 | ||||
| std::string ValueNode::asIdentifier() { | ||||
|     if (is(IDENTIFIER) || is(WIRE)) { | ||||
|         return identifierValue.value(); | ||||
|     } | ||||
|     return ""; | ||||
| } | ||||
| 
 | ||||
| Color ValueNode::asColor() { | ||||
|     if (is(COLOR)) { | ||||
|         return colorValue.value(); | ||||
|     } | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| bool ValueNode::asBool() { | ||||
|     if (is(BOOL)) { | ||||
|         return boolValue.value(); | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| bool ValueNode::is(ValueNode::ValueType valueType) { | ||||
|     return type.value == valueType; | ||||
| } | ||||
| 
 | ||||
| ValueNode ValueNode::ofBool(bool _value) { | ||||
|     ValueNode value; | ||||
|     value.type = EnumNode(BOOL); | ||||
|     value.boolValue = std::optional<bool>(_value); | ||||
|     return value; | ||||
| } | ||||
| 
 | ||||
| ValueNode ValueNode::ofInt(long long int _value) { | ||||
|     ValueNode value; | ||||
|     value.type = EnumNode(INT); | ||||
|     value.intValue = std::optional<long long>(_value); | ||||
|     return value; | ||||
| } | ||||
| 
 | ||||
| ValueNode ValueNode::ofString(std::string _value) { | ||||
|     ValueNode value; | ||||
|     value.type = EnumNode(STRING); | ||||
|     value.stringValue = std::optional<std::string>(_value); | ||||
|     return value; | ||||
| } | ||||
| 
 | ||||
| ValueNode ValueNode::ofIdentifier(std::string _value) { | ||||
|     ValueNode value; | ||||
|     value.type = EnumNode(IDENTIFIER); | ||||
|     value.identifierValue = std::optional<std::string>(_value); | ||||
|     return value; | ||||
| } | ||||
| 
 | ||||
| ValueNode ValueNode::ofNull() { | ||||
|     ValueNode value; | ||||
|     value.type = EnumNode(NIL); | ||||
|     return value; | ||||
| } | ||||
| 
 | ||||
| ValueNode ValueNode::ofColor(Color color) { | ||||
|     ValueNode value; | ||||
|     value.type = EnumNode(COLOR); | ||||
|     value.colorValue = color; | ||||
|     return value; | ||||
| } | ||||
| 
 | ||||
| ValueNode ValueNode::ofWire(std::optional<std::string> _value) { | ||||
|     ValueNode value; | ||||
|     value.type = EnumNode(WIRE); | ||||
|     value.identifierValue = _value; | ||||
|     return value; | ||||
| } | ||||
| 
 | ||||
| ValueNode ValueNode::ofMemory(std::optional<std::string> _value) { | ||||
|     ValueNode value; | ||||
|     value.type = EnumNode(MEMORY); | ||||
|     value.identifierValue = _value; | ||||
|     return value; | ||||
| } | ||||
| 
 | ||||
| /*************************** DisplayItem NODE ********************************/ | ||||
| 
 | ||||
| std::optional<long long int> DisplayItemNode::asInt(const std::string &property, long long int _default) { | ||||
|     auto prop = getProperty(property); | ||||
|     if(prop.has_value()) { | ||||
|         return prop->value.is(ValueNode::INT) ? std::optional(prop->value.asInt()) : std::nullopt; | ||||
|     } | ||||
|     return _default; | ||||
| } | ||||
| 
 | ||||
| std::optional<Color> DisplayItemNode::asColor(const std::string &property, Color _default) { | ||||
|     auto prop = getProperty(property); | ||||
|     if(prop.has_value()) { | ||||
|         return prop->value.is(ValueNode::COLOR) ? std::optional(prop->value.asColor()) : std::nullopt; | ||||
|     } | ||||
|     return _default; | ||||
| } | ||||
| 
 | ||||
| std::optional<std::string> DisplayItemNode::asString(const std::string &property, std::string _default) { | ||||
|     auto prop = getProperty(property); | ||||
|     if(prop.has_value()) { | ||||
|         return prop->value.is(ValueNode::STRING) ? std::optional(prop->value.asString()) : std::nullopt; | ||||
|     } | ||||
|     return _default; | ||||
| } | ||||
| 
 | ||||
| std::optional<PropertyNode> DisplayItemNode::getProperty(const std::string &property) { | ||||
|     for(auto &prop: values) { | ||||
|         if(prop.key.value == property) { | ||||
|             return prop; | ||||
|         } | ||||
|     } | ||||
|     return std::nullopt; | ||||
| } | ||||
| @ -1,553 +0,0 @@ | ||||
| #ifndef AST_NODE_H | ||||
| #define AST_NODE_H | ||||
| 
 | ||||
| #include "token.h" | ||||
| #include "color.h" | ||||
| #include "source_error.h" | ||||
| #include <optional> | ||||
| #include <utility> | ||||
| #include <vector> | ||||
| 
 | ||||
| /*****************************************************************************
 | ||||
|  *                            BASE TYPES                                     * | ||||
|  *****************************************************************************/ | ||||
| 
 | ||||
| /**
 | ||||
|  * AST base class, all AST node classes extend this class. Class contains basic | ||||
|  * information about nodes location in file. | ||||
|  */ | ||||
| class AstNode { | ||||
| public: | ||||
|     /** Contains information about where in source file given node is located */ | ||||
|     Span span; | ||||
| 
 | ||||
|     AstNode() = default; | ||||
|     AstNode(AstNode &&) = default; | ||||
|     AstNode &operator=(AstNode &&) = default; | ||||
|     AstNode(const AstNode &) = default; | ||||
|     AstNode &operator=(const AstNode &) = default; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * AST base enum class, | ||||
|  * Used to represent AST enums | ||||
|  * */ | ||||
| template<typename T> | ||||
| struct EnumNode : public AstNode { | ||||
|     EnumNode() = default; | ||||
| 
 | ||||
|     explicit EnumNode(T value) : value(value) {} | ||||
| 
 | ||||
|     T value; | ||||
| }; | ||||
| 
 | ||||
| /** Represents string
 | ||||
|  * value contains quote-marks ("" or '' depending on string type) | ||||
|  * */ | ||||
| struct StringNode : public AstNode { | ||||
|     /** String including quote-marks*/ | ||||
|     std::string value; | ||||
| 
 | ||||
|     /** Returns string without quote-marks */ | ||||
|     std::string asString(); | ||||
| }; | ||||
| 
 | ||||
| /** Represents identifiers */ | ||||
| struct IdentifierNode : public AstNode { | ||||
|     std::string value; | ||||
| }; | ||||
| 
 | ||||
| /** Represents all numbers used
 | ||||
|  * All numbers must fit into long long int | ||||
|  * */ | ||||
| struct NumberNode : public AstNode { | ||||
|     long long int value = 0; | ||||
| 
 | ||||
|     explicit NumberNode(const std::string &expression); | ||||
| 
 | ||||
|     NumberNode() = default; | ||||
| }; | ||||
| 
 | ||||
| /** Represents color
 | ||||
|  * color comes in two formats #RRGGBB or #RRGGBBAA (AA representing opacity) | ||||
|  * */ | ||||
| struct ColorNode : public AstNode { | ||||
|     Color color; | ||||
| 
 | ||||
|     explicit ColorNode(const std::string &expression); | ||||
| 
 | ||||
|     ColorNode() = default; | ||||
| }; | ||||
| 
 | ||||
| /** Represents ordered number pair */ | ||||
| struct NumberPairNode : public AstNode { | ||||
|     NumberNode first; | ||||
|     NumberNode second; | ||||
| 
 | ||||
|     NumberPairNode(NumberNode first, NumberNode second) : first(first), second(second) {} | ||||
| 
 | ||||
|     NumberPairNode() = default; | ||||
| }; | ||||
| 
 | ||||
| /** Represents generic value
 | ||||
|  * Because attributes can contain different value types, | ||||
|  * this allows us to use one generic type for all attributes | ||||
|  * */ | ||||
| class ValueNode : public AstNode { | ||||
| public: | ||||
|     enum ValueType { | ||||
|         /** Stores same content as NumberNode */ | ||||
|         INT, | ||||
|         /** Stores same content as StringNode */ | ||||
|         STRING, | ||||
|         /** Stores true or false */ | ||||
|         BOOL, | ||||
|         /** Stores wire nam or null */ | ||||
|         WIRE, | ||||
|         /** Default type assigned when node value is of type IdentifierNode and more correct type is assigned later */ | ||||
|         IDENTIFIER, | ||||
|         /** Stores memory name or null */ | ||||
|         MEMORY, | ||||
|         /** Stores null */ | ||||
|         NIL, | ||||
|         /** Store same content as ColorNode */ | ||||
|         COLOR, | ||||
|     }; | ||||
| 
 | ||||
| private: | ||||
|     /** Type determines what is stored inside ValueNode */ | ||||
|     EnumNode<ValueType> type = EnumNode(NIL); | ||||
|     /** All possible values for ValueNode are stored inside optionals */ | ||||
|     std::optional<long long> intValue = std::nullopt; | ||||
|     std::optional<std::string> stringValue = std::nullopt; | ||||
|     std::optional<bool> boolValue = std::nullopt; | ||||
|     std::optional<std::string> identifierValue = std::nullopt; | ||||
|     std::optional<Color> colorValue = std::nullopt; | ||||
| 
 | ||||
| public: | ||||
|     ValueNode() = default; | ||||
| 
 | ||||
|     ValueType getType() const; | ||||
| 
 | ||||
|     /** Checks ValueNode is of requested type and returns it or returns default value for given type*/ | ||||
|     long long int asInt(); | ||||
|     std::string asString(); | ||||
|     std::string asIdentifier(); | ||||
|     Color asColor(); | ||||
|     bool asBool(); | ||||
| 
 | ||||
|     /** Returns true if ValueNode is of given valueType */ | ||||
|     bool is(ValueType valueType); | ||||
| 
 | ||||
|     /** Static methods used to generate ValueNodes of requested type */ | ||||
|     static ValueNode ofBool(bool _value); | ||||
|     static ValueNode ofInt(long long _value); | ||||
|     static ValueNode ofString(std::string _value); | ||||
|     static ValueNode ofIdentifier(std::string _value); | ||||
|     static ValueNode ofMemory(std::optional<std::string> _value); | ||||
|     static ValueNode ofNull(); | ||||
|     static ValueNode ofColor(Color color); | ||||
|     static ValueNode ofWire(std::optional<std::string> _value); | ||||
| }; | ||||
| 
 | ||||
| /** Represents an identifier-value pair*/ | ||||
| struct PropertyNode : public AstNode { | ||||
|     IdentifierNode key; | ||||
|     ValueNode value; | ||||
| 
 | ||||
|     PropertyNode() = default; | ||||
|     PropertyNode(IdentifierNode key, ValueNode value): key(key), value(value) {} | ||||
| }; | ||||
| 
 | ||||
| /** Represents a string-value pair */ | ||||
| struct StringPropertyNode : public AstNode { | ||||
|     StringNode key; | ||||
|     ValueNode value; | ||||
| 
 | ||||
|     StringPropertyNode() = default; | ||||
|     StringPropertyNode(StringNode key, ValueNode value): key(key), value(value) {} | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| /*****************************************************************************
 | ||||
|  *                            RULE TYPES                                     * | ||||
|  *****************************************************************************/ | ||||
| 
 | ||||
| struct IfStatementNode; | ||||
| 
 | ||||
| /** Represents validation rule
 | ||||
|  * Rules are made from a list of | ||||
|  * if - else if statements | ||||
|  * */ | ||||
| struct RuleNode : public AstNode { | ||||
|     std::vector<IfStatementNode> statements; | ||||
| }; | ||||
| 
 | ||||
| /** Represents condition inside if statement
 | ||||
|  * Every condition is made from optional negation operator ! | ||||
|  * Function called and list of function parameters | ||||
|  * */ | ||||
| struct ConditionNode { | ||||
|     bool negated; | ||||
|     IdentifierNode functionName; | ||||
|     std::vector<ValueNode> params; | ||||
| }; | ||||
| 
 | ||||
| /** Represents action executed inside if statement
 | ||||
|  * */ | ||||
| struct ActionNode : public AstNode { | ||||
|     /** There are two types of action determined by action type */ | ||||
|     enum ActionType { | ||||
|         /** Error actions represent invalid state and cause validation to fail */ | ||||
|         ERROR, | ||||
|         /** Warning actions represent states that can cause issue when simulating
 | ||||
|          * model but models created with it are still valid | ||||
|          * */ | ||||
|         WARNING | ||||
|     }; | ||||
| 
 | ||||
|     EnumNode<ActionType> type; | ||||
|     /** Message used if condition is fulfilled */ | ||||
|     StringNode message; | ||||
| }; | ||||
| 
 | ||||
| /** If statements represents one validation check inside rule */ | ||||
| struct IfStatementNode : public AstNode { | ||||
|     ConditionNode condition; | ||||
|     ActionNode action; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| /*****************************************************************************
 | ||||
|  *                            ATTRIBUTE TYPES                                * | ||||
|  *****************************************************************************/ | ||||
| 
 | ||||
| /** Represents popup dialog used to modified attribute inside which it is defined
 | ||||
|  * */ | ||||
| struct PopupNode : public AstNode { | ||||
|     /** Determines type of popup*/ | ||||
|     enum PopupType { | ||||
|         /** Automatic popup is opened when component or connection containing it is defined */ | ||||
|         AUTOMATIC, | ||||
|         /** On demand popups are opened on user request usually from context menus*/ | ||||
|         ON_DEMAND | ||||
|     }; | ||||
| 
 | ||||
|     std::optional<EnumNode<PopupType>> type; | ||||
|     /** Title of popup */ | ||||
|     std::optional<StringNode> title; | ||||
|     /** Text of popup */ | ||||
|     std::optional<StringNode> text; | ||||
| 
 | ||||
|     /** If popup contains an enumeration*/ | ||||
|     bool enumerated; | ||||
|     std::vector<StringPropertyNode> enumeration; | ||||
| 
 | ||||
|     /** Validation rules for given popup */ | ||||
|     std::vector<RuleNode> rules; | ||||
| }; | ||||
| 
 | ||||
| /** Represents component or connection attribute
 | ||||
|  * Attributes are values that can programmatically be changed | ||||
|  * if popup is defined | ||||
|  * */ | ||||
| struct AttributeNode : public AstNode { | ||||
|     /** Type of attribute */ | ||||
|     ValueNode::ValueType type; | ||||
|     /** Name of attribute */ | ||||
|     IdentifierNode name; | ||||
|     /** Display name */ | ||||
|     std::optional<StringNode> displayName; | ||||
|     /** Default type of attribute */ | ||||
|     std::optional<ValueNode> defaultValue; | ||||
|     /** Popup used to change attribute value */ | ||||
|     std::optional<PopupNode> popup; | ||||
| }; | ||||
| 
 | ||||
| /*****************************************************************************
 | ||||
|  *                            DISPLAY TYPES                                  * | ||||
|  *****************************************************************************/ | ||||
| 
 | ||||
| struct DisplayItemNode; | ||||
| 
 | ||||
| /** Represents how a component or bus is rendered
 | ||||
|  * Display is made from an list of display items | ||||
|  * */ | ||||
| struct DisplayNode : public AstNode { | ||||
|     std::vector<DisplayItemNode> items; | ||||
| }; | ||||
| 
 | ||||
| /** DisplayItem represents one rendered item
 | ||||
|  * in source code items are defined similar to json objects | ||||
|  * eg. | ||||
|  * @code rect { | ||||
|  *  x: 100; | ||||
|  *  y: 100; | ||||
|  *  w: 100; | ||||
|  *  h: 100; | ||||
|  *  fillColor: #123456 | ||||
|  * } | ||||
|  * */ | ||||
| struct DisplayItemNode : public AstNode { | ||||
|     /** Contains type of display item */ | ||||
|     IdentifierNode type; | ||||
|     /** Contains all property nodes */ | ||||
|     std::vector<PropertyNode> values; | ||||
| 
 | ||||
|     /** Returns value of requested property
 | ||||
|      * If requested property doesn't exists default value is returned (eg. asInt is called but PropertyNode contains string) | ||||
|      * If value of requested property is different than expected nullopt is retured | ||||
|      * */ | ||||
|     std::optional<long long int> asInt(const std::string &property, long long int _default = 0); | ||||
|     std::optional<Color> asColor(const std::string &property, Color _default = Color(0, 0, 0)); | ||||
|     std::optional<std::string> asString(const std::string &property, std::string _default = ""); | ||||
| 
 | ||||
| private: | ||||
|     std::optional<PropertyNode> getProperty(const std::string &property); | ||||
| }; | ||||
| 
 | ||||
| /*****************************************************************************
 | ||||
|  *                            LIBRARY TYPES                                  * | ||||
|  *****************************************************************************/ | ||||
| 
 | ||||
| /** Represents AddressSpaces
 | ||||
|  * Address spaces are defined with their name and address range | ||||
|  * */ | ||||
| struct AddressSpaceNode : public AstNode { | ||||
|     IdentifierNode name; | ||||
|     /** Range represent which addresses are available for components that use memory space [first, second> */ | ||||
|     NumberPairNode range; | ||||
| }; | ||||
| 
 | ||||
| /** Pins are used to create component-component or component-bus connections */ | ||||
| struct PinNode : public AstNode { | ||||
|     /** Determines pin type, pin types currently only affect how pins are rendered */ | ||||
|     enum PinType { | ||||
|         IN_OUT, | ||||
|         IN, | ||||
|         OUT | ||||
|     }; | ||||
| 
 | ||||
|     /** Name of pin */ | ||||
|     IdentifierNode name; | ||||
|     /** Type of pin */ | ||||
|     EnumNode<PinType> type; | ||||
|     /** Tooltip content displayed on hover over pin */ | ||||
|     std::optional<StringNode> tooltip; | ||||
|     /** If present this means pin must be connected to another component or bus to create connection
 | ||||
|      * Connection contains error message shown | ||||
|      * */ | ||||
|     std::optional<StringNode> connection; | ||||
|     /** Determines how the pin is displayed */ | ||||
|     std::optional<DisplayNode> display; | ||||
|     /** If pin connection is optional it requires list of wires used to populate comdel model */ | ||||
|     std::optional<std::vector<ValueNode>> wires; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * Represents COMDEL component | ||||
|  * */ | ||||
| struct ComponentNode : public AstNode { | ||||
|     /** Determines type of component */ | ||||
|     enum ComponentType { | ||||
|         /** Generic component */ | ||||
|         OTHER, | ||||
|         /** Represents processor, all processors have implicit attribute _memory if type memory
 | ||||
|          * used when generating COMDEL model to connect memories and processors | ||||
|          */ | ||||
|         PROCESSOR, | ||||
|         /** Represents memory, all components of type memory can be selected in _memory attribute of processor */ | ||||
|         MEMORY | ||||
|     }; | ||||
| 
 | ||||
|     /** Component name */ | ||||
|     IdentifierNode name; | ||||
|     /** Component name */ | ||||
|     std::optional<StringNode> displayName; | ||||
|     /** Tooltip displayed on hover */ | ||||
|     std::optional<StringNode> tooltip; | ||||
|     /** Contains path to COMDEL source containing current component */ | ||||
|     std::optional<StringNode> source; | ||||
|     /** Type of component */ | ||||
|     EnumNode<ComponentType> type; | ||||
|     /** List of component level rules */ | ||||
|     std::vector<RuleNode> rules; | ||||
|     /** Default used to name instances */ | ||||
|     std::optional<IdentifierNode> instanceName; | ||||
|     /** Count determines number of instances allowed in a schema */ | ||||
|     std::optional<NumberPairNode> count; | ||||
|     /** Display determines how component is rendered */ | ||||
|     std::optional<DisplayNode> display; | ||||
|     /** List of all pins */ | ||||
|     std::vector<PinNode> pins; | ||||
|     /** List of all attributes */ | ||||
|     std::vector<AttributeNode> attributes; | ||||
| }; | ||||
| 
 | ||||
| /** WireNode represents COMDEL wire
 | ||||
|  * */ | ||||
| struct WireNode : public AstNode { | ||||
|     /** Determines type of wires */ | ||||
|     enum WireType { | ||||
|         /** Generic wire */ | ||||
|         WIRE, | ||||
|         /** wired_and can have multiple sources, that are ANDed together */ | ||||
|         WIRED_AND, | ||||
|         /** wired_and can have multiple sources, that are ORed together */ | ||||
|         WIRED_OR, | ||||
|         /** r_wire can remain unconnected */ | ||||
|         R_WIRE | ||||
|     }; | ||||
|     EnumNode<WireType> type; | ||||
|     /** Name of wire */ | ||||
|     IdentifierNode name; | ||||
|     /** Number of bits inside of a wire */ | ||||
|     NumberNode size; | ||||
| 
 | ||||
|     /** If wire is visible or hidden, this determines how wires are generated in COMDEL */ | ||||
|     bool hidden = false; | ||||
| 
 | ||||
|     /** If wire isn't connected to anything it is replaced with terminate with terminateWith value */ | ||||
|     bool hasTerminateWith = false; | ||||
|     ValueNode terminateWith; | ||||
| }; | ||||
| 
 | ||||
| /** Buses dont exist in COMDEL but they are useful
 | ||||
|  * as they allow us to connect multiple COMDEL wires together | ||||
|  * */ | ||||
| struct BusNode : public AstNode { | ||||
|     enum BusType { | ||||
|         /** This busses connect two components */ | ||||
|         AUTOMATIC, | ||||
|         /**
 | ||||
|          * This busses allow us to connect multiple component together using one bus | ||||
|          * */ | ||||
|         REGULAR, | ||||
|         /** This busses connect two components,
 | ||||
|          * they differ from automatic as they allow us to connect same pins multiple times */ | ||||
|         SINGLE_AUTOMATIC | ||||
|     }; | ||||
| 
 | ||||
|     EnumNode<BusType> type; | ||||
|     /** Bus name */ | ||||
|     IdentifierNode name; | ||||
|     /** Display name */ | ||||
|     std::optional<StringNode> displayName; | ||||
|     /** Default used to name instances */ | ||||
|     std::optional<IdentifierNode> instanceName; | ||||
|     /** Tooltip displayed on hover */ | ||||
|     std::optional<StringNode> tooltip; | ||||
|     /** Count determines number of instances allowed in a schema */ | ||||
|     std::optional<NumberPairNode> count; | ||||
|     /** Display determines how component is rendered */ | ||||
|     std::optional<DisplayNode> display; | ||||
| 
 | ||||
|     /** List of all COMDEL wires contained in bus */ | ||||
|     std::vector<WireNode> wires; | ||||
| }; | ||||
| 
 | ||||
| /** Represents ComponentConnection key in Connection node
 | ||||
|  * (eg. componentName.pinName) | ||||
|  * */ | ||||
| struct ConnectionComponentNode : public AstNode { | ||||
|     IdentifierNode component; | ||||
|     IdentifierNode pin; | ||||
| }; | ||||
| 
 | ||||
| /** Represents Connection node
 | ||||
|  * Connection can be between component and bus in which second is null, | ||||
|  * or between two components | ||||
|  * */ | ||||
| struct ConnectionNode : public AstNode { | ||||
|     ConnectionComponentNode first; | ||||
|     std::optional<ConnectionComponentNode> second; | ||||
| 
 | ||||
|     IdentifierNode bus; | ||||
|     std::vector<AttributeNode> attributes; | ||||
| 
 | ||||
|     /** If connection is of type component-component it contains two pairs of wires */ | ||||
|     std::vector<ValueNode> firstWires; | ||||
|     std::optional<std::vector<ValueNode>> secondWires; | ||||
| }; | ||||
| 
 | ||||
| /** LibraryNode represent library instance */ | ||||
| struct LibraryNode : public AstNode { | ||||
|     /** Name of library */ | ||||
|     std::optional<StringNode> name; | ||||
|     /** Library info contains generic information about library */ | ||||
|     std::optional<StringNode> libraryInfo; | ||||
|     /** Contains text that is added to top of COMDEL file */ | ||||
|     std::optional<StringNode> header; | ||||
|     /** Contains path to component directory */ | ||||
|     std::optional<StringNode> componentDirectory; | ||||
|     /** Contains text that is added to top of System component in COMDEL file */ | ||||
|     std::optional<StringNode> componentHeader; | ||||
| 
 | ||||
|     std::vector<AddressSpaceNode> addressSpaces; | ||||
| 
 | ||||
|     std::vector<ComponentNode> components; | ||||
|     std::vector<BusNode> buses; | ||||
|     std::vector<ConnectionNode> connections; | ||||
| 
 | ||||
|     /** Contains properties used to translate dialog and error messages */ | ||||
|     std::vector<PropertyNode> messages; | ||||
| }; | ||||
| 
 | ||||
| /*****************************************************************************
 | ||||
|  *                            LIBRARY TYPES                                  * | ||||
|  *****************************************************************************/ | ||||
| 
 | ||||
| /** Represents instance of attribute in component or connection instance */ | ||||
| struct InstanceAttributeNode : public AstNode { | ||||
|     IdentifierNode name; | ||||
|     ValueNode value; | ||||
| }; | ||||
| 
 | ||||
| /** Represents instance of a component or a bus */ | ||||
| struct InstanceNode : public AstNode { | ||||
|     /** Contains instance name */ | ||||
|     IdentifierNode name; | ||||
|     /** Contains component name */ | ||||
|     IdentifierNode component; | ||||
| 
 | ||||
|     /** Contains position of component instance */ | ||||
|     std::optional<NumberPairNode> position; | ||||
|     std::vector<InstanceAttributeNode> attributes; | ||||
| 
 | ||||
|     /** Contains size of bus instances */ | ||||
|     std::optional<NumberNode> size; | ||||
| }; | ||||
| 
 | ||||
| /** Represents ComponentConnection of a selected instance */ | ||||
| struct ConnectionComponentInstanceNode : public AstNode { | ||||
|     /** Name of component instance */ | ||||
|     IdentifierNode instance; | ||||
|     /** Name of pin */ | ||||
|     IdentifierNode pin; | ||||
| }; | ||||
| 
 | ||||
| /** Represents Connection instance */ | ||||
| struct ConnectionInstanceNode : public AstNode { | ||||
|     ConnectionComponentInstanceNode first; | ||||
|     std::optional<ConnectionComponentInstanceNode> second; | ||||
| 
 | ||||
|     IdentifierNode bus; | ||||
| 
 | ||||
|     std::vector<InstanceAttributeNode> attributes; | ||||
| }; | ||||
| 
 | ||||
| /** Represent schema instance */ | ||||
| struct SchemaNode : public AstNode { | ||||
|     /** Contains path to library source */ | ||||
|     std::optional<StringNode> source; | ||||
| 
 | ||||
|     /** Contains list of instances */ | ||||
|     std::vector<InstanceNode> instances; | ||||
|     /** Contains list of connection */ | ||||
|     std::vector<ConnectionInstanceNode> connections; | ||||
| 
 | ||||
|     /** Contains library */ | ||||
|     std::optional<LibraryNode> library; | ||||
| }; | ||||
| 
 | ||||
| #endif // AST_NODE_H
 | ||||
							
								
								
									
										109
									
								
								comdel/parser/astnode.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								comdel/parser/astnode.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,109 @@ | ||||
| #include "astnode.h" | ||||
| 
 | ||||
| /*************************** AST NODE ********************************/ | ||||
| 
 | ||||
| AstNode::~AstNode() = default; | ||||
| 
 | ||||
| /*************************** NUMBER NODE ********************************/ | ||||
| 
 | ||||
| NumberNode::NumberNode(const std::string& expression) { | ||||
|     if(expression.size() > 2) { | ||||
|         if(expression.substr(0, 2) == "0x") { | ||||
|             this->value = std::stoll(expression, 0, 16); | ||||
|         } else if(expression.substr(0, 2) == "0b") { | ||||
|             this->value = std::stoll(expression, 0, 2); | ||||
|         } else { | ||||
|             this->value = std::stoll(expression, 0, 10); | ||||
|         } | ||||
|     } else { | ||||
|         this->value = std::stoll(expression, 0, 10); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /*************************** STRING NODE ********************************/ | ||||
| 
 | ||||
| std::string StringNode::asString() { | ||||
|     return value.substr(1, value.length() - 2); | ||||
| } | ||||
| 
 | ||||
| /*************************** VALUE NODE ********************************/ | ||||
| 
 | ||||
| long long ValueNode::asInt() { | ||||
|     if(is(INT)) { | ||||
|         return intValue.value(); | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| std::string ValueNode::asString() { | ||||
|     if(is(STRING)) { | ||||
|         return stringValue.value(); | ||||
|     } | ||||
|     return ""; | ||||
| } | ||||
| 
 | ||||
| std::string ValueNode::asIdentifier() { | ||||
|     if(is(IDENTIFIER) || is(WIRE)) { | ||||
|         return identifierValue.value(); | ||||
|     } | ||||
|     return ""; | ||||
| } | ||||
| 
 | ||||
| bool ValueNode::asBool() { | ||||
|     if(is(BOOL)) { | ||||
|         return boolValue.value(); | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| bool ValueNode::is(ValueNode::ValueType valueType) { | ||||
|     return type.value == valueType; | ||||
| } | ||||
| 
 | ||||
| ValueNode ValueNode::ofBool(bool _value) { | ||||
|     ValueNode value; | ||||
|     value.type = EnumNode(BOOL); | ||||
|     value.boolValue = std::optional<bool>(_value); | ||||
|     return value; | ||||
| } | ||||
| 
 | ||||
| ValueNode ValueNode::ofInt(long long int _value) { | ||||
|     ValueNode value; | ||||
|     value.type = EnumNode(INT); | ||||
|     value.intValue = std::optional<long long>(_value); | ||||
|     return value; | ||||
| } | ||||
| 
 | ||||
| ValueNode ValueNode::ofString(std::string _value) { | ||||
|     ValueNode value; | ||||
|     value.type = EnumNode(STRING); | ||||
|     value.stringValue = std::optional<std::string>(_value); | ||||
|     return value; | ||||
| } | ||||
| 
 | ||||
| ValueNode ValueNode::ofIdentifier(std::string _value) { | ||||
|     ValueNode value; | ||||
|     value.type = EnumNode(IDENTIFIER); | ||||
|     value.identifierValue = std::optional<std::string>(_value); | ||||
|     return value; | ||||
| } | ||||
| 
 | ||||
| ValueNode ValueNode::ofNull() { | ||||
|     ValueNode value; | ||||
|     value.type = EnumNode(NIL); | ||||
|     return value; | ||||
| } | ||||
| 
 | ||||
| ValueNode ValueNode::ofWire(std::optional<std::string> _value) { | ||||
|     ValueNode value; | ||||
|     value.type = EnumNode(WIRE); | ||||
|     value.identifierValue = _value; | ||||
|     return value; | ||||
| } | ||||
| 
 | ||||
| ValueNode ValueNode::ofMemory(std::optional<std::string> _value) { | ||||
|     ValueNode value; | ||||
|     value.type = EnumNode(MEMORY); | ||||
|     value.identifierValue = _value; | ||||
|     return value; | ||||
| } | ||||
							
								
								
									
										353
									
								
								comdel/parser/astnode.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										353
									
								
								comdel/parser/astnode.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,353 @@ | ||||
| #ifndef AST_NODE_H | ||||
| #define AST_NODE_H | ||||
| 
 | ||||
| #include "token.h" | ||||
| #include <optional> | ||||
| #include <vector> | ||||
| 
 | ||||
| /**
 | ||||
|  * AST base class, all AST node classes extend this class. Class contains basic | ||||
|  * information about nodes location in file. | ||||
|  */ | ||||
| class AstNode { | ||||
| public: | ||||
| 
 | ||||
|     Span span; | ||||
| 
 | ||||
|     AstNode() = default; | ||||
| 
 | ||||
|     virtual ~AstNode(); | ||||
| 
 | ||||
|     AstNode(AstNode&&) = default; | ||||
|     AstNode& operator=(AstNode&&) = default; | ||||
|     AstNode(const AstNode&) = default; | ||||
|     AstNode& operator=(const AstNode&) = default; | ||||
| }; | ||||
| 
 | ||||
| template <typename T> | ||||
| struct EnumNode: public AstNode | ||||
| { | ||||
|     EnumNode() = default; | ||||
|     explicit EnumNode(T value): value(value) {} | ||||
| 
 | ||||
|     T value; | ||||
| }; | ||||
| 
 | ||||
| struct StringNode: public AstNode | ||||
| { | ||||
|     std::string value; | ||||
|     std::string asString(); | ||||
| }; | ||||
| 
 | ||||
| struct IdentifierNode: public AstNode | ||||
| { | ||||
|     std::string value; | ||||
| }; | ||||
| 
 | ||||
| struct NumberNode: public AstNode { | ||||
|     long long int value; | ||||
|     explicit NumberNode(const std::string& expression); | ||||
|     NumberNode(): value(0) {} | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| struct CountNode: public AstNode | ||||
| { | ||||
|     NumberNode first; | ||||
|     NumberNode second; | ||||
| 
 | ||||
|     CountNode(NumberNode first, NumberNode second): first(first), second(second) {} | ||||
|     CountNode() = default; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| struct AddressSpaceNode: public AstNode | ||||
| { | ||||
|     IdentifierNode name; | ||||
|     NumberNode start; | ||||
|     NumberNode end; | ||||
| }; | ||||
| 
 | ||||
| class ValueNode: public AstNode | ||||
| { | ||||
| public: | ||||
|     enum ValueType { | ||||
|         INT, | ||||
|         STRING, | ||||
|         BOOL, | ||||
|         WIRE, | ||||
|         IDENTIFIER, | ||||
|         MEMORY, | ||||
|         NIL, | ||||
|     }; | ||||
| 
 | ||||
| private: | ||||
|     EnumNode<ValueType> type; | ||||
|     std::optional<long long> intValue; | ||||
|     std::optional<std::string> stringValue; | ||||
|     std::optional<bool> boolValue; | ||||
|     std::optional<std::string> identifierValue; | ||||
| 
 | ||||
| public: | ||||
|     ValueNode() = default; | ||||
| 
 | ||||
|     ValueType getType() { | ||||
|         return type.value; | ||||
|     } | ||||
|     long long asInt(); | ||||
|     std::string asString(); | ||||
|     std::string asIdentifier(); | ||||
|     bool asBool(); | ||||
| 
 | ||||
|     bool is(ValueType valueType); | ||||
| 
 | ||||
|     static ValueNode ofBool(bool _value); | ||||
|     static ValueNode ofInt(long long _value); | ||||
|     static ValueNode ofString(std::string _value); | ||||
|     static ValueNode ofIdentifier(std::string _value); | ||||
|     static ValueNode ofMemory(std::optional<std::string> _value); | ||||
|     static ValueNode ofNull(); | ||||
|     static ValueNode ofWire(std::optional<std::string> _value); | ||||
| }; | ||||
| 
 | ||||
| struct ConditionNode | ||||
| { | ||||
|     bool negated; | ||||
|     IdentifierNode functionName; | ||||
|     std::vector<ValueNode> params; | ||||
| }; | ||||
| 
 | ||||
| class ActionNode: public AstNode { | ||||
| public: | ||||
|     enum ActionType { | ||||
|         ERROR, | ||||
|         WARNING | ||||
|     }; | ||||
| 
 | ||||
|     EnumNode<ActionType> type; | ||||
|     StringNode message; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| struct IfStatementNode: public AstNode | ||||
| { | ||||
|     ConditionNode condition; | ||||
|     ActionNode action; | ||||
| }; | ||||
| 
 | ||||
| struct RuleNode: public AstNode | ||||
| { | ||||
|     std::vector<IfStatementNode> statements; | ||||
| }; | ||||
| 
 | ||||
| struct EnumerationNode: public AstNode | ||||
| { | ||||
|     StringNode key; | ||||
|     ValueNode value; | ||||
| }; | ||||
| 
 | ||||
| struct PopupNode: public AstNode | ||||
| { | ||||
|     enum PopupType { | ||||
|         AUTOMATIC, | ||||
|         ON_DEMAND | ||||
|     }; | ||||
| 
 | ||||
|     std::optional<EnumNode<PopupType>> type; | ||||
|     std::optional<StringNode> title; | ||||
|     std::optional<StringNode> text; | ||||
| 
 | ||||
|     bool enumerated; | ||||
|     std::vector<EnumerationNode> enumeration; | ||||
| 
 | ||||
|     std::vector<RuleNode> rules; | ||||
| }; | ||||
| 
 | ||||
| struct PropertyNode: public AstNode | ||||
| { | ||||
|     IdentifierNode key; | ||||
|     ValueNode value; | ||||
| }; | ||||
| 
 | ||||
| struct DisplayItemNode: public AstNode | ||||
| { | ||||
|     IdentifierNode type; | ||||
|     std::vector<PropertyNode> values; | ||||
| }; | ||||
| 
 | ||||
| struct DisplayNode: public AstNode | ||||
| { | ||||
|     std::vector<DisplayItemNode> items; | ||||
| }; | ||||
| 
 | ||||
| struct PinConnectionNode: public AstNode | ||||
| { | ||||
|     enum ConnectionType { | ||||
|         REQUIRED, | ||||
|         OPTIONAL | ||||
|     }; | ||||
| 
 | ||||
|     StringNode message; | ||||
|     EnumNode<ConnectionType> type; | ||||
| }; | ||||
| 
 | ||||
| struct PinNode: public AstNode | ||||
| { | ||||
|     enum PinType { | ||||
|         IN_OUT, | ||||
|         IN, | ||||
|         OUT | ||||
|     }; | ||||
| 
 | ||||
|     IdentifierNode name; | ||||
|     EnumNode<PinType> type; | ||||
|     std::optional<StringNode> tooltip; | ||||
|     std::optional<PinConnectionNode> connection; | ||||
|     std::optional<DisplayNode> display; | ||||
|     std::optional<std::vector<ValueNode>> wires; | ||||
| }; | ||||
| 
 | ||||
| struct WireNode: public AstNode | ||||
| { | ||||
|     enum WireType { | ||||
|         WIRE, | ||||
|         WIRED_AND, | ||||
|         WIRED_OR, | ||||
|         R_WIRE | ||||
|     }; | ||||
|     EnumNode<WireType> type; | ||||
|     IdentifierNode name; | ||||
|     NumberNode size; | ||||
| 
 | ||||
|     bool hidden = false; | ||||
| 
 | ||||
|     bool hasTerminateWith; | ||||
|     ValueNode terminateWith; | ||||
| }; | ||||
| 
 | ||||
| struct AttributeNode: public AstNode | ||||
| { | ||||
|     ValueNode::ValueType type; | ||||
|     IdentifierNode name; | ||||
|     std::optional<ValueNode> defaultValue; | ||||
|     std::optional<PopupNode> popup; | ||||
| }; | ||||
| 
 | ||||
| struct ConnectionComponentNode: public AstNode | ||||
| { | ||||
|     IdentifierNode component; | ||||
|     IdentifierNode pin; | ||||
| }; | ||||
| 
 | ||||
| struct ConnectionNode: public AstNode | ||||
| { | ||||
|     ConnectionComponentNode first; | ||||
|     std::optional<ConnectionComponentNode> second; | ||||
| 
 | ||||
|     IdentifierNode bus; | ||||
|     std::vector<AttributeNode> attributes; | ||||
| 
 | ||||
|     std::vector<ValueNode> firstWires; | ||||
|     std::optional<std::vector<ValueNode>> secondWires; | ||||
| }; | ||||
| 
 | ||||
| struct ComponentNode: public AstNode | ||||
| { | ||||
|     enum ComponentType { | ||||
|         OTHER, | ||||
|         PROCESSOR, | ||||
|         MEMORY | ||||
|     }; | ||||
| 
 | ||||
|     IdentifierNode name; | ||||
|     std::optional<StringNode> tooltip; | ||||
|     std::optional<StringNode> source; | ||||
|     EnumNode<ComponentType> type; | ||||
|     std::vector<RuleNode> rules; | ||||
|     std::optional<StringNode> instanceName; | ||||
|     std::optional<CountNode> count; | ||||
|     std::optional<DisplayNode> display; | ||||
|     std::vector<PinNode> pins; | ||||
|     std::vector<AttributeNode> attributes; | ||||
| }; | ||||
| 
 | ||||
| struct BusNode: public AstNode | ||||
| { | ||||
|     enum BusType { | ||||
|         AUTOMATIC, | ||||
|         REGULAR, | ||||
|         SINGLE_AUTOMATIC | ||||
|     }; | ||||
| 
 | ||||
|     EnumNode<BusType> type; | ||||
|     IdentifierNode name; | ||||
|     std::optional<StringNode> tooltip; | ||||
|     std::optional<CountNode> count; | ||||
|     std::optional<DisplayNode> display; | ||||
| 
 | ||||
|     std::vector<WireNode> wires; | ||||
| }; | ||||
| 
 | ||||
| struct LibraryNode: public AstNode | ||||
| { | ||||
|     std::optional<StringNode> name; | ||||
|     std::optional<StringNode> libraryInfo; | ||||
|     std::optional<StringNode> header; | ||||
|     std::optional<StringNode> componentDirectory; | ||||
|     std::optional<StringNode> componentHeader; | ||||
| 
 | ||||
|     std::vector<AddressSpaceNode> addressSpaces; | ||||
| 
 | ||||
|     std::vector<ComponentNode> components; | ||||
|     std::vector<BusNode> buses; | ||||
|     std::vector<ConnectionNode> connections; | ||||
| 
 | ||||
|     std::vector<PropertyNode> messages; | ||||
| }; | ||||
| 
 | ||||
| // SCHEMA models
 | ||||
| struct InstanceAttributeNode: public AstNode | ||||
| { | ||||
|     IdentifierNode name; | ||||
|     ValueNode value; | ||||
| }; | ||||
| 
 | ||||
| struct InstanceNode: public AstNode | ||||
| { | ||||
|     IdentifierNode name; | ||||
|     IdentifierNode component; | ||||
| 
 | ||||
|     std::optional<CountNode> position; | ||||
|     std::vector<InstanceAttributeNode> attributes; | ||||
| 
 | ||||
|     std::optional<NumberNode> size; | ||||
| }; | ||||
| 
 | ||||
| struct ConnectionComponentInstance: public AstNode | ||||
| { | ||||
|     IdentifierNode instance; | ||||
|     IdentifierNode pin; | ||||
| }; | ||||
| 
 | ||||
| struct ConnectionInstanceNode: public AstNode | ||||
| { | ||||
|     ConnectionComponentInstance first; | ||||
|     std::optional<ConnectionComponentInstance> second; | ||||
| 
 | ||||
|     IdentifierNode bus; | ||||
| 
 | ||||
|     std::vector<InstanceAttributeNode> attributes; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| struct SchemaNode: public AstNode | ||||
| { | ||||
|     std::optional<StringNode> source; | ||||
| 
 | ||||
|     std::vector<InstanceNode> instances; | ||||
|     std::vector<ConnectionInstanceNode> connections; | ||||
| 
 | ||||
|     std::optional<LibraryNode> library; | ||||
| }; | ||||
| 
 | ||||
| #endif // AST_NODE_H
 | ||||
| @ -1,21 +0,0 @@ | ||||
| //
 | ||||
| // Created by bbr on 12.06.22..
 | ||||
| //
 | ||||
| 
 | ||||
| #ifndef SCHEMEEDITOR_COLOR_H | ||||
| #define SCHEMEEDITOR_COLOR_H | ||||
| 
 | ||||
| 
 | ||||
| struct Color { | ||||
|     unsigned char r = 0; | ||||
|     unsigned char g = 0; | ||||
|     unsigned char b = 0; | ||||
|     unsigned char a = 255; | ||||
| 
 | ||||
|     Color() = default; | ||||
| 
 | ||||
|     Color(unsigned char r, unsigned char g, unsigned char b, unsigned char a = 0): r(r), g(g), b(b), a(a) {} | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| #endif //SCHEMEEDITOR_COLOR_H
 | ||||
| @ -1,6 +1,6 @@ | ||||
| #include "comdel_lexer.h" | ||||
| #include "comdellexer.h" | ||||
| #include "token.h" | ||||
| #include "tokens_type.h" | ||||
| #include "tokenstype.h" | ||||
| 
 | ||||
| #include <fstream> | ||||
| #include <cctype> | ||||
| @ -36,13 +36,14 @@ inline bool isWhitespace(char ch) { | ||||
| *************************************************************************/ | ||||
| 
 | ||||
| ComdelLexer::ComdelLexer(std::string fileName, std::string source, | ||||
|                          ParseContext *parseContext) | ||||
|         : source(std::move(source)), | ||||
|           parseContext(parseContext), | ||||
|         // TODO Update this
 | ||||
|           fileId(this->parseContext->addFile(fileName, this->source)), | ||||
|           position(this->fileId, 1, 1, 0), | ||||
|           ch(this->source[0]) {} | ||||
|                          ParseContext* parseContext) | ||||
|     : source(std::move(source)), | ||||
|       parseContext(parseContext), | ||||
|       // TODO Update this
 | ||||
|       fileId(this->parseContext->addFile(fileName, this->source)), | ||||
|       position(this->fileId, 1, 1, 0), | ||||
|       ch(this->source[0]) | ||||
| {} | ||||
| 
 | ||||
| 
 | ||||
| LexerResult ComdelLexer::tokenize() { | ||||
| @ -50,11 +51,11 @@ LexerResult ComdelLexer::tokenize() { | ||||
|         tokenBegin = position; | ||||
| 
 | ||||
|         auto tokenType = nextTokenType(); | ||||
|         if (!tokenType) { | ||||
|         if(!tokenType) { | ||||
|             errors.push_back(tokenType.error()); | ||||
|             continue; | ||||
|         } | ||||
|         if (tokenType == TokenType::WHITESPACE || tokenType == TokenType::COMMENT) { | ||||
|         if (tokenType == TokenType::WHITESPACE || tokenType ==  TokenType::COMMENT) { | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
| @ -66,9 +67,9 @@ LexerResult ComdelLexer::tokenize() { | ||||
|         tokens.emplace_back(*tokenType, Span(tokenBegin, position), text); | ||||
|     } | ||||
| 
 | ||||
|     tokens.emplace_back(TokenType::END_OF_FILE, Span(position), ""); | ||||
|     tokens.emplace_back( TokenType::END_OF_FILE, Span(position), ""); | ||||
| 
 | ||||
|     return LexerResult{tokens, errors}; | ||||
|     return LexerResult { tokens, errors }; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| @ -85,11 +86,11 @@ LexerResult ComdelLexer::tokenize() { | ||||
| unsigned ComdelLexer::takeNumberInRadix(Radix radix) { | ||||
|     unsigned digitsTaken = 0; | ||||
| 
 | ||||
|     while (true) { | ||||
|     while(true) { | ||||
|         if (digitIsValid(ch, radix)) { // skip and count real digits
 | ||||
|             bump(); | ||||
|             digitsTaken++; | ||||
|         } else if (ch == '_') { // skip underscores
 | ||||
|         } else if(ch == '_') { // skip underscores
 | ||||
|             bump(); | ||||
|         } else { // some other character => end of number
 | ||||
|             return digitsTaken; | ||||
| @ -102,26 +103,26 @@ bool ComdelLexer::digitIsValid(char ch, Radix radix) { | ||||
| 
 | ||||
|     // Check valid digits
 | ||||
|     // digit is 0..1
 | ||||
|     if (ch == '1' || ch == '0') { | ||||
|     if(ch == '1' || ch == '0') { | ||||
|         // OK for all radixes
 | ||||
|         return true; | ||||
|     } | ||||
|     //digit is 2..9
 | ||||
|     if (isdigit(ch)) { | ||||
|     if(isdigit(ch)) { | ||||
|         // OK for decimal and hex radixes
 | ||||
|         return (radix != Radix::BIN_NUMBER); | ||||
|         return(radix != Radix::BIN_NUMBER); | ||||
|     } | ||||
|         // digit is a..f A..F
 | ||||
|     else if (isxdigit(ch)) { | ||||
|     // digit is a..f A..F
 | ||||
|     else if(isxdigit(ch)) { | ||||
|         // OK only for hex radix
 | ||||
|         return (radix == Radix::HEX_NUMBER); | ||||
|         return(radix ==Radix::HEX_NUMBER); | ||||
|     } | ||||
|     // NOT 0..9 a..f A..F
 | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| ComdelLexer::Radix ComdelLexer::takeRadix() { | ||||
| ComdelLexer::Radix ComdelLexer::takeRadix(){ | ||||
|     if (ch == '0') { | ||||
|         char nextChar = peek(); | ||||
|         if (nextChar == 'x' || nextChar == 'X') { | ||||
| @ -140,7 +141,7 @@ ComdelLexer::Radix ComdelLexer::takeRadix() { | ||||
| unsigned ComdelLexer::takeHexColor() { | ||||
|     unsigned digitsTaken = 0; | ||||
| 
 | ||||
|     while (true) { | ||||
|     while(true) { | ||||
|         if (digitIsValid(ch, Radix::HEX_NUMBER)) { // skip and count hex digits
 | ||||
|             bump(); | ||||
|             digitsTaken++; | ||||
| @ -161,10 +162,10 @@ PResult<TokenType> ComdelLexer::takeString() { | ||||
|     // Check escape-sequences  \t  \n  \\  \"  but leave them in string.
 | ||||
|     // They will be replaced in the constructor of StringLiteral AST-node.
 | ||||
|     while (ch != '"' && ch != '\n' && !eof()) { | ||||
|         if (ch == '"') { | ||||
|         if(ch == '"') { | ||||
|             // possible start of escape-sequence
 | ||||
|             char nextCh = peek(); | ||||
|             if (nextCh == '\\' || nextCh == '\"' || nextCh == 't' || nextCh == 'n') | ||||
|             if(nextCh == '\\' || nextCh == '\"' || nextCh == 't' || nextCh == 'n') | ||||
|                 bump();   // legal escape-sequence: skip backslash
 | ||||
|             else | ||||
|                 return PError({Span(lo, position), "illegal escape-sequence (allowed:  \\n  \\\"  \\\\  \\t"}); | ||||
| @ -176,11 +177,12 @@ PResult<TokenType> ComdelLexer::takeString() { | ||||
|         return PError({Span(lo, position), "unterminated string"}); | ||||
|     } | ||||
|     bump(); // skip closing "
 | ||||
|     return TokenType::STRING; | ||||
|     return  TokenType::STRING; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| PResult<TokenType> ComdelLexer::takeRawString() { | ||||
| PResult<TokenType> ComdelLexer::takeRawString() | ||||
| { | ||||
|     Position lo = position; | ||||
| 
 | ||||
|     if (ch != '`') | ||||
| @ -196,7 +198,7 @@ PResult<TokenType> ComdelLexer::takeRawString() { | ||||
|         return PError({Span(lo, position), "unterminated string"}); | ||||
|     } | ||||
|     bump(); // skip closing '
 | ||||
|     return TokenType::STRING; | ||||
|     return  TokenType::STRING; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| @ -235,16 +237,21 @@ bool ComdelLexer::skipMultilineComment() { | ||||
| 
 | ||||
| 
 | ||||
| PResult<TokenType> ComdelLexer::nextTokenType() { | ||||
|     if (isWhitespace(ch)) { | ||||
|     if (isWhitespace(ch)) | ||||
|     { | ||||
|         skipWhitespace(); | ||||
|         return TokenType::WHITESPACE; | ||||
|     } else if (identifierStart(ch)) { | ||||
|         return  TokenType::WHITESPACE; | ||||
|     } | ||||
|     else if (identifierStart(ch)) | ||||
|     { | ||||
|         bump(); | ||||
|         while (identifierContinue(ch)) | ||||
|             bump(); | ||||
|         return TokenType::IDENTIFIER; | ||||
|     } else if (numberStart(ch)) { | ||||
|         if (ch == '-') { | ||||
|         return  TokenType::IDENTIFIER; | ||||
|     } | ||||
|     else if (numberStart(ch)) | ||||
|     { | ||||
|         if(ch == '-') { | ||||
|             bump(); | ||||
|         } | ||||
|         unsigned takenDigits; | ||||
| @ -252,99 +259,145 @@ PResult<TokenType> ComdelLexer::nextTokenType() { | ||||
|         takenDigits = takeNumberInRadix(radix); | ||||
|         if (takenDigits == 0) { | ||||
|             return PError({Span(tokenBegin, position), | ||||
|                            "no digits found for number, or misspelled number"}); | ||||
|                 "no digits found for number, or misspelled number"}); | ||||
|         } | ||||
|         if (isalnum(ch)) { | ||||
|         if( isalnum(ch) ) { | ||||
|             return PError({Span(tokenBegin, position), | ||||
|                            "illegal digit or letter found at the end of number"}); | ||||
|                 "illegal digit or letter found at the end of number"}); | ||||
|         } | ||||
|         return TokenType::NUMBER; | ||||
|     } else if (ch == '!') { | ||||
|         return  TokenType::NUMBER; | ||||
|     } | ||||
|     else if (ch == '!') | ||||
|     { | ||||
|         bump(); | ||||
|         return TokenType::NOT; | ||||
|     } else if (ch == '<') { | ||||
|         return  TokenType::NOT; | ||||
|     } | ||||
| 
 | ||||
|     else if (ch == '<') | ||||
|     { | ||||
|         bump(); | ||||
|         return TokenType::LT; | ||||
|     } else if (ch == '>') { | ||||
|         return  TokenType::LT; | ||||
|     } | ||||
| 
 | ||||
|     else if (ch == '>') | ||||
|     { | ||||
|         bump(); | ||||
|         return TokenType::GT; | ||||
|     } else if (ch == '#') { | ||||
|         return  TokenType::GT; | ||||
|     } | ||||
| 
 | ||||
|     else if (ch == '#') | ||||
|     { | ||||
|         bump(); | ||||
| 
 | ||||
|         if (digitIsValid(ch, Radix::HEX_NUMBER)) { | ||||
|             unsigned takenDigits = takeHexColor(); | ||||
|             if (takenDigits != 6 && takenDigits != 8) { | ||||
|                 return PError({Span(tokenBegin, position), | ||||
|                                "hex-color must have 6 or 8 hex-digits"}); | ||||
|                        "hex-color must have 6 or 8 hex-digits"}); | ||||
|             } | ||||
|             if (isalnum(ch)) { | ||||
|             if( isalnum(ch) ) { | ||||
|                 return PError({Span(tokenBegin, position), | ||||
|                                "illegal letter found at the end of hex-color"}); | ||||
|                     "illegal letter found at the end of hex-color"}); | ||||
|             } | ||||
|             return TokenType::COLOR; | ||||
|             return  TokenType::COLOR; | ||||
|         } else { | ||||
|             return PError({Span(tokenBegin, position), | ||||
|                            "unexpected #"}); | ||||
|         } | ||||
|     } else if (ch == '@') { | ||||
|     } | ||||
|     else if (ch == '@') | ||||
|     { | ||||
|         bump(); | ||||
|         while (identifierContinue(ch)) | ||||
|             bump(); | ||||
|         return TokenType::KEYWORD; | ||||
|     } else if (ch == '"') { | ||||
|         return  TokenType::KEYWORD; | ||||
|     } | ||||
|     else if (ch == '"') | ||||
|     { | ||||
|         return takeString(); | ||||
|     } else if (ch == '`') { | ||||
|     } | ||||
|     else if (ch == '`') | ||||
|     { | ||||
|         return takeRawString(); | ||||
|     } else if (ch == '(') { | ||||
|     } | ||||
|     else if (ch == '(') | ||||
|     { | ||||
|         bump(); | ||||
|         return TokenType::LPAREN; | ||||
|     } else if (ch == ')') { | ||||
|         return  TokenType::LPAREN; | ||||
|     } | ||||
|     else if (ch == ')') | ||||
|     { | ||||
|         bump(); | ||||
|         return TokenType::RPAREN; | ||||
|     } else if (ch == '[') { | ||||
|         return  TokenType::RPAREN; | ||||
|     } | ||||
|     else if (ch == '[') | ||||
|     { | ||||
|         bump(); | ||||
|         return TokenType::LBRACKET; | ||||
|     } else if (ch == ']') { | ||||
|     } | ||||
|     else if (ch == ']') | ||||
|     { | ||||
|         bump(); | ||||
|         return TokenType::RBRACKET; | ||||
|     } else if (ch == '{') { | ||||
|         return  TokenType::RBRACKET; | ||||
|     } | ||||
|     else if (ch == '{') | ||||
|     { | ||||
|         bump(); | ||||
|         return TokenType::LBRACE; | ||||
|     } else if (ch == '}') { | ||||
|     } | ||||
|     else if (ch == '}') | ||||
|     { | ||||
|         bump(); | ||||
|         return TokenType::RBRACE; | ||||
|     } else if (ch == '/') { | ||||
|     } | ||||
|     else if (ch == '/') | ||||
|     { | ||||
|         bump(); | ||||
|         if (ch == '/') { | ||||
|         if (ch == '/') | ||||
|         { | ||||
|             bump(); | ||||
|             skipComment(); | ||||
|             return TokenType::COMMENT; | ||||
|         } else if (ch == '*') { | ||||
|         } else if (ch == '*') | ||||
|         { | ||||
|             bump(); | ||||
|             if (!skipMultilineComment()) { | ||||
|             if (!skipMultilineComment()) | ||||
|             { | ||||
|                 return PError({Span(tokenBegin, position), | ||||
|                                "unterminated multiline comment"}); | ||||
|                        "unterminated multiline comment"}); | ||||
|             } | ||||
|             return TokenType::COMMENT; | ||||
|         } | ||||
|         return PError({Span(tokenBegin, position), | ||||
|                        "unexpected /"}); | ||||
|     } else if (ch == '.') { | ||||
|     } | ||||
|     else if (ch == '.') | ||||
|     { | ||||
|         bump(); | ||||
|         return TokenType::DOT; | ||||
|     } else if (ch == ':') { | ||||
|     } | ||||
|     else if (ch == ':') | ||||
|     { | ||||
|         bump(); | ||||
|         return TokenType::COLON; | ||||
|     } else if (ch == ';') { | ||||
|     } | ||||
|     else if (ch == ';') | ||||
|     { | ||||
|         bump(); | ||||
|         return TokenType::SEMICOLON; | ||||
|     } else if (ch == ',') { | ||||
|     } | ||||
|     else if (ch == ',') | ||||
|     { | ||||
|         bump(); | ||||
|         return TokenType::COMMA; | ||||
|     } else if (ch == '=') { | ||||
|     } | ||||
|     else if (ch == '=') | ||||
|     { | ||||
|         bump(); | ||||
|         return TokenType::EQUALS; | ||||
|     } else { | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         std::stringstream message; | ||||
|         message << "unexpected character `" << ch << "`"; | ||||
|         bump(); | ||||
| @ -356,11 +409,11 @@ PResult<TokenType> ComdelLexer::nextTokenType() { | ||||
| // Move position to the new character in input file.
 | ||||
| // Fetch the new character in 'ch'
 | ||||
| void ComdelLexer::bump(unsigned count) { | ||||
|     for (unsigned i = 0; i < count && !eof(); i++) { | ||||
|     for (unsigned i=0; i < count && !eof(); i++) { | ||||
|         if (ch == '\n') { | ||||
|             position.line += 1; | ||||
|             position.col = 1; | ||||
|             parseContext->getFile(fileId).addLineOffset(position.offset + 1); | ||||
|             parseContext->getFile(fileId).addLineOffset(position.offset+1); | ||||
|         } else { | ||||
|             position.col += 1; | ||||
|         } | ||||
| @ -374,10 +427,10 @@ void ComdelLexer::bump(unsigned count) { | ||||
| // Fetch does not cross line boundary.
 | ||||
| // Returns \n when next char does not exist (end of line or end of file)
 | ||||
| char ComdelLexer::peek() { | ||||
|     if (position.offset + 1 == source.size()) // eof
 | ||||
|     if(position.offset+1 == source.size()) // eof
 | ||||
|         return '\n'; | ||||
| 
 | ||||
|     return source[position.offset + 1]; | ||||
|     return source[position.offset+1]; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| @ -1,9 +1,9 @@ | ||||
| #ifndef COMDEL_LEXER_H | ||||
| #define COMDEL_LEXER_H | ||||
| 
 | ||||
| #include "parse_context.h" | ||||
| #include "parsecontext.h" | ||||
| #include "presult.h" | ||||
| #include "source_error.h" | ||||
| #include "sourceerror.h" | ||||
| #include "token.h" | ||||
| 
 | ||||
| 
 | ||||
| @ -11,15 +11,13 @@ | ||||
| #include <string> | ||||
| #include <vector> | ||||
| 
 | ||||
| /** Contains results of tokenizing,
 | ||||
|  * if errors isn't empty tokenizing has failed */ | ||||
| struct LexerResult { | ||||
|     std::vector<Token> tokens; | ||||
|     std::vector<SourceError> errors; | ||||
| }; | ||||
| 
 | ||||
| /** Used to tokenize input string */ | ||||
| class ComdelLexer { | ||||
| class ComdelLexer | ||||
| { | ||||
| 
 | ||||
|     enum Radix { | ||||
|         BIN_NUMBER = 2, | ||||
| @ -27,46 +25,38 @@ class ComdelLexer { | ||||
|         HEX_NUMBER = 16 | ||||
|     }; | ||||
| 
 | ||||
|     /** Source file */ | ||||
|     std::string source; | ||||
|     std::vector<Token> tokens; | ||||
|     std::vector<SourceError> errors; | ||||
|     /** Source file */ | ||||
|     ParseContext *parseContext; | ||||
|     ParseContext* parseContext; | ||||
|     unsigned fileId; | ||||
| 
 | ||||
| public: | ||||
|     ComdelLexer(std::string fileName, std::string source, ParseContext *parseContext); | ||||
| 
 | ||||
|     ComdelLexer(std::string fileName, std::string source, ParseContext* parseContext); | ||||
|     LexerResult tokenize(); | ||||
| 
 | ||||
| private: | ||||
|     /** Current parsing info */ | ||||
|     void skipWhitespace(); | ||||
| 
 | ||||
|     unsigned takeNumberInRadix(Radix radix); | ||||
|     unsigned takeHexColor(); | ||||
|     bool digitIsValid(char ch, Radix radix); | ||||
|     Radix takeRadix(); | ||||
| 
 | ||||
|     PResult<TokenType> nextTokenType(); | ||||
| 
 | ||||
|     Position tokenBegin; | ||||
|     Position position; | ||||
|     char ch; | ||||
| 
 | ||||
|     /** Methods used to skip unused content */ | ||||
|     void skipWhitespace(); | ||||
|     void skipComment(); | ||||
|     bool skipMultilineComment(); | ||||
|     void bump(unsigned count = 1); | ||||
| 
 | ||||
|     /** Metods used for number parsing */ | ||||
|     unsigned takeNumberInRadix(Radix radix); | ||||
|     bool digitIsValid(char ch, Radix radix); | ||||
|     Radix takeRadix(); | ||||
| 
 | ||||
|     unsigned takeHexColor(); | ||||
| 
 | ||||
|     PResult<TokenType> nextTokenType(); | ||||
| 
 | ||||
|     PResult<TokenType> takeString(); | ||||
|     PResult<TokenType> takeRawString(); | ||||
| 
 | ||||
|     void bump(unsigned count = 1); | ||||
|     char peek(); | ||||
| 
 | ||||
|     /** Checks if we reached end of file */ | ||||
|     bool eof(); | ||||
| }; | ||||
| 
 | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -1,10 +1,10 @@ | ||||
| #ifndef COMDEL_PARSER_H | ||||
| #define COMDEL_PARSER_H | ||||
| 
 | ||||
| #include "source_error.h" | ||||
| #include "sourceerror.h" | ||||
| #include "presult.h" | ||||
| #include "token.h" | ||||
| #include "ast_nodes.h" | ||||
| #include "astnode.h" | ||||
| 
 | ||||
| #include <optional> | ||||
| #include <set> | ||||
| @ -18,21 +18,23 @@ | ||||
| class Spanner { | ||||
|     // REFERENCE to the parser's prevSpan. After parsing a node this will
 | ||||
|     // "point" to the span of the last token contained in the node.
 | ||||
|     const Span &prevSpan; | ||||
|     const Span& prevSpan; | ||||
| 
 | ||||
| public: | ||||
|     const Span lo; // the low end of the span, beginning of the node
 | ||||
| 
 | ||||
|     Spanner(Span lo, Span &prevSpan) : lo(lo), prevSpan(prevSpan) {} | ||||
| 
 | ||||
|     template<typename T, typename = std::enable_if<std::is_base_of<AstNode, T>::value>> | ||||
|     typename std::remove_reference_t<T> operator()(T &&astNode) const { | ||||
|     Spanner(Span lo, Span& prevSpan) : lo(lo), prevSpan(prevSpan) {} | ||||
| 
 | ||||
|     template <typename T, typename = std::enable_if<std::is_base_of<AstNode, T>::value>> | ||||
|     typename std::remove_reference_t<T> operator()(T&& astNode) const { | ||||
|         astNode.span = lo.to(prevSpan); | ||||
|         return std::forward<T>(astNode); | ||||
|         return std::move(astNode); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| class ComdelParser { | ||||
| class ComdelParser | ||||
| { | ||||
| private: | ||||
|     std::vector<Token> tokens; | ||||
|     std::set<TokenType> expectedTokens; | ||||
| @ -42,71 +44,66 @@ private: | ||||
| 
 | ||||
|     Span &getPreviousSpan(); | ||||
| 
 | ||||
|     /** Skips current token */ | ||||
|     void bump(); | ||||
|     /** Checks if next token is of given type and if it is consumes it */ | ||||
| 
 | ||||
|     bool consume(TokenType tokenType); | ||||
|     /** Checks if next token is of given type */ | ||||
|     bool check(TokenType tokenType); | ||||
|     /** Skips until next keyword on same level
 | ||||
|      * Used to continue parsing on error | ||||
|      * */ | ||||
| 
 | ||||
|     void skipUntilNextKeyword(); | ||||
|     /** Retuns current token */ | ||||
| 
 | ||||
|     Token ¤t(); | ||||
| 
 | ||||
|     /** Throws error of unexpected types */ | ||||
|     [[nodiscard]] PError unexpected(); | ||||
| 
 | ||||
|     template<typename T> | ||||
|     PResult<std::vector<T>> parseList(std::optional<TokenType> openDelim, | ||||
|                                       TokenType closeDelim, | ||||
|                                       std::optional<TokenType> separator, | ||||
|                                       bool allowTrailing, | ||||
|                                       const std::function<PResult<T>()> &parse_f); | ||||
|                                        TokenType closeDelim, | ||||
|                                        std::optional<TokenType> separator, | ||||
|                                        bool allowTrailing, | ||||
|                                        const std::function<PResult<T> ()> &parse_f); | ||||
| 
 | ||||
|     Spanner getSpanner(); | ||||
| 
 | ||||
|     /** Base types */ | ||||
|     PResult<StringNode> parseString(); | ||||
|     PResult<ColorNode> parseColor(); | ||||
|     PResult<IdentifierNode> parseIdentifier(); | ||||
|     PResult<NumberNode> parseNumber(); | ||||
|     PResult<NumberPairNode> parseNumberPair(); | ||||
|     PResult<CountNode> parseCount(); | ||||
|     PResult<PropertyNode> parseProperty(std::optional<TokenType> valueType); | ||||
|     PResult<StringPropertyNode> parseStringProperty(); | ||||
|     PResult<ValueNode> parseValue(); | ||||
|     PResult<EnumerationNode> parseEnumeration(); | ||||
| 
 | ||||
|     /** Library types */ | ||||
|     PResult<ValueNode> parseConnectionWire(); | ||||
|     PResult<ComponentNode> parseComponent(); | ||||
|     PResult<EnumNode<ComponentNode::ComponentType>> parseComponentType(); | ||||
|     PResult<AddressSpaceNode> parseAddress(); | ||||
|     PResult<PinNode> parsePin(); | ||||
|     PResult<DisplayNode> parseDisplay(); | ||||
|     PResult<PinConnectionNode> parsePinConnection(); | ||||
|     PResult<AttributeNode> parseAttribute(); | ||||
|     PResult<PopupNode> parsePopup(); | ||||
|     PResult<RuleNode> parseRule(); | ||||
|     PResult<BusNode> parseBus(); | ||||
|     PResult<WireNode> parseWire(); | ||||
|     PResult<ConnectionNode> parseConnection(); | ||||
|     PResult<ConnectionComponentNode> parseConnectionComponent(); | ||||
|     PResult<DisplayItemNode> parseDisplayItem(); | ||||
|     PResult<IfStatementNode> parseIfStatement(); | ||||
|     PResult<EnumNode<BusNode::BusType>> parseBusType(); | ||||
|     PResult<ValueNode> parseValue(); | ||||
| 
 | ||||
|     /** Schema types */ | ||||
| 
 | ||||
|     PResult<CountNode> parsePosition(); | ||||
|     PResult<InstanceNode> parseInstance(); | ||||
|     PResult<InstanceAttributeNode> parseInstanceAttribute(); | ||||
|     PResult<ConnectionInstanceNode> parseConnectionInstance(); | ||||
|     PResult<ConnectionComponentInstanceNode> parseConnectionComponentInstance(); | ||||
| 
 | ||||
| public: | ||||
|     explicit ComdelParser(std::vector<Token> tokens); | ||||
| 
 | ||||
|     ComdelParser(std::vector<Token> tokens); | ||||
|     std::optional<SchemaNode> parseSchema(); | ||||
|     std::optional<LibraryNode> parseLibrary(); | ||||
|     const std::vector<SourceError> &getErrors(); | ||||
|     std::optional<LibraryNode> parse(); | ||||
|     const std::vector<SourceError>& getErrors(); | ||||
| 
 | ||||
|     PResult<EnumNode<ComponentNode::ComponentType>> parseComponentType(); | ||||
| 
 | ||||
|     PResult<EnumNode<BusNode::BusType>> parseBusType(); | ||||
| 
 | ||||
|     PResult<EnumNode<PinConnectionNode::ConnectionType>> parseConnectionType(); | ||||
| }; | ||||
| 
 | ||||
| #endif // COMDEL_PARSER_H
 | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -1,4 +1,4 @@ | ||||
| #include "parse_context.h" | ||||
| #include "parsecontext.h" | ||||
| #include "assert.h" | ||||
| 
 | ||||
| #include <iostream> | ||||
| @ -6,29 +6,31 @@ | ||||
| #include <cmath> | ||||
| 
 | ||||
| 
 | ||||
| ParseContext::ParseContext() { | ||||
| ParseContext::ParseContext() | ||||
| { | ||||
|     applicationDir = std::string(); | ||||
| } | ||||
| 
 | ||||
| unsigned ParseContext::addFile(const std::string &fileName, | ||||
|                                const std::string &source) { | ||||
|     fileMap.emplace_back(fileName, source); | ||||
| unsigned ParseContext::addFile(const std::string& fileName, | ||||
|                                const std::string& source) | ||||
| { | ||||
|     fileMap.push_back(SourceFile(fileName, source)); | ||||
|     return fileMap.size(); | ||||
| } | ||||
| 
 | ||||
| SourceFile &ParseContext::getFile(unsigned fileId) { | ||||
|     return fileMap[fileId - 1]; | ||||
| SourceFile& ParseContext::getFile(unsigned fileId) | ||||
| { | ||||
|     return fileMap[fileId-1]; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| struct pad { | ||||
|     char ch; | ||||
|     int count; | ||||
|     char ch; int count; | ||||
| 
 | ||||
|     pad(char ch, int count) : ch(ch), count(count) {} | ||||
| }; | ||||
| 
 | ||||
| std::ostream &operator<<(std::ostream &stream, const pad &p) { | ||||
| std::ostream& operator<<(std::ostream& stream, const pad& p) { | ||||
|     for (int i = 0; i < p.count; i++) { | ||||
|         stream << p.ch; | ||||
|     } | ||||
| @ -38,13 +40,16 @@ std::ostream &operator<<(std::ostream &stream, const pad &p) { | ||||
| #define ATLAS_ASSERT(x) \ | ||||
|     do {} while(0) | ||||
| 
 | ||||
| void ParseContext::formatError(const SourceError &sourceError, | ||||
|                                std::ostream &stream, | ||||
|                                const std::string &errorOrWarning) { | ||||
| void ParseContext::formatError(const SourceError& sourceError, | ||||
|                                std::ostream& stream, | ||||
|                                const std::string& ErrorOrWarning) | ||||
| { | ||||
|     ATLAS_ASSERT(sourceError.span.lo.col != 0 | ||||
|                  && sourceError.span.hi.col != 0); | ||||
| 
 | ||||
|     stream << errorOrWarning << sourceError.message << std::endl; | ||||
|     SourceFile sourceFile = getFile(sourceError.span.lo.fileId); | ||||
| 
 | ||||
|     stream << ErrorOrWarning << sourceError.message << std::endl; | ||||
| 
 | ||||
|     Span span = sourceError.span; | ||||
| 
 | ||||
| @ -95,17 +100,21 @@ void ParseContext::formatError(const SourceError &sourceError, | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| SourceFile::SourceFile(std::string fileName, std::string source) | ||||
|         : fileName(std::move(fileName)), source(std::move(source)) { | ||||
|     : fileName(std::move(fileName)), source(std::move(source)) | ||||
| { | ||||
|     lineOffsets.push_back(0); | ||||
| } | ||||
| 
 | ||||
| const std::string &SourceFile::getFileName() const { | ||||
| const std::string& SourceFile::getFileName() const | ||||
| { | ||||
|     return fileName; | ||||
| } | ||||
| 
 | ||||
| std::string SourceFile::getLine(unsigned line) const { | ||||
|     auto lineOffset = lineOffsets[line - 1]; | ||||
| const std::string SourceFile::getLine(unsigned line) const | ||||
| { | ||||
|     auto lineOffset = lineOffsets[line-1]; | ||||
|     auto nextLF = source.find('\n', lineOffset); | ||||
|     auto nextCR = source.find('\r', lineOffset); | ||||
|     auto nl = std::min(nextCR, nextLF); | ||||
| @ -113,6 +122,7 @@ std::string SourceFile::getLine(unsigned line) const { | ||||
|     return source.substr(lineOffset, nl - lineOffset); | ||||
| } | ||||
| 
 | ||||
| void SourceFile::addLineOffset(unsigned offset) { | ||||
| void SourceFile::addLineOffset(unsigned offset) | ||||
| { | ||||
|     lineOffsets.push_back(offset); | ||||
| } | ||||
| @ -2,40 +2,40 @@ | ||||
| #define PARSE_CONTEXT_H | ||||
| 
 | ||||
| 
 | ||||
| #include "source_error.h" | ||||
| #include "sourceerror.h" | ||||
| 
 | ||||
| #include <string> | ||||
| #include <vector> | ||||
| 
 | ||||
| /*** Represent source file */ | ||||
| 
 | ||||
| class SourceFile { | ||||
|     std::string fileName; | ||||
|     std::string source; | ||||
|     std::vector<unsigned> lineOffsets; | ||||
| 
 | ||||
| public: | ||||
|     // qqq source je CIJELI comdel fajl,
 | ||||
|     // za inicijalizaciju source se koristi std::move, a možda treba biti referenca???
 | ||||
|     SourceFile(std::string fileName, std::string source); | ||||
| 
 | ||||
|     const std::string &getFileName() const; | ||||
| 
 | ||||
|     std::string getLine(unsigned line) const; | ||||
| 
 | ||||
|     const std::string& getFileName() const; | ||||
|     const std::string getLine(unsigned line) const; | ||||
|     void addLineOffset(unsigned offset); | ||||
| }; | ||||
| 
 | ||||
| /*** Represent parsing context */ | ||||
| class ParseContext { | ||||
| 
 | ||||
| class ParseContext | ||||
| { | ||||
|     std::string applicationDir; | ||||
|     std::vector<SourceFile> fileMap; | ||||
| 
 | ||||
| public: | ||||
|     ParseContext(); | ||||
| 
 | ||||
|     unsigned addFile(const std::string &fileName, const std::string &source); | ||||
|     unsigned addFile(const std::string& fileName, const std::string& source); | ||||
|     SourceFile& getFile(unsigned file); | ||||
| 
 | ||||
|     SourceFile &getFile(unsigned file); | ||||
| 
 | ||||
|     void formatError(const SourceError &sourceError, std::ostream &stream, const std::string &errorOrWarning); | ||||
|     void formatError(const SourceError &sourceError, std::ostream &stream, const std::string& ErrorOrWarning); | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| @ -1,15 +0,0 @@ | ||||
| #ifndef PARSER_UTIL_H | ||||
| #define PARSER_UTIL_H | ||||
| 
 | ||||
| #include "ast_nodes.h" | ||||
| #include "parse_context.h" | ||||
| 
 | ||||
| std::optional<LibraryNode> load_library_from_file(ParseContext *parseContext, | ||||
|                                                   const char *name, | ||||
|                                                   std::ostream &stream); | ||||
| 
 | ||||
| std::optional<SchemaNode> load_schema_from_file(ParseContext *parseContext, | ||||
|                                                 const char *name, | ||||
|                                                 std::ostream &stream); | ||||
| 
 | ||||
| #endif // PARSER_UTIL_H
 | ||||
| @ -1,17 +1,18 @@ | ||||
| #include "comdel_lexer.h" | ||||
| #include "comdel_parser.h" | ||||
| #include "parser_util.h" | ||||
| #include "comdellexer.h" | ||||
| #include "comdelparser.h" | ||||
| #include "parserutil.h" | ||||
| 
 | ||||
| #include <iostream> | ||||
| #include <fstream> | ||||
| #include <string> | ||||
| #include <QDir> | ||||
| 
 | ||||
| std::optional<LibraryNode> load_library_from_file(ParseContext *parseContext, | ||||
|                                                   const char *name, | ||||
|                                                   std::ostream &stream) { | ||||
| std::optional<LibraryNode> loadLibraryFromFile(ParseContext * parseContext, | ||||
|                                                             const char* name, | ||||
|                                                             std::ostream& stream) | ||||
| { | ||||
|     std::ifstream in(name, std::ios::in | std::ios::binary); | ||||
|     if (!in) { | ||||
|     if( ! in ) { | ||||
|         stream << "ERROR: cannot open file '" << name | ||||
|                << "' (file does not exist or is unreadable)" << std::endl; | ||||
|         return std::nullopt; | ||||
| @ -22,17 +23,17 @@ std::optional<LibraryNode> load_library_from_file(ParseContext *parseContext, | ||||
|     ComdelLexer lexer(name, source, parseContext); | ||||
|     LexerResult lexerResult = lexer.tokenize(); | ||||
| 
 | ||||
|     if (!lexerResult.errors.empty()) { | ||||
|         for (auto &error: lexerResult.errors) { | ||||
|     if (lexerResult.errors.size()) { | ||||
|         for (auto& error : lexerResult.errors) { | ||||
|             parseContext->formatError(error, stream, "ERROR: "); | ||||
|         } | ||||
|         return std::nullopt;  // if lexer has found errors => don't parseLibrary
 | ||||
|         return std::nullopt;  // if lexer has found errors => don't parse
 | ||||
|     } | ||||
| 
 | ||||
|     ComdelParser parser(lexerResult.tokens); | ||||
|     auto unit = parser.parseLibrary(); | ||||
|     auto unit = parser.parse(); | ||||
|     if (!unit) { | ||||
|         for (auto &error: parser.getErrors()) { | ||||
|         for (auto& error : parser.getErrors()) { | ||||
|             parseContext->formatError(error, stream, "ERROR: "); | ||||
|         } | ||||
|         return std::nullopt; | ||||
| @ -42,11 +43,12 @@ std::optional<LibraryNode> load_library_from_file(ParseContext *parseContext, | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| std::optional<SchemaNode> load_schema_from_file(ParseContext *parseContext, | ||||
|                                                 const char *name, | ||||
|                                                 std::ostream &stream) { | ||||
| std::optional<SchemaNode> loadSchemaFromFile(ParseContext * parseContext, | ||||
|                                                             const char* name, | ||||
|                                                             std::ostream& stream) | ||||
| { | ||||
|     std::ifstream in(name, std::ios::in | std::ios::binary); | ||||
|     if (!in) { | ||||
|     if( ! in ) { | ||||
|         stream << "ERROR: cannot open file '" << name | ||||
|                << "' (file does not exist or is unreadable)" << std::endl; | ||||
|         return std::nullopt; | ||||
| @ -57,32 +59,32 @@ std::optional<SchemaNode> load_schema_from_file(ParseContext *parseContext, | ||||
|     ComdelLexer lexer(name, source, parseContext); | ||||
|     LexerResult lexerResult = lexer.tokenize(); | ||||
| 
 | ||||
|     if (!lexerResult.errors.empty()) { | ||||
|         for (auto &error: lexerResult.errors) { | ||||
|     if (lexerResult.errors.size()) { | ||||
|         for (auto& error : lexerResult.errors) { | ||||
|             parseContext->formatError(error, stream, "ERROR: "); | ||||
|         } | ||||
|         return std::nullopt;  // if lexer has found errors => don't parseLibrary
 | ||||
|         return std::nullopt;  // if lexer has found errors => don't parse
 | ||||
|     } | ||||
| 
 | ||||
|     ComdelParser parser(lexerResult.tokens); | ||||
|     auto unit = parser.parseSchema(); | ||||
|     if (!unit) { | ||||
|         for (auto &error: parser.getErrors()) { | ||||
|         for (auto& error : parser.getErrors()) { | ||||
|             parseContext->formatError(error, stream, "ERROR: "); | ||||
|         } | ||||
|         return std::nullopt; | ||||
|     } | ||||
| 
 | ||||
|     if (unit->source) { | ||||
|     if(unit->source) { | ||||
|         QFileInfo info(name); | ||||
|         auto filepath = info.absolutePath(); | ||||
|         QDir::setCurrent(filepath); | ||||
| 
 | ||||
|         QDir dir; | ||||
|         dir.setCurrent(filepath); | ||||
| 
 | ||||
|         auto libraryPath = dir.absoluteFilePath(QString::fromStdString(unit->source->asString())); | ||||
| 
 | ||||
|         unit->library = load_library_from_file(parseContext, libraryPath.toUtf8().data(), stream); | ||||
|         if (unit->library == std::nullopt) { | ||||
|         unit->library = loadLibraryFromFile(parseContext, libraryPath.toUtf8().data(), stream); | ||||
|         if(unit->library == std::nullopt) { | ||||
|             return std::nullopt; | ||||
|         } | ||||
|     } | ||||
							
								
								
									
										15
									
								
								comdel/parser/parserutil.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								comdel/parser/parserutil.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
| #ifndef PARSER_UTIL_H | ||||
| #define PARSER_UTIL_H | ||||
| 
 | ||||
| #include "astnode.h" | ||||
| #include "parsecontext.h" | ||||
| 
 | ||||
| std::optional<LibraryNode> loadLibraryFromFile(ParseContext * parseContext, | ||||
|                                                             const char* name, | ||||
|                                                             std::ostream& stream); | ||||
| 
 | ||||
| std::optional<SchemaNode> loadSchemaFromFile(ParseContext * parseContext, | ||||
|                                                             const char* name, | ||||
|                                                             std::ostream& stream); | ||||
| 
 | ||||
| #endif // PARSERUTIL_H
 | ||||
| @ -30,119 +30,142 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||||
| #include <type_traits> | ||||
| #include <typeinfo> | ||||
| 
 | ||||
| namespace detail { | ||||
| namespace detail | ||||
| { | ||||
| 
 | ||||
|     ////////////////////////////////////////////////////////////////////////////
 | ||||
|     // Implementation detail classes
 | ||||
|     ////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
|     template<class T> | ||||
|     struct default_copy { | ||||
|         T *operator()(const T &t) const { | ||||
|     template <class T> | ||||
|     struct default_copy | ||||
|     { | ||||
|         T* operator()(const T& t) const | ||||
|         { | ||||
|             return new T(t); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     template<class T> | ||||
|     struct default_delete { | ||||
|         void operator()(const T *t) const { | ||||
|     template <class T> | ||||
|     struct default_delete | ||||
|     { | ||||
|         void operator()(const T* t) const | ||||
|         { | ||||
|             delete t; | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     template<class T> | ||||
|     struct control_block { | ||||
|     template <class T> | ||||
|     struct control_block | ||||
|     { | ||||
|         virtual ~control_block() = default; | ||||
| 
 | ||||
|         virtual std::unique_ptr<control_block> clone() const = 0; | ||||
| 
 | ||||
|         virtual T *ptr() = 0; | ||||
|         virtual T* ptr() = 0; | ||||
|     }; | ||||
| 
 | ||||
|     template<class T, class U = T> | ||||
|     class direct_control_block : public control_block<T> { | ||||
|     template <class T, class U = T> | ||||
|     class direct_control_block : public control_block<T> | ||||
|     { | ||||
|         static_assert(!std::is_reference<U>::value, ""); | ||||
|         U u_; | ||||
| 
 | ||||
|     public: | ||||
|         template<class... Ts> | ||||
|         explicit direct_control_block(Ts &&... ts) : u_(U(std::forward<Ts>(ts)...)) { | ||||
|         template <class... Ts> | ||||
|         explicit direct_control_block(Ts&&... ts) : u_(U(std::forward<Ts>(ts)...)) | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         std::unique_ptr<control_block<T>> clone() const override { | ||||
|         std::unique_ptr<control_block<T>> clone() const override | ||||
|         { | ||||
|             return std::make_unique<direct_control_block>(*this); | ||||
|         } | ||||
| 
 | ||||
|         T *ptr() override { | ||||
|         T* ptr() override | ||||
|         { | ||||
|             return std::addressof(u_); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     template<class T, class U, class C = default_copy<U>, | ||||
|             class D = default_delete<U>> | ||||
|     class pointer_control_block : public control_block<T>, public C { | ||||
|     template <class T, class U, class C = default_copy<U>, | ||||
|               class D = default_delete<U>> | ||||
|     class pointer_control_block : public control_block<T>, public C | ||||
|     { | ||||
|         std::unique_ptr<U, D> p_; | ||||
| 
 | ||||
|     public: | ||||
|         explicit pointer_control_block(U *u, C c = C{}, D d = D{}) | ||||
|                 : C(std::move(c)), p_(u, std::move(d)) { | ||||
|         explicit pointer_control_block(U* u, C c = C{}, D d = D{}) | ||||
|             : C(std::move(c)), p_(u, std::move(d)) | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         explicit pointer_control_block(std::unique_ptr<U, D> p, C c = C{}) | ||||
|                 : C(std::move(c)), p_(std::move(p)) { | ||||
|             : C(std::move(c)), p_(std::move(p)) | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         std::unique_ptr<control_block<T>> clone() const override { | ||||
|         std::unique_ptr<control_block<T>> clone() const override | ||||
|         { | ||||
|             assert(p_); | ||||
|             return std::make_unique<pointer_control_block>( | ||||
|                     C::operator()(*p_), static_cast<const C &>(*this), p_.get_deleter()); | ||||
|                    C::operator()(*p_), static_cast<const C&>(*this), p_.get_deleter()); | ||||
|         } | ||||
| 
 | ||||
|         T *ptr() override { | ||||
|         T* ptr() override | ||||
|         { | ||||
|             return p_.get(); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     template<class T, class U> | ||||
|     class delegating_control_block : public control_block<T> { | ||||
|     template <class T, class U> | ||||
|     class delegating_control_block : public control_block<T> | ||||
|     { | ||||
|         std::unique_ptr<control_block<U>> delegate_; | ||||
| 
 | ||||
|     public: | ||||
|         explicit delegating_control_block(std::unique_ptr<control_block<U>> b) | ||||
|                 : delegate_(std::move(b)) { | ||||
|             : delegate_(std::move(b)) | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         std::unique_ptr<control_block<T>> clone() const override { | ||||
|         std::unique_ptr<control_block<T>> clone() const override | ||||
|         { | ||||
|             return std::make_unique<delegating_control_block>(delegate_->clone()); | ||||
|         } | ||||
| 
 | ||||
|         T *ptr() override { | ||||
|             return static_cast<T *>(delegate_->ptr()); | ||||
|         T* ptr() override | ||||
|         { | ||||
|             return static_cast<T*>(delegate_->ptr()); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
| 
 | ||||
| } // end namespace detail
 | ||||
| 
 | ||||
| class bad_poly_construction : std::exception { | ||||
| class bad_poly_construction : std::exception | ||||
| { | ||||
| public: | ||||
|     bad_poly_construction() noexcept = default; | ||||
| 
 | ||||
|     const char *what() const noexcept override { | ||||
|     const char* what() const noexcept override | ||||
|     { | ||||
|         return "Dynamic and static type mismatch in poly " | ||||
|                "construction"; | ||||
|                         "construction"; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| template<class T> | ||||
| template <class T> | ||||
| class poly; | ||||
| 
 | ||||
| template<class T> | ||||
| struct is_poly : std::false_type { | ||||
| template <class T> | ||||
| struct is_poly : std::false_type | ||||
| { | ||||
| }; | ||||
| 
 | ||||
| template<class T> | ||||
| struct is_poly<poly<T>> : std::true_type { | ||||
| template <class T> | ||||
| struct is_poly<poly<T>> : std::true_type | ||||
| { | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| @ -150,25 +173,23 @@ struct is_poly<poly<T>> : std::true_type { | ||||
| // `poly` class definition
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| template<class T> | ||||
| class poly { | ||||
| template <class T> | ||||
| class poly | ||||
| { | ||||
|     static_assert(!std::is_union<T>::value, ""); | ||||
|     static_assert(std::is_class<T>::value, ""); | ||||
| 
 | ||||
|     template<class U> | ||||
|     friend | ||||
|     class poly; | ||||
|     template <class U> | ||||
|     friend class poly; | ||||
| 
 | ||||
|     template<class T_, class U, class... Ts> | ||||
|     friend poly<T_> make_poly(Ts &&... ts); | ||||
| 
 | ||||
|     template<class T_, class... Ts> | ||||
|     friend poly<T_> make_poly(Ts &&... ts); | ||||
| 
 | ||||
|     template<class T_, class U> | ||||
|     template <class T_, class U, class... Ts> | ||||
|     friend poly<T_> make_poly(Ts&&... ts); | ||||
|     template <class T_, class... Ts> | ||||
|     friend poly<T_> make_poly(Ts&&... ts); | ||||
|     template <class T_, class U> | ||||
|     friend poly<T_> poly_cast(poly<U> p); | ||||
| 
 | ||||
|     T *ptr_ = nullptr; | ||||
|     T* ptr_ = nullptr; | ||||
|     std::unique_ptr<detail::control_block<T>> cb_; | ||||
| 
 | ||||
| public: | ||||
| @ -183,14 +204,17 @@ public: | ||||
|     // Constructors
 | ||||
|     //
 | ||||
| 
 | ||||
|     poly() { | ||||
|     poly() | ||||
|     { | ||||
|     } | ||||
| 
 | ||||
|     template<class U, class C = detail::default_copy<U>, | ||||
|             class D = detail::default_delete<U>, | ||||
|             class V = std::enable_if_t<std::is_convertible<U *, T *>::value>> | ||||
|     explicit poly(U *u, C copier = C{}, D deleter = D{}) { | ||||
|         if (!u) { | ||||
|     template <class U, class C = detail::default_copy<U>, | ||||
|               class D = detail::default_delete<U>, | ||||
|               class V = std::enable_if_t<std::is_convertible<U*, T*>::value>> | ||||
|     explicit poly(U* u, C copier = C{}, D deleter = D{}) | ||||
|     { | ||||
|         if (!u) | ||||
|         { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
| @ -203,7 +227,7 @@ public: | ||||
|         std::unique_ptr<U, D> p(u, std::move(deleter)); | ||||
| 
 | ||||
|         cb_ = std::make_unique<detail::pointer_control_block<T, U, C, D>>( | ||||
|                 std::move(p), std::move(copier)); | ||||
|               std::move(p), std::move(copier)); | ||||
|         ptr_ = u; | ||||
|     } | ||||
| 
 | ||||
| @ -212,8 +236,10 @@ public: | ||||
|     // Copy-constructors
 | ||||
|     //
 | ||||
| 
 | ||||
|     poly(const poly &p) { | ||||
|         if (!p) { | ||||
|     poly(const poly& p) | ||||
|     { | ||||
|         if (!p) | ||||
|         { | ||||
|             return; | ||||
|         } | ||||
|         auto tmp_cb = p.cb_->clone(); | ||||
| @ -225,7 +251,8 @@ public: | ||||
|     // Move-constructors
 | ||||
|     //
 | ||||
| 
 | ||||
|     poly(poly &&p) noexcept { | ||||
|     poly(poly&& p) noexcept | ||||
|     { | ||||
|         ptr_ = p.ptr_; | ||||
|         cb_ = std::move(p.cb_); | ||||
|         p.ptr_ = nullptr; | ||||
| @ -235,23 +262,25 @@ public: | ||||
|     // Converting constructors
 | ||||
|     //
 | ||||
| 
 | ||||
|     template<class U, | ||||
|             class V = std::enable_if_t<!std::is_same<T, U>::value && | ||||
|                                        std::is_convertible<U *, T *>::value>> | ||||
|     poly(const poly<U> &p) { | ||||
|     template <class U, | ||||
|               class V = std::enable_if_t<!std::is_same<T, U>::value && | ||||
|               std::is_convertible<U*, T*>::value>> | ||||
|     poly(const poly<U>& p) | ||||
|     { | ||||
|         poly<U> tmp(p); | ||||
|         ptr_ = tmp.ptr_; | ||||
|         cb_ = std::make_unique<detail::delegating_control_block<T, U>>( | ||||
|                 std::move(tmp.cb_)); | ||||
|               std::move(tmp.cb_)); | ||||
|     } | ||||
| 
 | ||||
|     template<class U, | ||||
|             class V = std::enable_if_t<!std::is_same<T, U>::value && | ||||
|                                        std::is_convertible<U *, T *>::value>> | ||||
|     poly(poly<U> &&p) { | ||||
|     template <class U, | ||||
|               class V = std::enable_if_t<!std::is_same<T, U>::value && | ||||
|               std::is_convertible<U*, T*>::value>> | ||||
|     poly(poly<U>&& p) | ||||
|     { | ||||
|         ptr_ = p.ptr_; | ||||
|         cb_ = std::make_unique<detail::delegating_control_block<T, U>>( | ||||
|                 std::move(p.cb_)); | ||||
|               std::move(p.cb_)); | ||||
|         p.ptr_ = nullptr; | ||||
|     } | ||||
| 
 | ||||
| @ -259,13 +288,14 @@ public: | ||||
|     // Forwarding constructor
 | ||||
|     //
 | ||||
| 
 | ||||
|     template<class U, class V = std::enable_if_t< | ||||
|             std::is_convertible<std::decay_t<U> *, T *>::value && | ||||
|             !is_poly<std::decay_t<U>>::value>> | ||||
|     poly(U &&u) | ||||
|             : cb_(std::make_unique< | ||||
|             detail::direct_control_block<T, std::decay_t<U>>>( | ||||
|             std::forward<U>(u))) { | ||||
|     template <class U, class V = std::enable_if_t< | ||||
|               std::is_convertible<std::decay_t<U>*, T*>::value && | ||||
|               !is_poly<std::decay_t<U>>::value>> | ||||
|     poly(U&& u) | ||||
|         : cb_(std::make_unique< | ||||
|               detail::direct_control_block<T, std::decay_t<U>>>( | ||||
|               std::forward<U>(u))) | ||||
|     { | ||||
|         ptr_ = cb_->ptr(); | ||||
|     } | ||||
| 
 | ||||
| @ -273,12 +303,15 @@ public: | ||||
|     // Assignment
 | ||||
|     //
 | ||||
| 
 | ||||
|     poly &operator=(const poly &p) { | ||||
|         if (std::addressof(p) == this) { | ||||
|     poly& operator=(const poly& p) | ||||
|     { | ||||
|         if (std::addressof(p) == this) | ||||
|         { | ||||
|             return *this; | ||||
|         } | ||||
| 
 | ||||
|         if (!p) { | ||||
|         if (!p) | ||||
|         { | ||||
|             cb_.reset(); | ||||
|             ptr_ = nullptr; | ||||
|             return *this; | ||||
| @ -295,8 +328,10 @@ public: | ||||
|     // Move-assignment
 | ||||
|     //
 | ||||
| 
 | ||||
|     poly &operator=(poly &&p) noexcept { | ||||
|         if (std::addressof(p) == this) { | ||||
|     poly& operator=(poly&& p) noexcept | ||||
|     { | ||||
|         if (std::addressof(p) == this) | ||||
|         { | ||||
|             return *this; | ||||
|         } | ||||
| 
 | ||||
| @ -311,7 +346,8 @@ public: | ||||
|     // Modifiers
 | ||||
|     //
 | ||||
| 
 | ||||
|     void swap(poly &p) noexcept { | ||||
|     void swap(poly& p) noexcept | ||||
|     { | ||||
|         using std::swap; | ||||
|         swap(ptr_, p.ptr_); | ||||
|         swap(cb_, p.cb_); | ||||
| @ -322,26 +358,31 @@ public: | ||||
|     // Observers
 | ||||
|     //
 | ||||
| 
 | ||||
|     explicit operator bool() const { | ||||
|         return (bool) cb_; | ||||
|     explicit operator bool() const | ||||
|     { | ||||
|         return (bool)cb_; | ||||
|     } | ||||
| 
 | ||||
|     const T *operator->() const { | ||||
|     const T* operator->() const | ||||
|     { | ||||
|         assert(ptr_); | ||||
|         return ptr_; | ||||
|     } | ||||
| 
 | ||||
|     const T &operator*() const { | ||||
|     const T& operator*() const | ||||
|     { | ||||
|         assert(*this); | ||||
|         return *ptr_; | ||||
|     } | ||||
| 
 | ||||
|     T *operator->() { | ||||
|     T* operator->() | ||||
|     { | ||||
|         assert(*this); | ||||
|         return ptr_; | ||||
|     } | ||||
| 
 | ||||
|     T &operator*() { | ||||
|     T& operator*() | ||||
|     { | ||||
|         assert(*this); | ||||
|         return *ptr_; | ||||
|     } | ||||
| @ -350,17 +391,18 @@ public: | ||||
| //
 | ||||
| // poly creation
 | ||||
| //
 | ||||
| template<class T, class... Ts> | ||||
| poly<T> make_poly(Ts &&... ts) { | ||||
| template <class T, class... Ts> | ||||
| poly<T> make_poly(Ts&&... ts) | ||||
| { | ||||
|     poly<T> p; | ||||
|     p.cb_ = std::make_unique<detail::direct_control_block<T, T>>( | ||||
|             std::forward<Ts>(ts)...); | ||||
|     p.ptr_ = p.cb_->ptr(); | ||||
|     return std::move(p); | ||||
| } | ||||
| 
 | ||||
| template<class T, class U, class... Ts> | ||||
| poly<T> make_poly(Ts &&... ts) { | ||||
| template <class T, class U, class... Ts> | ||||
| poly<T> make_poly(Ts&&... ts) | ||||
| { | ||||
|     poly<T> p; | ||||
|     p.cb_ = std::make_unique<detail::direct_control_block<T, U>>( | ||||
|             std::forward<Ts>(ts)...); | ||||
| @ -368,30 +410,32 @@ poly<T> make_poly(Ts &&... ts) { | ||||
|     return std::move(p); | ||||
| } | ||||
| 
 | ||||
| template<class T, class U> | ||||
| const T *poly_view(const poly<U> &p) { | ||||
| template <class T, class U> | ||||
| const T* poly_view(const poly<U>& p) { | ||||
|     if (p) { | ||||
|         return dynamic_cast<const T *>(&*p); | ||||
|     } else { | ||||
|         return dynamic_cast<const T*>(&*p); | ||||
|     } | ||||
|     else { | ||||
|         return nullptr; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| template<class T, class U> | ||||
| T *poly_view(poly<U> &p) { | ||||
| template <class T, class U> | ||||
| T* poly_view(poly<U>& p) { | ||||
|     if (p) { | ||||
|         return dynamic_cast<T *>(&*p); | ||||
|     } else { | ||||
|         return dynamic_cast<T*>(&*p); | ||||
|     } | ||||
|     else { | ||||
|         return nullptr; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| template<class T, class U> | ||||
| template <class T, class U> | ||||
| poly<T> poly_cast(poly<U> p) { | ||||
|     poly<T> ret; | ||||
|     if (T *ptr = dynamic_cast<T *>(&*p)) { | ||||
|     if (T* ptr = dynamic_cast<T*>(&*p)) { | ||||
|         ret.cb_ = std::make_unique<detail::delegating_control_block<T, U>>( | ||||
|                 std::move(p.cb_)); | ||||
|                   std::move(p.cb_)); | ||||
|         ret.ptr_ = ret.cb_->ptr(); | ||||
|     } | ||||
|     return ret; | ||||
|  | ||||
| @ -2,7 +2,7 @@ | ||||
| #define PRESULT_H | ||||
| 
 | ||||
| #include "expected.h" | ||||
| #include "source_error.h" | ||||
| #include "sourceerror.h" | ||||
| 
 | ||||
| #include <optional> | ||||
| 
 | ||||
| @ -32,18 +32,19 @@ using PError = tl::unexpected<SourceError>; | ||||
| 
 | ||||
| /// Holds either an AST node or an error
 | ||||
| /// The value MUST be checked before usage, e.g. using RETURN_IF_ERR
 | ||||
| template<typename T> | ||||
| template <typename T> | ||||
| struct PResult : tl::expected<T, SourceError> { | ||||
|     using tl::expected<T, SourceError>::expected; | ||||
| 
 | ||||
|     /// Implicit conversion from PResult<U> to PResult<T>
 | ||||
|     /// if U is convertible to T
 | ||||
|     template<typename U, class V = std::enable_if_t<std::is_convertible<std::decay_t<U>, T>::value>> | ||||
|     template <typename U, class V = std::enable_if_t<std::is_convertible<std::decay_t<U>, T>::value>> | ||||
|     PResult(PResult<U> presult) : | ||||
|             tl::expected<T, SourceError>(presult ? PResult<T>(*presult) : PError(presult.error())) {} | ||||
|         tl::expected<T, SourceError>(presult ? PResult<T>(*presult) : PError(presult.error())) | ||||
|     {} | ||||
| }; | ||||
| 
 | ||||
| /// Alternative to PResult that is returned from parseLibrary* functions
 | ||||
| /// Alternative to PResult that is returned from parse* functions
 | ||||
| /// that only consume one token so they can fail without affecting
 | ||||
| /// the parser state
 | ||||
| template<typename T> | ||||
|  | ||||
| @ -1,5 +0,0 @@ | ||||
| #include "source_error.h" | ||||
| 
 | ||||
| 
 | ||||
| SourceError::SourceError(Span span, std::string message) | ||||
|         : span(span), message(std::move(message)) {} | ||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user