Compare commits

...

51 Commits

Author SHA1 Message Date
Borna Rajković 6dfe86335d Added cancel to dialogs 2022-06-12 11:51:57 +02:00
Borna Rajković 4d4cf136fb Added pin connection editing 2022-06-09 23:42:45 +02:00
Borna Rajković f66fc1db26 Updated translations + bugfixes 2022-06-09 20:24:27 +02:00
Borna Rajković 1759adf25a Moved connection determination to schema 2022-06-07 21:13:21 +02:00
Borna Rajković 1ec8b10ef5 Fixed schema generation 2022-06-06 01:10:11 +02:00
Borna Rajković 9b7ede933a Added single automatic connection dialog + bugfixes 2022-06-05 19:02:44 +02:00
Borna Rajković 3172d7e4cf Added component/bus deletion and rename 2022-06-02 01:37:14 +02:00
Borna Rajković f93a2afa63 Updated component and bus generation logic + bugfixes 2022-05-31 01:05:08 +02:00
Borna Rajković 86b8861533 Extracted schema and library management to Application 2022-05-30 23:11:06 +02:00
Borna Rajković 0c4afe87d9 Basic refactor 2022-05-27 08:18:17 +02:00
Borna Rajković aac972c6ca Updated bus rendering 2022-05-26 19:22:10 +02:00
Borna Rajković 5cf8235608 Added connection generation 2022-05-25 07:39:45 +02:00
Borna Rajković cbff8ff5f2 Added drag&drop to insert component or bus instances 2022-05-23 08:48:13 +02:00
Borna Rajković 0a658a4aba Added count and pin validators 2022-05-20 00:44:40 +02:00
Borna Rajković 1100a9f0b9 Added connection display 2022-05-19 21:08:00 +02:00
Borna Rajković f11551fef6 Added connection display 2022-05-18 00:14:33 +02:00
Borna Rajković 281926cb8b Added movement storing 2022-05-17 21:31:32 +02:00
Borna Rajković e2e0506041 Added support for @componentHeader 2022-05-16 01:02:34 +02:00
Borna Rajković 59b19062ff Added support for memory attribute 2022-05-15 23:55:03 +02:00
Borna Rajković bb423c2184 Added warning and error dialogs to attribute change 2022-05-15 18:38:17 +02:00
Borna Rajković 65020c2b7f Updated name dialog 2022-05-15 17:00:20 +02:00
Borna Rajković 23764776f1 Updated attribute dialog 2022-05-15 16:13:29 +02:00
Borna Rajković 05fa2abbb0 Refactored function validators 2022-05-15 11:17:05 +02:00
Borna Rajković e7fd7df154 Added display code generation 2022-05-14 15:58:44 +02:00
Borna Rajković 45a668fc46 Added comdel system generation
// todo display generation
2022-05-09 00:51:47 +02:00
Borna Rajković 74a7ef3e7a Refactored instances 2022-05-08 15:47:47 +02:00
Borna Rajković fb8aafb2a9 Updated support for single automatic bus 2022-05-08 14:50:56 +02:00
Borna Rajković 9ff6633777 Removed @wire from schema 2022-05-07 18:28:31 +02:00
Borna Rajković 5ccd9b2fa4 Cleaned up connections 2022-05-07 14:19:43 +02:00
Borna Rajković 344fe7cfa6 Refactor 2022-05-07 13:20:09 +02:00
Borna Rajković dde9bb8af8 Updated error handling while parsing *.csl files 2022-05-01 18:13:01 +02:00
Borna Rajkovic d6c1023df2 Refactored state 2022-04-24 22:21:45 +02:00
Borna Rajkovic 9e2b0f6c3c WIP 2022-04-20 21:50:39 +02:00
Borna Rajkovic 562b77ea0a Adding popups (WIP) 2022-04-19 08:16:41 +02:00
Borna Rajkovic 93e643503e Updated .gitignore 2022-04-18 11:43:56 +02:00
Borna Rajkovic a74bfc4f82 Updated .gitignore 2022-04-18 11:42:25 +02:00
Borna Rajkovic 9f1714d844 Updated schema 2022-04-18 11:41:02 +02:00
Borna Rajković bf029929a7 Added examples and documentation 2022-04-13 00:25:21 +02:00
Borna Rajković c17fbd2dcf Cleanup and support for relative paths 2022-04-12 23:37:05 +02:00
Borna Rajkovic 389113722e Separated components from pins 2022-04-10 17:24:15 +02:00
Borna Rajkovic e8505f9cef Added rule validation 2022-04-10 14:23:18 +02:00
Borna Rajkovic 23e63f7b6f Added log display 2022-04-09 21:11:17 +02:00
Borna Rajkovic 883eaeb10a Updated naming 2022-04-09 20:03:43 +02:00
Borna Rajkovic c65d12a2a1 Added support for direct buses 2022-04-09 19:44:02 +02:00
Borna Rajkovic 7fcfb8c977 Added default pin connection rule 2022-04-09 14:10:40 +02:00
Borna Rajkovic dfc7bf48dc Added support for integers and null to connections 2022-04-08 23:09:19 +02:00
Borna Rajkovic 9bd68ecf23 Typos 2022-04-08 21:07:29 +02:00
Borna Rajkovic 0a0b20a156 Added CMake support 2022-04-08 19:13:53 +02:00
Borna Rajkovic b8bd4a678a Cleaned up property fetching 2022-04-08 18:55:29 +02:00
Borna Rajkovic 4b99a0bf33 Added initial view 2022-04-08 00:21:23 +02:00
Borna Rajkovic 3cdd126927 Added display parsing 2022-04-07 22:40:31 +02:00
114 changed files with 10760 additions and 5565 deletions

13
.gitignore vendored Normal file
View File

@ -0,0 +1,13 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
/cmake-build-debug/**
/.idea/**
**.pro.user
**.pro.user.*

1
.vscode/configurationCache.log vendored Normal file
View File

@ -0,0 +1 @@
{"buildTargets":[],"launchTargets":[],"customConfigurationProvider":{"workspaceBrowse":{"browsePath":[],"compilerArgs":[]},"fileIndex":[]}}

6
.vscode/dryrun.log vendored Normal file
View File

@ -0,0 +1,6 @@
make --dry-run --always-make --keep-going --print-directory
make: Entering directory '/home/bbr/SchemeEditor'
make: Leaving directory '/home/bbr/SchemeEditor'
make: *** No targets specified and no makefile found. Stop.

288
.vscode/targets.log vendored Normal file
View File

@ -0,0 +1,288 @@
make all --print-data-base --no-builtin-variables --no-builtin-rules --question
make: *** No rule to make target 'all'. Stop.
# GNU Make 4.3
# Built for x86_64-pc-linux-gnu
# Copyright (C) 1988-2020 Free Software Foundation, Inc.
# License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
# This is free software: you are free to change and redistribute it.
# There is NO WARRANTY, to the extent permitted by law.
# Make data base, printed on Sun Apr 24 22:18:48 2022
# Variables
# environment
GDK_BACKEND = x11
# environment
LC_ALL = C
# environment
NO_AT_BRIDGE = 1
# environment
VSCODE_IPC_HOOK_EXTHOST = /run/user/1000/vscode-ipc-378bef37-635c-4f71-808d-af9f8b80a929.sock
# environment
LC_NAME = hr_HR.UTF-8
# environment
LC_NUMERIC = hr_HR.UTF-8
# environment
VSCODE_CWD = /home/bbr
# environment
LC_ADDRESS = hr_HR.UTF-8
# default
MAKE_COMMAND := make
# environment
GTK3_MODULES = xapp-gtk3-module
# automatic
@D = $(patsubst %/,%,$(dir $@))
# environment
VSCODE_HANDLES_UNCAUGHT_ERRORS = true
# default
.VARIABLES :=
# environment
PWD = /home/bbr/SchemeEditor
# automatic
%D = $(patsubst %/,%,$(dir $%))
# environment
MAIL = /var/spool/mail/bbr
# environment
XDG_DATA_DIRS = /usr/local/share:/usr/share:/var/lib/snapd/desktop
# automatic
^D = $(patsubst %/,%,$(dir $^))
# environment
VSCODE_LOG_STACK = false
# automatic
%F = $(notdir $%)
# environment
VSCODE_CODE_CACHE_PATH = /home/bbr/.config/Code - OSS/CachedData/e18005f0f1b33c29e81d732535d8c0e47cafb0b5
# environment
XDG_SESSION_PATH = /org/freedesktop/DisplayManager/Session0
# environment
LANG = C
# environment
XAUTHORITY = /home/bbr/.Xauthority
# default
.LOADED :=
# default
.INCLUDE_DIRS = /usr/include /usr/local/include /usr/include
# makefile
MAKEFLAGS = pqrR
# makefile
CURDIR := /home/bbr/SchemeEditor
# environment
VSCODE_PIPE_LOGGING = true
# environment
APPLICATION_INSIGHTS_NO_DIAGNOSTIC_CHANNEL = true
# automatic
*D = $(patsubst %/,%,$(dir $*))
# environment
MFLAGS = -pqrR
# environment
SSH_AUTH_SOCK = /run/user/1000/keyring/ssh
# default
.SHELLFLAGS := -c
# automatic
+D = $(patsubst %/,%,$(dir $+))
# environment
XDG_SESSION_DESKTOP = budgie-desktop
# makefile
MAKEFILE_LIST :=
# automatic
@F = $(notdir $@)
# environment
VSCODE_VERBOSE_LOGGING = true
# environment
VSCODE_PID = 1877190
# environment
XDG_SESSION_TYPE = x11
# automatic
?D = $(patsubst %/,%,$(dir $?))
# environment
SESSION_MANAGER = local/bbr:@/tmp/.ICE-unix/1465,unix/bbr:/tmp/.ICE-unix/1465
# automatic
*F = $(notdir $*)
# environment
QT_QPA_PLATFORMTHEME = qt5ct
# environment
CHROME_DESKTOP = code-oss.desktop
# environment
DBUS_SESSION_BUS_ADDRESS = unix:path=/run/user/1000/bus
# automatic
<D = $(patsubst %/,%,$(dir $<))
# environment
VSCODE_NLS_CONFIG = {"locale":"en-gb","availableLanguages":{},"_languagePackSupport":true}
# default
MAKE_HOST := x86_64-pc-linux-gnu
# makefile
SHELL = /bin/sh
# default
MAKECMDGOALS := all
# environment
DOTNET_BUNDLE_EXTRACT_BASE_DIR = /home/bbr/.cache/dotnet_bundle_extract
# environment
SHLVL = 0
# environment
MAKELEVEL := 0
# default
MAKE = $(MAKE_COMMAND)
# environment
PATH = /home/bbr/.local/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/home/bbr/.dotnet/tools:/usr/lib/jvm/default/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl:/var/lib/snapd/snap/bin
# default
MAKEFILES :=
# environment
LC_MONETARY = hr_HR.UTF-8
# environment
MOTD_SHOWN = pam
# automatic
^F = $(notdir $^)
# environment
LC_TIME = hr_HR.UTF-8
# environment
GRADLE_HOME = /usr/share/java/gradle
# environment
VSCODE_LOG_NATIVE = false
# environment
LC_TELEPHONE = hr_HR.UTF-8
# automatic
?F = $(notdir $?)
# environment
XDG_CURRENT_DESKTOP = Budgie:GNOME
# automatic
+F = $(notdir $+)
# environment
XDG_SEAT_PATH = /org/freedesktop/DisplayManager/Seat0
# environment
DESKTOP_SESSION = budgie-desktop
# environment
ORIGINAL_XDG_CURRENT_DESKTOP = Budgie:GNOME
# 'override' directive
GNUMAKEFLAGS :=
# environment
LOGNAME = bbr
# environment
GIO_LAUNCHED_DESKTOP_FILE = /usr/share/applications/code-oss.desktop
# makefile
.DEFAULT_GOAL :=
# environment
EDITOR = /usr/bin/nano
# environment
DISPLAY = :0
# environment
GTK_MODULES = canberra-gtk-module
# environment
USER = bbr
# default
MAKE_VERSION := 4.3
# environment
LC_MEASUREMENT = hr_HR.UTF-8
# environment
GIO_LAUNCHED_DESKTOP_FILE_PID = 1877159
# environment
_ = /usr/bin/make
# environment
LC_PAPER = hr_HR.UTF-8
# environment
XDG_RUNTIME_DIR = /run/user/1000
# environment
XDG_SESSION_CLASS = user
# environment
VSCODE_AMD_ENTRYPOINT = vs/workbench/api/node/extensionHostProcess
# environment
GTK2_RC_FILES = /home/bbr/.gtkrc-2.0
# environment
HOME = /home/bbr
# environment
ELECTRON_RUN_AS_NODE = 1
# environment
VSCODE_IPC_HOOK = /run/user/1000/vscode-bb99a93f-1.66.0-main.sock
# default
.RECIPEPREFIX :=
# automatic
<F = $(notdir $<)
# default
SUFFIXES :=
# environment
VSCODE_CLI = 1
# environment
ELECTRON_NO_ATTACH_CONSOLE = 1
# environment
XDG_GREETER_DATA_DIR = /var/lib/lightdm-data/bbr
# default
.FEATURES := target-specific order-only second-expansion else-if shortest-stem undefine oneshell nocomment grouped-target extra-prereqs archives jobserver output-sync check-symlink guile load
# environment
XDG_MENU_PREFIX = gnome-
# environment
DOTNET_ROOT = /usr/share/dotnet
# environment
GDMSESSION = budgie-desktop
# environment
LC_IDENTIFICATION = hr_HR.UTF-8
# variable set hash-table stats:
# Load=102/1024=10%, Rehash=0, Collisions=5/129=4%
# Pattern-specific Variable Values
# No pattern-specific variable values.
# Directories
# . (device 66306, inode 9380506): 17 files, no impossibilities.
# 17 files, no impossibilities in 1 directories.
# Implicit Rules
# No implicit rules.
# Files
# Not a target:
Makefile:
# Implicit rule search has been done.
# File does not exist.
# File has been updated.
# Failed to be updated.
# Not a target:
.DEFAULT:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# Not a target:
all:
# Command line target.
# Implicit rule search has been done.
# File does not exist.
# File has not been updated.
# Not a target:
makefile:
# Implicit rule search has been done.
# File does not exist.
# File has been updated.
# Failed to be updated.
# Not a target:
GNUmakefile:
# Implicit rule search has been done.
# File does not exist.
# File has been updated.
# Failed to be updated.
# files hash-table stats:
# Load=6/1024=1%, Rehash=0, Collisions=0/15=0%
# VPATH Search Paths
# No 'vpath' search paths.
# No general ('VPATH' variable) search path.
# strcache buffers: 1 (0) / strings = 25 / storage = 264 B / avg = 10 B
# current buf: size = 8162 B / used = 264 B / count = 25 / avg = 10 B
# strcache performance: lookups = 28 / hit rate = 10%
# hash-table stats:
# Load=25/8192=0%, Rehash=0, Collisions=0/28=0%
# Finished Make data base on Sun Apr 24 22:18:48 2022

41
CMakeLists.txt Normal file
View File

@ -0,0 +1,41 @@
cmake_minimum_required(VERSION 3.9)
project(SchemeEditor)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
find_package(Qt5 CONFIG REQUIRED COMPONENTS Core Gui Widgets)
set(CMAKE_AUTOMOC TRUE)
set(CMAKE_AUTORCC TRUE)
set(CMAKE_AUTOUIC TRUE)
add_executable(SchemeEditor
mainwindow.cpp
comdel/display/component_display.cpp
comdel/display/schema_display.cpp
comdel/display/library_display.cpp
comdel/domain/value.cpp
comdel/domain/schema.cpp
comdel/domain/component.cpp
comdel/domain/connection_instance.cpp
comdel/domain/rule.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/connection.cpp
comdel/domain/instance.cpp
comdel/domain/schema_creator.cpp
comdel/parser/comdel_parser.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
main.cpp
mainwindow.ui
comdel/domain/comdel_validator.cpp comdel/domain/comdel_validator.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 comdel/display/library_list.cpp comdel/display/library_list.h application.cpp application.h comdel/display/single_automatic_dialog.cpp comdel/display/single_automatic_dialog.h)
target_link_libraries(SchemeEditor Qt5::Core Qt5::Gui Qt5::Widgets)

View File

@ -9,65 +9,80 @@ CONFIG += c++17
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
comdel/domain/addressspace.cpp \
comdel/display/attribute_dialog.cpp \
comdel/display/component_display.cpp \
comdel/display/library_display.cpp \
comdel/display/library_list.cpp \
comdel/display/name_dialog.cpp \
comdel/display/schema_display.cpp \
comdel/display/single_automatic_dialog.cpp \
comdel/domain/address_space.cpp \
comdel/domain/attribute.cpp \
comdel/domain/bus.cpp \
comdel/domain/comdelgenerator.cpp \
comdel/domain/comdel_generator.cpp \
comdel/domain/comdel_validator.cpp \
comdel/domain/component.cpp \
comdel/domain/connection.cpp \
comdel/domain/connectioninstance.cpp \
comdel/domain/connection_instance.cpp \
comdel/domain/display.cpp \
comdel/domain/functionsignature.cpp \
comdel/domain/function_signature.cpp \
comdel/domain/instance.cpp \
comdel/domain/instanceattribute.cpp \
comdel/domain/instance_attribute.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/domain/wireinstance.cpp \
comdel/parser/assert.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/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/parser/token.cpp \
comdel/parser/tokenstype.cpp \
comdel/parser/tokens_type.cpp \
application.cpp \
main.cpp \
mainwindow.cpp
HEADERS += \
comdel/domain/addressspace.h \
comdel/display/attribute_dialog.h \
comdel/display/component_display.h \
comdel/display/library_display.h \
comdel/display/library_list.h \
comdel/display/name_dialog.h \
comdel/display/schema_display.h \
comdel/display/single_automatic_dialog.h \
comdel/domain/address_space.h \
comdel/domain/attribute.h \
comdel/domain/bus.h \
comdel/domain/comdelgenerator.h \
comdel/domain/comdel_generator.h \
comdel/domain/comdel_validator.h \
comdel/domain/component.h \
comdel/domain/connection.h \
comdel/domain/connectioninstance.h \
comdel/domain/connection_instance.h \
comdel/domain/display.h \
comdel/domain/functionsignature.h \
comdel/domain/function_signature.h \
comdel/domain/instance.h \
comdel/domain/instanceattribute.h \
comdel/domain/instance_attribute.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/domain/wireinstance.h \
comdel/parser/assert.h \
comdel/parser/astnode.h \
comdel/parser/comdellexer.h \
comdel/parser/comdelparser.h \
comdel/parser/ast_nodes.h \
comdel/parser/comdel_lexer.h \
comdel/parser/comdel_parser.h \
comdel/parser/expected.h \
comdel/parser/parsecontext.h \
comdel/parser/parserutil.h \
comdel/parser/parse_context.h \
comdel/parser/parser_util.h \
comdel/parser/poly.h \
comdel/parser/presult.h \
comdel/parser/sourceerror.h \
comdel/parser/source_error.h \
comdel/parser/token.h \
comdel/parser/tokenstype.h \
comdel/parser/tokens_type.h \
mainwindow.h
FORMS += \

View File

@ -1,268 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 6.0.2, 2022-04-05T08:22:13. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>
<value type="QByteArray">{391729b0-9fcc-4b56-ba51-7d7ee685fc97}</value>
</data>
<data>
<variable>ProjectExplorer.Project.ActiveTarget</variable>
<value type="qlonglong">0</value>
</data>
<data>
<variable>ProjectExplorer.Project.EditorSettings</variable>
<valuemap type="QVariantMap">
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
<value type="QString" key="language">Cpp</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
</valuemap>
</valuemap>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
<value type="QString" key="language">QmlJS</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
</valuemap>
</valuemap>
<value type="qlonglong" key="EditorConfiguration.CodeStyle.Count">2</value>
<value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
<value type="int" key="EditorConfiguration.IndentSize">4</value>
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
<value type="bool" key="EditorConfiguration.PreferSingleLineComments">false</value>
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
<value type="int" key="EditorConfiguration.TabSize">8</value>
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
<value type="bool" key="EditorConfiguration.UseIndenter">false</value>
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
<value type="QString" key="EditorConfiguration.ignoreFileTypes">*.md, *.MD, Makefile</value>
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
<value type="bool" key="EditorConfiguration.skipTrailingWhitespace">true</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.PluginSettings</variable>
<valuemap type="QVariantMap">
<valuemap type="QVariantMap" key="AutoTest.ActiveFrameworks">
<value type="bool" key="AutoTest.Framework.Boost">true</value>
<value type="bool" key="AutoTest.Framework.CTest">false</value>
<value type="bool" key="AutoTest.Framework.Catch">true</value>
<value type="bool" key="AutoTest.Framework.GTest">true</value>
<value type="bool" key="AutoTest.Framework.QtQuickTest">true</value>
<value type="bool" key="AutoTest.Framework.QtTest">true</value>
</valuemap>
<valuemap type="QVariantMap" key="AutoTest.CheckStates"/>
<value type="int" key="AutoTest.RunAfterBuild">0</value>
<value type="bool" key="AutoTest.UseGlobal">true</value>
<valuelist type="QVariantList" key="ClangCodeModel.CustomCommandLineKey"/>
<value type="bool" key="ClangCodeModel.UseGlobalConfig">true</value>
<value type="QString" key="ClangCodeModel.WarningConfigId">Builtin.BuildSystem</value>
<valuemap type="QVariantMap" key="ClangTools">
<value type="bool" key="ClangTools.AnalyzeOpenFiles">true</value>
<value type="bool" key="ClangTools.BuildBeforeAnalysis">true</value>
<value type="QString" key="ClangTools.DiagnosticConfig">Builtin.DefaultTidyAndClazy</value>
<value type="int" key="ClangTools.ParallelJobs">4</value>
<valuelist type="QVariantList" key="ClangTools.SelectedDirs"/>
<valuelist type="QVariantList" key="ClangTools.SelectedFiles"/>
<valuelist type="QVariantList" key="ClangTools.SuppressedDiagnostics"/>
<value type="bool" key="ClangTools.UseGlobalSettings">true</value>
</valuemap>
<valuemap type="QVariantMap" key="CppEditor.QuickFix">
<value type="bool" key="UseGlobalSettings">true</value>
</valuemap>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.Target.0</variable>
<valuemap type="QVariantMap">
<value type="QString" key="DeviceType">Desktop</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{8ccd2350-ba56-4630-b9a6-4b0b4b193aaf}</value>
<value type="qlonglong" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
<value type="qlonglong" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
<value type="qlonglong" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
<value type="int" key="EnableQmlDebugging">0</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/bbr/build-SchemeEditor-Desktop-Debug</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory.shadowDir">/home/bbr/build-SchemeEditor-Desktop-Debug</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
<valuelist type="QVariantList" key="QtProjectManager.QMakeBuildStep.SelectedAbis"/>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Debug</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">2</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.1">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/bbr/build-SchemeEditor-Desktop-Release</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory.shadowDir">/home/bbr/build-SchemeEditor-Desktop-Release</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
<valuelist type="QVariantList" key="QtProjectManager.QMakeBuildStep.SelectedAbis"/>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Release</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
<value type="int" key="QtQuickCompiler">0</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.2">
<value type="int" key="EnableQmlDebugging">0</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/bbr/build-SchemeEditor-Desktop-Profile</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory.shadowDir">/home/bbr/build-SchemeEditor-Desktop-Profile</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
<valuelist type="QVariantList" key="QtProjectManager.QMakeBuildStep.SelectedAbis"/>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Profile</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
<value type="int" key="QtQuickCompiler">0</value>
<value type="int" key="SeparateDebugInfo">0</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.Target.BuildConfigurationCount">3</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Deploy</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
<valuelist type="QVariantList" key="CustomOutputParsers"/>
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4RunConfiguration:/home/bbr/SchemeEditor/SchemeEditor.pro</value>
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">/home/bbr/SchemeEditor/SchemeEditor.pro</value>
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
<value type="bool" key="RunConfiguration.UseLibrarySearchPath">true</value>
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
<value type="QString" key="RunConfiguration.WorkingDirectory.default">/home/bbr/build-SchemeEditor-Desktop-Debug</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.TargetCount</variable>
<value type="qlonglong">1</value>
</data>
<data>
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
<value type="int">22</value>
</data>
<data>
<variable>Version</variable>
<value type="int">22</value>
</data>
</qtcreator>

394
application.cpp Normal file
View File

@ -0,0 +1,394 @@
//
// 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 parsing 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;
}
}

60
application.h Normal file
View File

@ -0,0 +1,60 @@
//
// 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

View File

@ -0,0 +1,283 @@
//
// Created by bbr on 18. 04. 2022..
//
#include "attribute_dialog.h"
#include "mainwindow.h"
#include "application.h"
namespace display {
AttributeDialog::AttributeDialog(domain::InstanceAttribute *attribute, bool updating) {
setAttribute(Qt::WA_DeleteOnClose);
attributeValue = attribute;
auto actionType = updating ? "Izmjeni " : "Postavi ";
this->setWindowTitle(QString::fromStdString(actionType + 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;
default:
throw std::exception();
}
} else if (type == domain::Value::ValueType::BOOL) {
auto *group = new QGroupBox(this);
auto *radioLayout = new QHBoxLayout(group);
group->setLayout(radioLayout);
auto isTrue = new QRadioButton("da", group);
connect(isTrue, &QRadioButton::clicked, [this]() {
this->value = domain::Value::fromBool(true);
});
auto isFalse = new QRadioButton("ne", 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 buttonLayout = new QHBoxLayout(this);
auto okButton = new QPushButton(updating ? "Ažuriraj" : "Postavi", this);
auto cancelButton = new QPushButton("Odustani", this);
connect(okButton, &QPushButton::clicked, this, &AttributeDialog::onUpdate);
connect(cancelButton, &QPushButton::clicked, [this]() { reject(); });
buttonLayout->addWidget(okButton);
buttonLayout->addWidget(cancelButton);
layout->addLayout(buttonLayout);
}
void AttributeDialog::onUpdate() {
auto oldValue = attributeValue->value;
attributeValue->value = value;
domain::ComdelValidator validator(domain::getSupportedValidators());
domain::ValidationContext context;
for (auto &addressSpace: Application::instance()->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 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::exception();
}
}
void AttributeDialog::onEnumerationChanged(int index) {
value = attributeValue->attribute.getPopup()->getEnumeration()[index].getValue();
}
MemoryDialog::MemoryDialog(domain::InstanceAttribute *attribute,
std::vector<std::shared_ptr<domain::ComponentInstance>> instances, bool updating) {
memoryInstances = std::vector<std::string>();
setAttribute(Qt::WA_DeleteOnClose);
attributeValue = attribute;
auto actionType = updating ? "Izmjeni memoriju" : "Postavi memoriju";
this->setWindowTitle(QString::fromStdString(actionType));
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 buttonLayout = new QHBoxLayout(this);
auto okButton = new QPushButton(updating ? "Ažuriraj" : "Postavi");
auto cancelButton = new QPushButton("Odustani", this);
connect(okButton, &QPushButton::clicked, this, &MemoryDialog::onUpdate);
connect(cancelButton, &QPushButton::clicked, [this]() { reject(); });
buttonLayout->addWidget(okButton);
buttonLayout->addWidget(cancelButton);
layout->addLayout(buttonLayout);
}
void MemoryDialog::onUpdate() {
attributeValue->value = value;
accept();
}
void MemoryDialog::onMemoryChanged(int index) {
if (index == memoryInstances.size()) {
value = domain::Value::fromMemoryReference(std::nullopt);
} else {
value = domain::Value::fromMemoryReference(memoryInstances[index]);
}
}
ErrorDialog::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));
}
}
WarningDialog::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->addLayout(buttonLayout);
}
}

View File

@ -0,0 +1,89 @@
#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"
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, 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;
}
}
domain::InstanceAttribute *attributeValue;
public:
AttributeDialog(domain::InstanceAttribute *attribute, bool updating = true);
public slots:
void onTextChanged(const QString &string);
void onEnumerationChanged(int index);
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, bool updating = true);
public slots:
void onMemoryChanged(int index);
void onUpdate();
};
class ErrorDialog : public QDialog {
public:
ErrorDialog(std::vector<domain::ValidationError> errors);
};
class WarningDialog : public QDialog {
public:
WarningDialog(domain::ValidationError error);
};
}
#endif //ATTRIBUTE_DIALOG_H

View File

@ -0,0 +1,324 @@
#include "component_display.h"
#include "attribute_dialog.h"
#include "name_dialog.h"
#include "mainwindow.h"
#include "application.h"
#include "single_automatic_dialog.h"
#include <QMenu>
#include <QLine>
#include <QPen>
#include <QGraphicsSceneContextMenuEvent>
#include <set>
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.getName()));
instance->component.getDisplay().render(this);
}
void Component::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) {
QMenu menu;
menu.addAction("Izmjeni ime", [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.getName()));
});
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();
if(attr->value.getType() == domain::Value::MEMORY_REFERENCE) {
menu.addAction("Izmjeni memoriju", [attr]() {
auto dialog = new MemoryDialog(attr,
Application::instance()->getSchema()->componentInstances);
dialog->exec();
});
} else {
auto action = menu.addAction(QString::fromStdString("Izmjeni '" + attr->name + "'"),
[attr]() {
auto dialog = new AttributeDialog(attr);
dialog->exec();
});
action->setEnabled(enabled);
}
}
menu.addSeparator();
menu.addAction(QString::fromStdString("Ukloni " + this->instance->name), [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("Izmjeni");
auto *remove = menu.addMenu("Ukloni");
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 connectionName = directConnection->attributes[0].value.stringify() + "-" +
directConnection->attributes[1].value.stringify();
update->addAction(QString::fromStdString("Izmjeni " + connectionName), [directConnection]() {
auto dialog = new SingleAutomaticDialog(directConnection->attributes);
dialog->exec();
});
remove->addAction(QString::fromStdString("Ukloni " + connectionName),
[this, directConnection]() {
Application::instance()->removeConnection(directConnection);
auto view = dynamic_cast<Schema *>(this->scene()->views()[0]);
view->refreshContent();
});
}
}
}
} else {
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];
menu.addAction(QString::fromStdString("Izmjeni '" + attr->name + "'"),[attr]() {
auto dialog = new AttributeDialog(attr);
dialog->exec();
});
}
menu.addAction("Ukloni poveznicu", [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("Izmjeni ime", [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.getName()));
});
menu.addSeparator();
menu.addAction(QString::fromStdString("Ukloni " + this->busInstance->name), [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);
}
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() {
auto pin1 = connection->instance->component.getPin(
connection->connection.getComponent().pin).getDisplayPin();
auto pin2 = connection->secondInstance->component.getPin(
connection->connection.getSecondComponent()->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();
}
} // namespace display

View File

@ -0,0 +1,116 @@
#ifndef DISPLAY_COMPONENT_H
#define DISPLAY_COMPONENT_H
#include <comdel/domain/instance.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;
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()));
}
void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override;
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;
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();
};
} // namespace display
#endif // DISPLAY_COMPONENT_H

View File

@ -0,0 +1,52 @@
#include "library_display.h"
#include <QLabel>
#include <QListWidget>
#include <QVBoxLayout>
#include <application.h>
namespace display {
Library::Library() {
auto layout = new QVBoxLayout();
this->setLayout(layout);
componentList = new LibraryList(this);
busList = new LibraryList(this);
layout->setContentsMargins(4, 4, 4, 4);
layout->addWidget(new QLabel("Komponente:"));
layout->addWidget(componentList, 1);
layout->addSpacing(8);
layout->addWidget(new QLabel("Sabirnice:"));
layout->addWidget(busList, 1);
}
void Library::refreshContent() {
library = Application::instance()->getLibrary();
componentList->clear();
busList->clear();
if (!library) {
return;
}
for (auto &component: library->getComponents()) {
auto item = new LibraryListItem{component.getName(), "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.getName(), "comdel/bus", bus.getName(), busList};
item->setToolTip(QString::fromStdString(bus.getTooltip()));
busList->addItem(item);
}
}
}
} // namespace display

View File

@ -0,0 +1,28 @@
#ifndef DISPLAY_LIBRARY_H
#define DISPLAY_LIBRARY_H
#include <QListWidget>
#include <QWidget>
#include <comdel/domain/library.h>
#include "library_list.h"
namespace display {
class Library : public QWidget {
public:
Library();
void refreshContent();
private:
std::optional<domain::Library> library;
LibraryList *componentList;
LibraryList *busList;
};
} // namespace display
#endif // DISPLAY_LIBRARY_H

View File

@ -0,0 +1,32 @@
//
// 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

View File

@ -0,0 +1,34 @@
//
// 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

View File

@ -0,0 +1,50 @@
//
// Created by bbr on 18. 04. 2022..
//
#include <set>
#include "name_dialog.h"
display::NameDialog::NameDialog(std::string currentName, std::set<std::string> &names): currentName(currentName) {
usedNames.erase(currentName);
auto *layout = new QVBoxLayout(this);
layout->addWidget(new QLabel("Izmjeni ime", this));
edit = new QLineEdit(this);
edit->insert(currentName.c_str());
connect(edit, &QLineEdit::textChanged, this, &NameDialog::onNameUpdate);
layout->addWidget(edit);
setWindowTitle("Izmjeni ime");
setLayout(layout);
auto buttonLayout = new QHBoxLayout(this);
auto okButton = new QPushButton("Ažuriraj");
auto cancelButton = new QPushButton("Odustani", this);
connect(okButton, &QPushButton::clicked, this, &NameDialog::onNameChange);
connect(cancelButton, &QPushButton::clicked, [this]() { reject(); });
buttonLayout->addWidget(okButton);
buttonLayout->addWidget(cancelButton);
layout->addLayout(buttonLayout);
}
void display::NameDialog::onNameUpdate(const QString &text) {
if(usedNames.find(text.toStdString()) == usedNames.end()) {
button->setDisabled(false);
} else {
button->setDisabled(true);
}
}
void display::NameDialog::onNameChange() {
currentName = edit->text().toStdString();
close();
}
std::string display::NameDialog::getName() {
return currentName;
}

View File

@ -0,0 +1,36 @@
#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>
namespace display {
class NameDialog : public QDialog {
std::set<std::string> usedNames;
QLineEdit *edit = nullptr;
std::string currentName;
QPushButton *button;
public:
NameDialog(std::string currentName, std::set<std::string>& names);
std::string getName();
public slots:
void onNameUpdate(const QString& text);
void onNameChange();
};
}
#endif //NAME_DIALOG_H

View File

@ -0,0 +1,320 @@
#include "component_display.h"
#include "schema_display.h"
#include "application.h"
#include "attribute_dialog.h"
#include "single_automatic_dialog.h"
#include <QDrag>
#include <QDragEnterEvent>
#include <QMimeData>
namespace display {
Schema::Schema() {
schema = nullptr;
library = std::nullopt;
this->setScene(&scene);
this->setAcceptDrops(true);
}
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::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 rect = pins[pinInstance]->boundingRect();
rect.setX(pins[pinInstance]->scenePos().x());
rect.setY(pins[pinInstance]->scenePos().y());
if (rect.contains(endPoint)) {
auto name = components[pinInstance.component]->getComponentInstance()->component.getName();
auto con = library->getConnection({instance->component.getName(), pin.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;
}
auto conInstance = std::make_shared<domain::DirectConnectionInstance>(instance,
components[pinInstance.component]->getComponentInstance().get(),
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(&attribute, schema->componentInstances, false);
if(dialog->exec() == QDialog::Rejected) {
// if any dialog isn't set, whole creation is rejected
return {};
}
} else {
auto dialog = new AttributeDialog(&attribute, false);
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(instanceAttributes, false);
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

View File

@ -0,0 +1,82 @@
#ifndef DISPLAY_SCHEMA_H
#define DISPLAY_SCHEMA_H
#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 {
Q_OBJECT
public:
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();
};
} // namespace display
#endif // DISPLAY_SCHEMA_H

View File

@ -0,0 +1,84 @@
//
// Created by bbr on 05.06.22..
//
#include "single_automatic_dialog.h"
#include <QVBoxLayout>
#include <QLabel>
#include <QComboBox>
#include <QPushButton>
namespace display {
SingleAutomaticDialog::SingleAutomaticDialog(std::vector<domain::InstanceAttribute> &values, bool updating): attributes(values) {
setAttribute(Qt::WA_DeleteOnClose);
setWindowTitle(QString::fromStdString(updating ? "Ažuriraj poveznicu" : "Postavi poveznicu"));
firstValue = values[0].value;
secondValue = values[1].value;
auto *parentLayout = new QVBoxLayout(this);
auto *contentLayout = new QHBoxLayout(this);
auto *firstLayout = new QVBoxLayout(this);
auto *secondLayout = new QVBoxLayout(this);
parentLayout->addLayout(contentLayout);
contentLayout->addLayout(firstLayout);
contentLayout->addLayout(secondLayout);
this->setLayout(parentLayout);
setupValues(firstLayout, values[0], &SingleAutomaticDialog::onFirstEnumerationChanged);
setupValues(secondLayout, values[1], &SingleAutomaticDialog::onSecondEnumerationChanged);
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);
parentLayout->addLayout(buttonLayout);
}
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();
}
void SingleAutomaticDialog::onUpdate() {
attributes[0].value = firstValue;
attributes[1].value = secondValue;
accept();
}
} // display

View File

@ -0,0 +1,35 @@
//
// Created by bbr on 05.06.22..
//
#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"
namespace display {
class SingleAutomaticDialog: public QDialog {
domain::Value firstValue;
domain::Value secondValue;
std::vector<domain::InstanceAttribute> &attributes;
public:
explicit SingleAutomaticDialog(std::vector<domain::InstanceAttribute>& values, bool updating = true);
void setupValues(QVBoxLayout *layout, domain::InstanceAttribute &attribute, void (display::SingleAutomaticDialog::* handler)(int));
public slots:
void onFirstEnumerationChanged(int index);
void onSecondEnumerationChanged(int index);
void onUpdate();
};
} // display
#endif //SCHEMEEDITOR_SINGLE_AUTOMATIC_DIALOG_H

View File

@ -0,0 +1,29 @@
#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

View File

@ -0,0 +1,29 @@
#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

View File

@ -1,19 +0,0 @@
#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() {
return start;
}
long long AddressSpace::getEnd() {
return end;
}
} // namespace domain

View File

@ -1,26 +0,0 @@
#ifndef DOMAIN_ADDRESSSPACE_H
#define DOMAIN_ADDRESSSPACE_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();
long long getEnd();
};
} // namespace domain
#endif // DOMAIN_ADDRESSSPACE_H

View File

@ -2,55 +2,65 @@
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::getText() {
return text;
}
Popup::PopupType Popup::getType() {
return type;
}
std::vector<Rule> Popup::getRules() {
return rules;
}
std::string Popup::getTitle() {
return title;
}
bool Popup::isEnumerated() {
return enumerated;
}
std::vector<Enumeration> &Popup::getEnumeration() {
return enumeration;
}
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;
}
Attribute::Attribute(std::string name, Value defaultValue, std::optional<Popup> popup)
: name(name), defaultValue(defaultValue), popup(popup)
{}
Attribute::Attribute(std::string name, Value defaultValue, std::optional<Popup> popup)
: name(name), defaultValue(defaultValue), popup(popup) {}
std::string Attribute::getName() {
return name;
}
Value Attribute::getDefault() {
return defaultValue;
}
std::optional<Popup> Attribute::getPopup() {
return popup;
}
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;
}
} // namespace domain

View File

@ -1,64 +1,78 @@
#ifndef DOMAIN_ATTRIBUTE_H
#define DOMAIN_ATTRIBUTE_H
#include <utility>
#include <vector>
#include "rule.h"
#include "value.h"
#include <vector>
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();
Value getValue();
};
std::string &getName();
class Popup {
public:
enum PopupType {
AUTOMATIC,
ON_DEMAND
Value getValue();
};
private:
std::string title;
std::string text;
PopupType type;
class Popup {
public:
enum PopupType {
AUTOMATIC,
ON_DEMAND
};
bool enumerated;
std::vector<Enumeration> enumeration;
std::vector<Rule> rules;
private:
std::string title;
std::string text;
PopupType type;
public:
Popup(std::string title, std::string text, PopupType type, std::vector<Rule> rules, std::vector<Enumeration> enumeration);
bool enumerated;
std::vector<Enumeration> enumeration;
std::vector<Rule> rules;
std::string getTitle();
std::string getText();
PopupType getType();
std::vector<Rule> getRules();
public:
Popup(std::string title, std::string text, PopupType type, std::vector<Rule> rules,
std::vector<Enumeration> enumeration);
bool isEnumerated();
std::vector<Enumeration> &getEnumeration();
std::string getTitle();
};
std::string getText();
class Attribute
{
std::string name;
Value defaultValue;
std::optional<Popup> popup;
public:
Attribute(std::string name, Value defaultValue, std::optional<Popup> popup = std::nullopt);
PopupType getType();
std::string getName();
Value getDefault();
std::optional<Popup> getPopup();
};
std::vector<Rule> getRules();
bool isEnumerated();
std::vector<Enumeration> &getEnumeration();
void setEnumeration(std::vector<Enumeration> enums) {
enumerated = true;
enumeration = enums;
}
};
class Attribute {
std::string name;
Value defaultValue;
std::optional<Popup> popup;
public:
Attribute(std::string name, Value defaultValue, std::optional<Popup> popup = std::nullopt);
std::string getName();
Value getDefault();
std::optional<Popup> getPopup();
void setPupup(std::optional<Popup> popup);
};
} // namespace domain

View File

@ -2,53 +2,64 @@
namespace domain {
Wire::Wire(std::string name, WireType type, int width, bool hidden, bool hasTermination, long long ifUnterminated)
: name(name), type(type), width(width), hidden(hidden), hasTermination(hasTermination), ifUnterminated(ifUnterminated)
{}
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;
}
int Wire::getWidth() {
return width;
}
bool Wire::isHidden() {
return hidden;
}
bool Wire::getHasTermination() {
return hasTermination;
}
long long Wire::getIfUnterminated() {
return ifUnterminated;
}
Wire::WireType Wire::getType() {
return type;
}
std::string Wire::getName() {
return name;
}
std::string Bus::getInstanceName() {
return instanceName;
}
int Wire::getWidth() {
return width;
}
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)
{}
bool Wire::isHidden() {
return hidden;
}
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::hasTerminateWith() {
return hasTerminate;
}
Value Wire::getTerminateWith() {
return terminateWith;
}
Wire::WireType Wire::getType() {
return type;
}
Bus::Bus(std::string name, std::string instanceName, std::string tooltip, BusType type, std::pair<int, int> count, std::vector<Wire> wires,
std::optional<ui::Bus> displayBus)
: name(name), instanceName(instanceName), tooltip(tooltip), type(type), count(count), wires(wires), displayBus(displayBus) {}
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::vector<Wire> Bus::getWires() {
return wires;
}
std::optional<ui::Bus> Bus::getDisplayBus() {
return displayBus;
}
} // namespace domain

View File

@ -2,6 +2,7 @@
#define DOMAIN_BUS_H
#include "display.h"
#include "value.h"
#include <string>
#include <optional>
@ -10,63 +11,75 @@
namespace domain {
class Wire
{
public:
enum WireType {
WIRE_DEFAULT,
WIRED_AND,
WIRED_OR,
R_WIRE
class Wire {
public:
enum WireType {
WIRE_DEFAULT,
WIRED_AND,
WIRED_OR,
R_WIRE
};
private:
std::string name;
WireType type;
int width;
bool hidden;
bool hasTerminate;
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 Bus {
public:
enum BusType {
AUTOMATIC,
REGULAR,
SINGLE_AUTOMATIC
};
private:
std::string name;
std::string instanceName;
std::string tooltip;
BusType type;
private:
std::string name;
WireType type;
int width;
bool hidden;
bool hasTermination;
long long ifUnterminated;
std::pair<int, int> count;
std::optional<ui::Bus> displayBus;
std::vector<Wire> wires;
public:
Wire(std::string name, WireType type, int width, bool hidden, bool hasTermination, long long ifUnterminated);
public:
Bus(std::string name, std::string instanceName, std::string tooltip, BusType type, std::pair<int, int> count, std::vector<Wire> wires,
std::optional<ui::Bus> display = std::nullopt);
std::string getName();
int getWidth();
bool isHidden();
bool getHasTermination();
long long getIfUnterminated();
WireType getType();
};
std::string getName();
class Bus
{
public:
enum BusType {
AUTOMATIC,
REGULAR,
AUTOMATIC_SINGLE
std::string getInstanceName();
std::string getTooltip();
BusType getType();
std::pair<int, int> getCount();
std::vector<Wire> getWires();
std::optional<ui::Bus> getDisplayBus();
};
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

View File

@ -0,0 +1,375 @@
//
// Created by bbr on 08.05.22..
//
#include <set>
#include "comdel_generator.h"
namespace domain {
void generate_schema(std::string &librarySource, Schema *schema, std::ostream &buffer) {
buffer << "@source \"" << librarySource << "\"" << std::endl << 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 &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;
}
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 << "}" << 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) {
buffer << "\t\tline {x1:" << connection->start.first << "; y1:" << connection->start.second << "; " <<
"x2:" << connection->end.first << "; y2:" << connection->end.second << ";}" << "\n";
}
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()) {
std::string name = wire.getName();
if (usedNames.count(wire.getName()) > 0) {
name = bus->name + "__" + wire.getName();
}
if (wire.isHidden()) {
name = "--" + name;
}
usedNames.insert(name);
usedMappings.insert(std::make_pair(bus->name + "." + wire.getName(), name));
generateWire(name, wire, buffer);
}
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";
}
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;
}
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 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;
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;
}
}
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;
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 {
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);
} else {
generateSingleAutomaticPin(dirConn, component->name, 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
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() << ", ";
}
} 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() << ", ";
}
}
}
}
} // domain

View File

@ -0,0 +1,16 @@
#ifndef COMDEL_GENERATOR_H
#define COMDEL_GENERATOR_H
#include <sstream>
#include "schema.h"
#include "library.h"
namespace domain {
void generate_schema(std::string &librarySource, Schema *schema, std::ostream &buffer);
void generate_comdel(Schema *schema, Library &library, std::ostream &buffer);
} // domain
#endif //COMDEL_GENERATOR_H

View File

@ -0,0 +1,255 @@
#include <set>
#include "comdel_validator.h"
#include "library.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.getName());
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 = populateMessage(
"Nedovoljno instanci komponente '{componentName}' potrebno barem {min}, pronađeno {count}",
context);
errors.emplace_back(Action::ERROR, message);
} else if (count > comp.getCount().second) {
auto message = populateMessage(
"Previše insanci komponente '{componentName}' dozvoljeno najviše {max}, pronađeno {count}", context);
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.getName());
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 = populateMessage(
"Nedovoljno instanci sabirnice '{busName}' potrebna barem jedna {min}, pronađeno {count}", context);
errors.emplace_back(Action::ERROR, message);
} else if (count > bus.getCount().second) {
auto message = populateMessage(
"Previše instanci sabirnice '{busName}' dozvoljeno najviše {max}, pronašeno {count}", context);
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().getType() == PinConnection::REQUIRED) {
if (!connectionExists(schema, inst, pin)) {
context.instance = inst.get();
context.attributes["instanceName"] = Value::fromString(inst->name);
auto message = populateMessage(pin.getConnection().getMessage(), context);
errors.emplace_back(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) {
std::string message = this->populateMessage(action->getMessage(), context);
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 = populateMessage("Ne postoji memorijska komponenta '{memoryReference}'", context);
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.attributes["componentName"] = Value::fromString(component->name);
auto message = populateMessage(
"Pronađeno više instanci sa imenom '{componentName}'", context);
errors.emplace_back(Action::ERROR, message);
}
names.insert(component->name);
}
return errors;
}
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;
}
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()) {
return true;
}
if (directConnection->secondInstance->name == component->name &&
directConnection->connection.getSecondComponent()->pin == pin.getName()) {
return true;
}
}
}
return false;
}
ComdelValidator::ComdelValidator(std::vector<FunctionValidator *> validators) {
for (auto *validator: validators) {
validator->clear();
this->validators.insert(std::make_pair(validator->getName(), validator));
}
}
}

View File

@ -0,0 +1,60 @@
#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;
};
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;
std::string populateMessage(string message, ValidationContext context);
string replacePlaceholder(string message, const string name, Value value);
bool connectionExists(Schema &schema, shared_ptr<ComponentInstance> &component, Pin &pin);
};
}
#endif //COMDEL_VALIDATOR_H

View File

@ -1,697 +0,0 @@
#include "comdelgenerator.h"
#include<set>
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::WIRE:
return Value::WIRE_REFERENCE;
case ValueNode::STRING:
return Value::STRING;
case ValueNode::INT:
return Value::INT;
default:
return Value::UNDEFINED;
}
}
Value toType(ValueNode node) {
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());
}
return Value::fromReference(node.asIdentifier(), Value::UNDEFINED);
}
Bus::BusType toType(BusNode::BusType type) {
if(type == BusNode::AUTOMATIC) {
return Bus::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::AUTOMATICALLY) {
return PinConnection::AUTOMATICALLY;
}
return PinConnection::CHECK_ONLY;
}
Popup::PopupType toType(PopupNode::PopupType type)
{
if(type == PopupNode::AUTOMATIC) {
return Popup::AUTOMATIC;
}
return Popup::ON_DEMAND;
}
ComdelGenerator::ComdelGenerator(std::vector<FunctionSignature> signatures)
: signatures(signatures)
{}
std::optional<Library> ComdelGenerator::loadLibrary(LibraryNode node)
{
// library fields
if(!node.name) {
errors.push_back(SourceError{node.span, "missing @name"});
return nullopt;
} else {
name = node.name->asString();
}
if(!node.componentDirectory) {
errors.push_back(SourceError{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(uint i=0; i<node.buses.size(); i++) {
auto bus = loadBus(node.buses[i]);
if(bus) {
buses.push_back(*bus);
}
}
for(uint i=0; i<node.connections.size(); i++) {
auto conn = loadConnection(node.connections[i]);
if(conn) {
connections.push_back(*conn);
}
}
for(uint i=0; i<node.messages.size(); i++) {
if(!node.messages[i].value.is(ValueNode::STRING)) {
errors.push_back(SourceError{node.messages[i].span, "expected `string`"});
} else {
messages[node.messages[i].key.value] = node.messages[i].value.asString();
}
}
return Library(name, libraryInfo, header, componentDirectory, addressSpaces, components, buses, connections, messages);
}
std::optional<Bus> ComdelGenerator::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.push_back(SourceError{node.count->span, "invalid @size"});
return nullopt;
}
auto type = toType(node.type);
if(!node.tooltip && type == Bus::REGULAR) {
errors.push_back(SourceError{node.span, "missing @tooltip"});
return nullopt;
}
std::string tooltip = node.tooltip->asString();
if(!node.display && type == Bus::REGULAR) {
errors.push_back(SourceError{node.span, "missing @display"});
return nullopt;
}
if(node.display && (type == Bus::AUTOMATIC || type == Bus::AUTOMATIC_SINGLE)) {
errors.push_back(SourceError{node.span, "automatic bus cannot have a @display"});
return nullopt;
}
optional<Display> display;
if(Bus::REGULAR) {
display = loadDisplay(*node.display);
if(!display) {
return nullopt;
}
}
if(node.wires.size() == 0) {
errors.push_back(SourceError{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);
}
}
return Bus(name, tooltip, type, count, wires, display);
}
std::optional<AddressSpace> ComdelGenerator::loadAddressSpace(AddressSpaceNode node)
{
return AddressSpace(node.name.value, node.start.value, node.end.value);
}
std::optional<Connection> ComdelGenerator::loadConnection(ConnectionNode node)
{
push(ComdelContext("connection", false, true, false));
std::string component = node.component.value;
std::string pin = node.pin.value;
std::string bus = node.bus.value;
auto componentInstance = getComponentPin(component, pin);
if(!componentInstance) {
errors.push_back(SourceError(node.span, "pin does not exist"));
}
auto busInstance = getBus(bus);
if(!busInstance) {
errors.push_back(SourceError(node.span, "bus does not exist"));
}
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(uint i=0; i<node.attributes.size(); i++) {
auto attr = loadAttribute(node.attributes[i]);
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(uint i=0; i<node.wires.size(); i++) {
if(attributeNames.count(node.wires[i].value)) {
wires.push_back(Value::fromReference(node.wires[i].value, Value::ATTRIBUTE_REFERENCE));
} else if(wireNames.count(node.wires[i].value)) {
wires.push_back(Value::fromReference(node.wires[i].value, Value::WIRE_REFERENCE));
} else {
errors.push_back(SourceError(node.wires[i].span, "unknown identifier"));
}
}
pop();
return Connection(component, pin, bus, attributes, wires);
}
std::optional<Component> ComdelGenerator::loadComponent(ComponentNode node)
{
push(ComdelContext(node.name.value, true, false, false));
std::string name = node.name.value;
if(!node.tooltip) {
errors.push_back(SourceError{node.span, "missing @tooltip"});
pop();
return nullopt;
}
std::string tooltip = node.tooltip->asString();
if(!node.source) {
errors.push_back(SourceError{node.span, "missing @source"});
pop();
return nullopt;
}
std::string source = node.source->asString();
Component::ComponentType type = toType(node.type);
std::vector<Attribute> attributes;
for(auto& a: node.attributes) {
std::optional<Attribute> attribute = loadAttribute(a);
if(attribute) {
attributes.push_back(*attribute);
}
}
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.push_back(SourceError{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.push_back(SourceError{node.count->first.span, "invalid @size"});
pop();
return nullopt;
}
if(!node.display) {
errors.push_back(SourceError{node.span, "missing @display"});
pop();
return nullopt;
}
optional<Display> display = loadDisplay(*node.display);
if(!display) {
pop();
return nullopt;
}
std::vector<Pin> pins;
for(uint i=0; i<node.pins.size(); i++) {
auto pin = loadPin(node.pins[i]);
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> ComdelGenerator::loadWire(WireNode node) {
return Wire(
node.name.value,
toType(node.type),
node.size.value,
node.hidden,
node.hasTermination,
node.isUnterminated
);
}
optional<Pin> ComdelGenerator::loadPin(PinNode node)
{
std::string name = node.name.value;
Pin::PinType type = toType(node.type);
if(!node.tooltip) {
errors.push_back(SourceError{node.span, "missing @tooltip"});
return nullopt;
}
std::string tooltip = node.tooltip->asString();
if(!node.display) {
errors.push_back(SourceError{node.span, "missing @display"});
return nullopt;
}
std::vector<Attribute> attributes;
optional<Display> display = loadDisplay(*node.display);
if(!display) {
return nullopt;
}
if(!node.connection) {
errors.push_back(SourceError{node.span, "missing @connection"});
return nullopt;
}
auto connection = loadPinConnection(*node.connection);
return Pin(name, type, tooltip, connection, *display);
}
std::optional<Display> ComdelGenerator::loadDisplay(DisplayNode node)
{
return Display();
}
PinConnection ComdelGenerator::loadPinConnection(PinConnectionNode node)
{
std::string message = node.message.asString();
PinConnection::ConnectionType type = toType(node.type);
return PinConnection(message, type);
}
std::optional<Attribute> ComdelGenerator::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.push_back(SourceError{node.name.span, "unsupported type"});
}
}
if(current().inConnection) { // 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.push_back(SourceError{node.span, "unknown identifier"});
}
} else {
errors.push_back(SourceError{node.name.span, "unsupported type"});
}
}
current().attributes.push_back(Attribute(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> ComdelGenerator::loadPopup(PopupNode node, std::string name, Value::ValueType type)
{
auto popupType = toType(*node.type);
pushAdditional(name);
current().attributes.clear();
current().attributes.push_back(Attribute(name, Value::ofType(type)));
if(!node.title) {
errors.push_back(SourceError{node.span, "missing @title"});
return nullopt;
}
std::string title = node.title->asString();
if(!node.text) {
errors.push_back(SourceError{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(uint i=0; i<node.enumeration.size(); i++) {
if(toType(node.enumeration[i].value.getType()) != type) {
}
auto value = toType(node.enumeration[i].value);
if(value.isType(Value::UNDEFINED) && current().doesWireExists(value.asReference())) {
value = Value::fromReference(value.asReference(), Value::WIRE_REFERENCE);
} else {
errors.push_back(SourceError{node.enumeration[i].span, "unknown wire"});
}
if(value.getType() != type) {
errors.push_back(SourceError{node.enumeration[i].span, "wrong type"});
}
enumeration.push_back(Enumeration(node.enumeration[i].key.asString(), value));
}
} else {
if(type == Value::WIRE_REFERENCE && !current().inConnection) {
errors.push_back(SourceError{node.span, "@enumeration is required for atributes of type wire"});
}
}
pop();
return Popup(title, text, popupType, rules, enumeration);
}
std::optional<Rule> ComdelGenerator::loadRule(RuleNode node)
{
std::vector<IfStatement> statements;
for(auto& stmt: node.statements) {
auto condition = loadCondition(stmt.condition);
if(condition) {
statements.push_back(IfStatement(*condition, Action(toType(stmt.action.type), stmt.action.message.asString())));
} else {
return nullopt;
}
}
return Rule(statements);
}
std::optional<Condition> ComdelGenerator::loadCondition(ConditionNode node)
{
std::string function = node.functionName.value;
for(uint i=0; i<signatures.size(); i++) {
if(signatures[i].name == function) {
if(signatures[i].params.size() == node.params.size()) {
std::vector<Value> params;
for(uint j=0; j<signatures[i].params.size(); j++) {
bool exists = false;
auto type = toType(node.params[j]);
if (type.getType() == Value::UNDEFINED) {
if(current().doesAttributeExists(type.asReference(), signatures[i].params[j])) {
exists = true;
type = Value::fromReference(type.asReference(), Value::ATTRIBUTE_REFERENCE);
}
if(signatures[i].params[j] == Value::ADDRESS_SPACE) {
if(hasAddressSpace(type.asReference())) {
exists = true;
type = Value::fromReference(type.asReference(), Value::ADDRESS_SPACE);
}
}
if(!exists) {
errors.push_back(SourceError{node.functionName.span, "unknown reference " + type.asReference()});
}
}
params.push_back(type);
}
return Condition(function, params, node.negated);
} else {
errors.push_back(SourceError{node.functionName.span, "wrong number of parametars"});
}
}
}
errors.push_back(SourceError{node.functionName.span, "unknown function name"});
return nullopt;
}
std::optional<Schema> ComdelGenerator::loadSchema(SchemaNode node, Library &library)
{
Schema schema;
for(auto &instance: node.instances) {
if(library.hasComponent(instance.component.value)) {
schema.instances.push_back(loadComponentInstance(instance, library));
}
if(library.hasBus(instance.component.value)) {
schema.instances.push_back(loadBusInstance(instance, library));
}
}
for(auto &wire: node.wires) {
auto w = loadWireInstance(wire);
if(w) {
schema.wires.push_back(*w);
}
}
for(auto &conn: node.connections) {
auto component = dynamic_cast<ComponentInstance*>(schema.getInstance(conn.instance.value));
if(component == NULL) {
errors.push_back(SourceError{conn.instance.span, "unknown component"});
continue;
}
if(!component->component.hasPin(conn.pin.value)) {
errors.push_back(SourceError{conn.pin.span, "unknown pin"});
continue;
}
auto bus = dynamic_cast<BusInstance*>(schema.getInstance(conn.bus.value));
if(bus == NULL) {
errors.push_back(SourceError{conn.bus.span, "unknown bus"});
continue;
}
if(!library.hasConnection(component->component.getName(), conn.pin.value, bus->bus.getName())) {
errors.push_back(SourceError{conn.span, "unknown connection"});
continue;
}
auto connection = *library.getConnection(component->component.getName(), conn.pin.value, bus->bus.getName());
if(!conn.wire) {
errors.push_back(SourceError{conn.span, "missing @wire"});
continue;
}
if(!schema.hasWire(conn.wire->value)) {
errors.push_back(SourceError{conn.wire->span, "unknown wire"});
continue;
}
auto wire = schema.getWire(conn.wire->value);
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.push_back(SourceError{attr.span, "invalid value"});
}
attributes.push_back(new InstanceAttribute(attribute.getName(), toType(attr.value), attribute));
} else {
errors.push_back(SourceError(attr.name.span, "unknown attribute"));
}
}
schema.connections.push_back(new BusConnectionInstance(component, attributes, bus, wire, connection));
}
return schema;
}
ComponentInstance *ComdelGenerator::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.push_back(new InstanceAttribute(attribute.getName(), toType(attr.value), attribute));
} else {
errors.push_back(SourceError(attr.name.span, "unknown attribute"));
}
}
return new ComponentInstance(name, attributes, position, component);
}
BusInstance *ComdelGenerator::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 new BusInstance(name, position, bus, size);
}
std::optional<WireInstance*> ComdelGenerator::loadWireInstance(WireInstanceNode node) {
if(!node.display) {
errors.push_back(SourceError{node.span, "missing @text"});
return nullopt;
}
auto display = loadDisplay(*node.display);
if(!display) {
return nullopt;
}
return std::optional<WireInstance*>(new WireInstance(node.name.value, *display));
}
} // namespace domain

View File

@ -1,146 +0,0 @@
#ifndef DOMAIN_COMDELGENERATOR_H
#define DOMAIN_COMDELGENERATOR_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 inBus;
ComdelContext(std::string name, bool inComponent, bool inConnection, bool inBus)
: name(name), inComponent(inComponent), inConnection(inConnection), 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 ComdelGenerator
{
std::vector<ComdelContext> context;
std::string name;
std::string libraryInfo;
std::string header;
std::string componentDirectory;
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<FunctionSignature> signatures;
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);
ComponentInstance *loadComponentInstance(InstanceNode instance, Library &library);
BusInstance *loadBusInstance(InstanceNode instance, Library &library);
std::optional<WireInstance*> loadWireInstance(WireInstanceNode node);
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.size() > 0) {
this->context.push_back(current());
current().name = name;
} else {
ComdelContext con(name, false, false, false);
push(con);
}
}
ComdelContext &current() {
return this->context[this->context.size() - 1];
}
void pop() {
this->context.pop_back();
}
public:
ComdelGenerator(std::vector<FunctionSignature> signatures);
std::vector<SourceError> getErrors() {
return errors;
}
std::optional<Library> loadLibrary(LibraryNode node);
std::optional<Schema> loadSchema(SchemaNode node, Library &library);
};
} // namespace domain
#endif // DOMAIN_COMDELGENERATOR_H

View File

@ -1,18 +0,0 @@
#include "comdelvalidator.h"
namespace domain {
ComdelValidator::ComdelValidator(std::vector<FunctionSignature> signatures)
: signatures(signatures)
{}
std::vector<SourceError> ComdelValidator::getErrors() {
return errors;
}
void validateLibrary(Library library, ParseContext* parseContext, std::ostream& stream) {
}
} // namespace domain

View File

@ -1,34 +0,0 @@
#ifndef DOMAIN_COMDELVALIDATOR_H
#define DOMAIN_COMDELVALIDATOR_H
#include "functionsignature.h"
#include "library.h"
#include <vector>
#include <comdel/parser/parsecontext.h>
#include <comdel/parser/sourceerror.h>
namespace domain {
class ComdelValidator
{
private:
std::vector<SourceError> errors;
std::vector<FunctionSignature> signatures;
public:
ComdelValidator(std::vector<FunctionSignature> signatures);
std::vector<SourceError> getErrors() {
return errors;
}
void validateLibrary(Library library, ParseContext* parseContext, std::ostream& stream);
};
} // namespace domain
#endif // DOMAIN_COMDELVALIDATOR_H

View File

@ -2,78 +2,97 @@
namespace domain {
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)
{}
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::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(uint i=0; i<pins.size(); i++) {
if(pins[i].getName() == pin) {
return pins[i];
}
std::string Component::getName() {
return name;
}
throw std::exception();
}
bool Component::hasPin(std::string name) {
for(auto pin: pins) {
if(pin.getName() == name) {
return true;
}
std::string Component::getTooltip() {
return tooltip;
}
return false;
}
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];
}
std::string Component::getSource() {
return source;
}
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;
}
}
return false;
}
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;
}
}
throw std::exception();
}
bool Component::hasPin(std::string name) {
for (auto pin: pins) {
if (pin.getName() == name) {
return true;
}
}
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 (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;
}
}
return false;
}
} // namespace domain

View File

@ -11,56 +11,65 @@
namespace domain {
using namespace std;
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);
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

View File

@ -2,47 +2,78 @@
namespace domain {
Connection::Connection(std::string component, std::string pin, std::string bus, std::vector<Attribute> attributes, std::vector<Value> wires)
: component(component), pin(pin), bus(bus), attributes(attributes), wires(wires)
{}
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) {}
bool Connection::isConnecting(std::string component, std::string pin, std::string bus) {
return this->component == component && this->pin == pin && this->bus == bus;
}
std::string Connection::getComponent() {
return component;
}
std::string Connection::getPin() {
return pin;
}
std::string Connection::getBus() {
return bus;
}
std::vector<Attribute> Connection::getAttributes() {
return attributes;
}
std::vector<Value> Connection::getWires() {
return wires;
}
Attribute Connection::getAttribute(std::string name) {
for(uint i=0; i<attributes.size(); i++) {
if(attributes[i].getName() == name) {
return attributes[i];
}
ConnectionComponent Connection::getComponent() {
return first;
}
throw std::exception();
}
bool Connection::hasAttribute(std::string name) {
for(uint i=0; i<attributes.size(); i++) {
if(attributes[i].getName() == name) {
return true;
}
std::optional<ConnectionComponent> Connection::getSecondComponent() {
return second;
}
return false;
}
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;
}
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::exception();
}
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;
}
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);
}
} // namespace domain

View File

@ -8,29 +8,71 @@
namespace domain {
class Connection
{
std::string component;
std::string pin;
std::string bus;
struct ConnectionComponent {
std::string component;
std::string pin;
std::vector<Attribute> attributes;
std::vector<Value> wires;
public:
Connection(std::string component, std::string pin, std::string bus, std::vector<Attribute> attributes, std::vector<Value> wires);
bool operator==(const ConnectionComponent &rhs) const {
return (component == rhs.component) && (pin == rhs.pin);
}
bool isConnecting(std::string component, std::string pin, std::string bus);
bool operator!=(const ConnectionComponent &rhs) const {
return !operator==(rhs);
}
std::string getComponent();
std::string getPin();
std::string getBus();
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<Attribute> getAttributes();
std::vector<Value> getWires();
class Connection {
ConnectionComponent first;
std::optional<ConnectionComponent> second;
std::string bus;
std::vector<Attribute> attributes;
Attribute getAttribute(std::string name);
bool hasAttribute(std::string name);
};
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);
bool isConnecting(ConnectionComponent first, std::string bus);
bool isConnecting(ConnectionComponent first, std::string bus, ConnectionComponent second);
bool isConnecting(ConnectionComponent first, ConnectionComponent second);
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);
};
} // namespace domain

View File

@ -0,0 +1,29 @@
#include "connection_instance.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

View File

@ -0,0 +1,49 @@
#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);
};
} // namespace domain
#endif // DOMAIN_CONNECTIONINSTANCE_H

View File

@ -1,18 +0,0 @@
#include "connectioninstance.h"
namespace domain {
ConnectionInstance::ConnectionInstance(ComponentInstance *instance, std::vector<InstanceAttribute*> attributes, WireInstance *wire, Connection connection)
: instance(instance), attributes(attributes), connection(connection), wire(wire)
{}
BusConnectionInstance::BusConnectionInstance(ComponentInstance *instance, std::vector<InstanceAttribute*> attributes, BusInstance *bus, WireInstance *wire, Connection connection)
: ConnectionInstance(instance, attributes, wire, connection), bus(bus)
{}
DirectConnectionInstance::DirectConnectionInstance(ComponentInstance *instance, ComponentInstance *secondsInstance, std::vector<InstanceAttribute*> attributes, BusInstance *bus, WireInstance *wire, Connection connection)
: ConnectionInstance(instance, attributes, wire, connection), secondInstance(secondInstance), bus(bus)
{}
} // namespace domain

View File

@ -1,46 +0,0 @@
#ifndef DOMAIN_CONNECTIONINSTANCE_H
#define DOMAIN_CONNECTIONINSTANCE_H
#include "connection.h"
#include "instance.h"
#include "wireinstance.h"
namespace domain {
class ConnectionInstance
{
public:
ComponentInstance *instance;
Connection connection;
WireInstance *wire;
std::vector<InstanceAttribute*> attributes;
ConnectionInstance(ComponentInstance *instance, std::vector<InstanceAttribute*> attributes, WireInstance *wire, Connection connection);
};
class BusConnectionInstance: public ConnectionInstance
{
public:
BusInstance *bus;
BusConnectionInstance(ComponentInstance *instance, std::vector<InstanceAttribute*> attributes, BusInstance *bus, WireInstance *wire, Connection connection);
};
class DirectConnectionInstance: public ConnectionInstance
{
public:
BusInstance *bus;
ComponentInstance *secondInstance;
DirectConnectionInstance(ComponentInstance *instance, ComponentInstance *secondsInstance, std::vector<InstanceAttribute*> attributes, BusInstance *bus, WireInstance *wire, Connection connection);
};
} // namespace domain
#endif // DOMAIN_CONNECTIONINSTANCE_H

View File

@ -1,10 +1,184 @@
#include "display.h"
#include <QBrush>
#include <QPen>
namespace domain {
Display::Display()
{
QBrush busBrush(QColor::fromRgb(200, 200, 200));
QPen busPen(QColor::fromRgb(200, 200, 200));
}
Display::Display(std::vector<ui::Item> items) : items(items) {}
void Display::render(QGraphicsItemGroup *group) {
for (auto &item: items) {
item.render(group);
}
}
void Display::comdel(std::ostream &buffer, int x, int y, int size) {
for (auto &item: items) {
item.comdel(buffer, x, y, size);
}
}
void ui::Rect::render(QGraphicsItemGroup *group) {
group->addToGroup(new QGraphicsRectItem(x, y, w, h));
}
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\tw: " << w << "; h: " << h << ";\n";
buffer << "\t\t}\n\n";
}
void ui::Line::render(QGraphicsItemGroup *group) {
group->addToGroup(new QGraphicsLineItem(x1, y1, x2, y2));
}
void ui::Line::comdel(std::ostream &buffer, int x, int y) {
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";
}
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(busBrush);
rect->setPen(busPen);
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\tw: " << size << "; h: " << h << ";\n";
} else {
buffer << "\t\t\tw: " << w << "; h: " << size << ";\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;
}
group->addToGroup(new QGraphicsPolygonItem(polygon));
}
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;
}
group->addToGroup(new QGraphicsPolygonItem(polygon));
}
void ui::Pin::renderInOut(QGraphicsItemGroup *group) {
group->addToGroup(new QGraphicsRectItem(x, y, w, h));
}
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, int size) {
if (rect) rect->render(group);
if (line) line->render(group);
if (pin) pin->render(group);
if (bus) bus->render(group, size);
}
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);
}
} // namespace domain

View File

@ -1,14 +1,116 @@
#ifndef DOMAIN_DISPLAY_H
#define DOMAIN_DISPLAY_H
#include <QGraphicsItem>
#include <optional>
#include <ostream>
namespace domain {
class Display
{
public:
Display();
};
namespace ui {
class Rect {
public:
int x, y, w, h;
Rect(int x, int y, int w, int h) : x(x), y(y), w(w), h(h) {}
void render(QGraphicsItemGroup *group);
void comdel(std::ostream &buffer, int x, int y);
};
class Line {
public:
int x1, y1, x2, y2;
Line(int x1, int y1, int x2, int y2) : x1(x1), y1(y1), x2(x2), y2(y2) {}
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;
Bus(int x, int y, int w, int h, BusOrientation orientation) : x(x), y(y), w(w), h(h),
orientation(orientation) {}
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;
Pin(int x, int y, int w, int h, PinOrientation orientation, PinType pinType) : x(x), y(y), w(w), h(h),
orientation(orientation),
pinType(pinType) {}
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;
void render(QGraphicsItemGroup *group, int size = 0);
void comdel(std::ostream &buffer, int x, int y, int size = 0);
};
}
class Display {
public:
Display(std::vector<ui::Item> items);
void render(QGraphicsItemGroup *group);
void comdel(std::ostream &buffer, int x, int y, int size = 0);
std::vector<ui::Item> &getItems() { return items; }
private:
std::vector<ui::Item> items;
};
} // namespace domain

View File

@ -0,0 +1,166 @@
#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

View File

@ -0,0 +1,36 @@
#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

View File

@ -1,5 +0,0 @@
#include "functionsignature.h"
namespace domain {
} // namespace domain

View File

@ -1,20 +0,0 @@
#ifndef DOMAIN_FUNCTIONSIGNATURE_H
#define DOMAIN_FUNCTIONSIGNATURE_H
#include<functional>
#include "value.h"
namespace domain {
typedef std::function<bool (std::vector<Value>)> FunctionCallback;
struct FunctionSignature {
std::string name;
std::vector<Value::ValueType> params;
FunctionSignature(std::string name, std::vector<Value::ValueType> params): name(name), params(params) {}
};
} // namespace domain
#endif // DOMAIN_FUNCTIONSIGNATURE_H

View File

@ -2,16 +2,18 @@
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();
}
}
Instance::Instance(std::string name, std::vector<InstanceAttribute*> attributes, std::pair<int, int> position)
: name(name), attributes(attributes), position(position)
{}
BusInstance::BusInstance(std::string name, std::pair<int, int> position, Bus bus, int size)
: Instance(name, vector<InstanceAttribute*>(), position), bus(bus), size(size)
{}
ComponentInstance::ComponentInstance(std::string name, std::vector<InstanceAttribute*> attributes, std::pair<int, int> position, Component component)
: Instance(name, attributes, position), component(component)
{}
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) {}
} // namespace domain

View File

@ -3,51 +3,41 @@
#include "bus.h"
#include "component.h"
#include "instanceattribute.h"
#include "instance_attribute.h"
#include <string>
#include <vector>
namespace domain {
class Instance
{
public:
std::string name;
std::vector<InstanceAttribute*> attributes;
std::pair<int, int> position;
class BusInstance {
public:
std::string name;
std::pair<int, int> position;
virtual ~Instance() {};
Bus bus;
int size;
Instance(std::string name, std::vector<InstanceAttribute*> attributes, std::pair<int, int> position);
};
BusInstance(std::string name, Bus bus);
class BusInstance: public Instance
{
public:
Bus bus;
int size;
BusInstance(std::string name, std::pair<int, int> position, Bus bus, int size = -1);
BusInstance(std::string name, std::pair<int, int> position, Bus bus, int size);
virtual ~BusInstance() = default;
};
virtual ~BusInstance() {
Instance::~Instance();
}
};
class ComponentInstance {
public:
std::string name;
std::vector<InstanceAttribute> attributes;
std::pair<int, int> position;
class ComponentInstance: public Instance
{
public:
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() {
Instance::~Instance();
}
};
virtual ~ComponentInstance() = default;
};
} // namespace domain

View File

@ -0,0 +1,8 @@
#include "instance_attribute.h"
namespace domain {
InstanceAttribute::InstanceAttribute(std::string name, Value value, Attribute attribute)
: name(name), value(value), attribute(attribute) {}
} // namespace domain

View File

@ -0,0 +1,25 @@
#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

View File

@ -1,9 +0,0 @@
#include "instanceattribute.h"
namespace domain {
InstanceAttribute::InstanceAttribute(std::string name, Value value, Attribute attribute)
: name(name), value(value), attribute(attribute)
{}
} // namespace domain

View File

@ -1,26 +0,0 @@
#ifndef DOMAIN_INSTANCEATTRIBUTE_H
#define DOMAIN_INSTANCEATTRIBUTE_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;
};
} // namespace domain
#endif // DOMAIN_INSTANCEATTRIBUTE_H

View File

@ -2,99 +2,144 @@
namespace domain {
Library::Library(string name, string libraryInfo, string header, string componentDirectory,
vector<AddressSpace> addressSpaces, vector<Component> components, vector<Bus> buses, vector<Connection> connections, map<string, string> messages)
: name(name), libraryInfo(libraryInfo), header(header), componentDirectory(componentDirectory), 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::getLibraryInfo() {
return libraryInfo;
}
std::string Library::getHeader() {
return header;
}
std::string Library::getComponentDirectory() {
return componentDirectory;
}
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(uint i=0; i<components.size(); i++) {
if(components[i].getName() == name) {
return true;
}
std::string Library::getName() {
return name;
}
return false;
}
bool Library::hasBus(std::string name) {
for(uint i=0; i<buses.size(); i++) {
if(buses[i].getName() == name) {
return true;
}
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::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 (uint i = 0; i < components.size(); i++) {
if (components[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(uint 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::exception();
}
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::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::exception();
}
std::optional<Connection> Library::getConnection(std::string component, std::string pin, std::string bus) {
for(uint i=0; i<connections.size(); i++) {
if(connections[i].isConnecting(component, pin, bus)) {
return connections[i];
Component &Library::getComponent(std::string component) {
for (uint i = 0; i < components.size(); i++) {
if (components[i].getName() == component) {
return components[i];
}
}
throw std::exception();
}
return nullopt;
}
bool Library::hasConnection(std::string component, std::string pin, std::string bus) {
return getConnection(component, pin, bus).has_value();
}
std::string Library::getMessage(std::string key) {
return messages[key];
}
Bus &Library::getBus(std::string bus) {
for (uint i = 0; i < buses.size(); i++) {
if (buses[i].getName() == bus) {
return buses[i];
}
}
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 (uint i = 0; i < connections.size(); i++) {
if (connections[i].isConnecting(component, bus)) {
return connections[i];
}
}
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 (uint i = 0; i < connections.size(); i++) {
if (connections[i].isConnecting(component, bus, secondComponent)) {
return connections[i];
}
}
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;
}
} // namespace domain

View File

@ -1,7 +1,7 @@
#ifndef DOMAIN_LIBRARY_H
#define DOMAIN_LIBRARY_H
#include "addressspace.h"
#include "address_space.h"
#include "bus.h"
#include "component.h"
#include "connection.h"
@ -10,54 +10,75 @@
#include <vector>
namespace domain {
using namespace std;
using namespace std;
class Library
{
std::string name;
std::string libraryInfo;
std::string header;
std::string componentDirectory;
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,
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 getLibraryInfo();
std::string getHeader();
std::string getComponentDirectory();
std::string getName();
std::vector<AddressSpace> getAddressSpaces();
std::vector<Component> getComponents();
std::vector<Bus> getBuses();
std::vector<Connection> getConnections();
std::string getLibraryInfo();
bool hasComponent(std::string name);
bool hasBus(std::string name);
bool hasConnection(std::string component, std::string pin, std::string bus);
std::string getHeader();
std::map<std::string, std::string> getMessages();
std::string getComponentDirectory();
AddressSpace &getAddressSpace(std::string name);
Component &getComponent(std::string name);
Bus &getBus(std::string bus);
std::optional<Connection> getConnection(std::string component, std::string pin, std::string bus);
std::string getMessage(std::string key);
std::optional<std::string> getComponentHeader();
std::vector<AddressSpace> getAddressSpaces();
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);
};
} // namespace domain

View File

@ -2,37 +2,45 @@
namespace domain {
PinConnection::PinConnection(std::string message, ConnectionType type)
: message(message), type(type)
{}
PinConnection::PinConnection(std::string message, ConnectionType type)
: message(message), type(type) {}
PinConnection::ConnectionType PinConnection::getType() {
return type;
}
std::string PinConnection::getMessage() {
return message;
}
PinConnection::ConnectionType PinConnection::getType() {
return type;
}
std::string PinConnection::getMessage() {
return message;
}
Pin::Pin(std::string name, PinType type, std::string tooltip, PinConnection connection, Display display)
: name(name), type(type), tooltip(tooltip), connection(connection), display(display)
{}
Pin::Pin(std::string name, PinType type, std::string tooltip, PinConnection connection, domain::ui::Pin pin,
std::optional<std::vector<Value>> wires)
: name(name), type(type), tooltip(tooltip), connection(connection), displayPin(pin), wires(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::string &Pin::getName() {
return name;
}
Pin::PinType Pin::getType() {
return type;
}
std::string Pin::getTooltip() {
return tooltip;
}
ui::Pin &Pin::getDisplayPin() {
return displayPin;
}
PinConnection &Pin::getConnection() {
return connection;
}
std::optional<std::vector<Value>> &Pin::getWires() {
return wires;
}
} // namespace domain

View File

@ -2,58 +2,66 @@
#define DOMAIN_PIN_H
#include "display.h"
#include "value.h"
#include <string>
namespace domain {
class PinConnection
{
public:
enum ConnectionType {
CHECK_ONLY,
AUTOMATICALLY
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();
};
private:
std::string message;
ConnectionType type;
class Pin {
public:
enum PinType {
IN_OUT,
IN,
OUT
};
public:
PinConnection(std::string message, ConnectionType type);
private:
std::string name;
PinType type;
std::string tooltip;
PinConnection connection;
domain::ui::Pin displayPin;
ConnectionType getType();
std::string getMessage();
};
std::optional<std::vector<Value>> wires;
class Pin
{
public:
enum PinType {
IN_OUT,
IN,
OUT
public:
Pin(std::string name, PinType type, std::string tooltip, PinConnection connection, domain::ui::Pin pin,
std::optional<std::vector<Value>> wires);
std::string &getName();
PinType getType();
std::string getTooltip();
ui::Pin &getDisplayPin();
PinConnection &getConnection();
std::optional<std::vector<Value>> &getWires();
};
private:
std::string name;
PinType type;
std::string tooltip;
PinConnection connection;
Display display;
public:
Pin(std::string name, PinType type, std::string tooltip, PinConnection connection, Display display);
std::string getName();
PinType getType();
std::string getTooltip();
Display &getDisplay();
PinConnection &getConnection();
};
} // namespace domain
#endif // DOMAIN_PIN_H

View File

@ -1,60 +1,61 @@
#include "rule.h"
#include <utility>
namespace domain {
Condition::Condition(std::string function, std::vector<Value> params, bool negated)
: negated(negated), function(function), params(params)
{}
Condition::Condition(std::string function, std::vector<Value> params, bool negated)
: negated(negated), function(std::move(function)), params(std::move(params)) {}
bool Condition::evaluate(RuleContext &context) {
std::vector<Value> request;
for(uint i=0; i<params.size(); i++) {
if(params[i].isType(Value::ATTRIBUTE_REFERENCE)) {
request.push_back(context.attributes[params[i].asReference()]);
} else {
request.push_back(params[i]);
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 result = context.function[function]->validate(request);
return negated ? !result : result;
}
bool result = context.function[function](request);
return negated ? !result : result;
}
Action::Action(ActionType type, std::string message)
: type(type), message(message)
{}
Action::Action(ActionType type, std::string message)
: type(type), message(std::move(message)) {}
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;
Action::ActionType Action::getType() {
return type;
}
return std::nullopt;
}
Rule::Rule(std::vector<IfStatement> statements)
: statements(statements)
{}
std::string Action::getMessage() {
return message;
}
std::optional<Action> Rule::evaluate(RuleContext &context) {
for(uint i=0; i<statements.size(); i++) {
auto response = statements[i].evaluate(context);
if(response) {
return response;
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;
}
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

View File

@ -1,9 +1,9 @@
#ifndef DOMAIN_RULE_H
#define DOMAIN_RULE_H
#include "addressspace.h"
#include "address_space.h"
#include "value.h"
#include "functionsignature.h"
#include "function_signature.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, FunctionCallback> 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
struct RuleContext {
std::map<std::string, AddressSpace> addressSpaces;
std::map<std::string, Value> attributes;
std::map<std::string, FunctionValidator *> function;
};
private:
ActionType type;
std::string message;
class Condition {
bool negated;
std::string function;
std::vector<Value> params;
public:
Action(ActionType type, std::string message);
public:
Condition(std::string function, std::vector<Value> params, bool negated);
ActionType getType();
std::string getMessage();
};
bool evaluate(RuleContext &context);
};
class IfStatement {
Condition condition;
Action action;
public:
IfStatement(Condition condition, Action action);
class Action {
public:
enum ActionType {
ERROR,
WARNING
};
std::optional<Action> evaluate(RuleContext &context);
};
private:
ActionType type;
std::string message;
class Rule
{
std::vector<IfStatement> statements;
public:
Rule(std::vector<IfStatement> statements);
public:
Action(ActionType type, std::string message);
std::optional<Action> evaluate(RuleContext &context);
};
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);
};
} // namespace domain

View File

@ -2,8 +2,119 @@
namespace domain {
Schema::Schema()
{
}
bool Schema::hasConnection(string &component, string &pin) {
return getConnection(component, pin) != nullptr;
}
ConnectionInstance *Schema::getConnection(string &component, string &pin) {
auto pinConnections = getConnections(component, pin);
if(pinConnections.empty()) {
return nullptr;
} else {
return pinConnections[0];
}
}
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());
}
}
}
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 bus connection
if(library.getBus(conn.getBus()).getType() == Bus::REGULAR) {
for(auto& bus: busInstances) {
if(bus->bus.getName() == conn.getBus()) {
ConnectionEntry entry{ConnectionEntry::BUS, bus.get(), nullopt, nullopt, conn};
entries.emplace_back(entry);
}
}
} 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) {
if(entry.busInstance.value()->bus.getName() == conn->connection.getBus()) {
return true;
}
} else {
auto *directInstance = dynamic_cast<DirectConnectionInstance*>(conn.get());
ComponentInstance* secondInstance;
if(directInstance->instance == instance) {
secondInstance = directInstance->secondInstance;
} else {
secondInstance = directInstance->instance;
}
return entry.componentInstance == secondInstance;
}
}
}
return false;
}),
entries.end()
);
}
return entries;
}
} // namespace domain

View File

@ -1,46 +1,50 @@
#ifndef DOMAIN_SCHEMA_H
#define DOMAIN_SCHEMA_H
#include "connectioninstance.h"
#include "connection_instance.h"
#include "instance.h"
#include "wireinstance.h"
#include "library.h"
#include <utility>
#include <vector>
namespace domain {
class Schema
{
public:
Schema();
struct ConnectionEntry {
enum Type {
BUS,
COMPONENT
};
std::vector<Instance*> instances;
std::vector<ConnectionInstance*> connections;
std::vector<WireInstance*> wires;
Type type;
WireInstance *getWire(std::string name) {
for(auto wire: wires) {
if (wire->name == name) {
return wire;
}
}
return nullptr;
}
std::optional<BusInstance*> busInstance;
std::optional<ComponentInstance*> componentInstance;
std::optional<Pin> pin;
bool hasWire(std::string name) {
return getWire(name) != NULL;
}
Connection connection;
};
class Schema {
private:
Library library;
public:
Schema(Library library): library(std::move(library)) {}
Instance *getInstance(std::string name) {
for(auto instance: instances) {
if (instance->name == name) {
return instance;
}
}
return nullptr;
}
};
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);
};
} // namespace domain

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,93 @@
#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 {
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);
bool doesAttributeExists(std::string name, Value::ValueType type);
bool doesWireExists(std::string name);
};
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<Bus> getBus(std::string name);
std::optional<Pin> getComponentPin(std::string name, std::string pin);
bool hasAddressSpace(std::string name);
void push(ComdelContext context);
void pushAdditional(std::string name);
ComdelContext &current();
void pop();
std::optional<Attribute> createMemoryAttribute();
vector<Enumeration> createWireEnumeration(vector<Value> enumeration);
std::optional<Popup> createMemoryPopup();
public:
explicit SchemaCreator(std::vector<FunctionValidator *> validators);
std::vector<SourceError> getErrors();
std::optional<Library> loadLibrary(LibraryNode node);
Schema *loadSchema(SchemaNode node, Library &library);
};
} // namespace domain
#endif // DOMAIN_COMDEL_GENERATOR_H

View File

@ -4,105 +4,197 @@
namespace domain {
Value::ValueType Value::getType() {
return type;
}
bool Value::isType(Value::ValueType type) {
return this->type == type;
}
long long Value::asInt() {
if(isType(Value::INT)) {
return intValue;
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";
}
}
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::ATTRIBUTE_REFERENCE) || isType(Value::UNDEFINED)) {
return reference;
}
throw std::exception();
}
void Value::setInt(long long value) {
if(isType(Value::INT)) {
this->intValue = value;
}
throw std::exception();
}
void Value::setString(std::string value) {
if(isType(Value::STRING)) {
this->stringValue = value;
}
throw std::exception();
}
void Value::setBool(bool value) {
if(isType(Value::BOOL)) {
this->boolValue = value;
}
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::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::ofType(Value::ValueType type) {
Value val;
val.type = type;
return val;
Value::ValueType Value::getType() {
return type;
}
}
bool Value::isType(Value::ValueType _type) {
return type == _type;
}
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;
}
domain::ComponentInstance *Value::asMemory() {
return memory;
}
void Value::setInt(long long value) {
if (isType(Value::INT)) {
this->intValue = value;
}
throw std::exception();
}
void Value::setString(std::string value) {
if (isType(Value::STRING)) {
this->stringValue = value;
}
throw std::exception();
}
void Value::setBool(bool value) {
if (isType(Value::BOOL)) {
this->boolValue = value;
}
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::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::fromNull() {
Value val;
val.type = Value::NIL;
return val;
}
Value Value::fromMemoryReference(std::optional<std::string> value) {
Value val;
val.type = MEMORY_REFERENCE;
val.memoryReference = value;
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::exception();
}
}
Value Value::ofType(Value::ValueType type) {
Value val;
val.type = type;
return val;
}
} // namespace domain

View File

@ -1,63 +1,122 @@
#ifndef DOMAIN_VALUE_H
#define DOMAIN_VALUE_H
#include "addressspace.h"
#include "address_space.h"
#include <string>
#include <optional>
namespace domain {
class Value
{
public:
enum ValueType {
INT,
STRING,
BOOL,
ADDRESS_SPACE,
ATTRIBUTE_REFERENCE,
WIRE_REFERENCE,
UNDEFINED,
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) {
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 fromMemoryReference(std::optional<std::string> memoryReference);
static Value ofType(ValueType type);
};
private:
long long intValue;
std::string stringValue;
bool boolValue;
std::optional<AddressSpace> addressSpace;
std::string reference;
ValueType type;
public:
Value() {
this->type = UNDEFINED;
}
ValueType getType();
bool isType(ValueType type);
long long asInt();
std::string asString();
bool asBool();
std::string asReference();
AddressSpace asAddressSpace();
void setInt(long long intValue);
void setString(std::string value);
void setBool(bool value);
void setReference(std::string value);
static Value fromInt(long long value);
static Value fromString(std::string value);
static Value fromBool(bool value);
static Value fromAddressSpace(AddressSpace addressSpace);
static Value fromReference(std::string value, ValueType type);
static Value ofType(ValueType type);
};
} // namespace domain
#endif // DOMAIN_VALUE_H

View File

@ -1,10 +0,0 @@
#include "wireinstance.h"
namespace domain {
WireInstance::WireInstance(std::string name, Display display)
: name(name), display(display)
{}
} // namespace domain

View File

@ -1,23 +0,0 @@
#ifndef DOMAIN_WIREINSTANCE_H
#define DOMAIN_WIREINSTANCE_H
#include "display.h"
#include <string>
namespace domain {
class WireInstance
{
public:
std::string name;
Display display;
WireInstance(std::string name, Display display);
};
} // namespace domain
#endif // DOMAIN_WIREINSTANCE_H

View File

@ -1 +0,0 @@
#include "assert.h"

View File

@ -1,36 +0,0 @@
#ifndef ASSERT_H
#define ASSERT_H
#include <string>
class AtlasException : public std::exception {
const std::string fileName;
const int fileLine;
const std::string message;
protected:
virtual void buildString(std::ostream& stream) const;
std::string fullMessage;
public:
explicit AtlasException(const std::string& file, int line,
const std::string& msg);
virtual ~AtlasException() {
}
virtual std::string buildMessage() const;
virtual std::string toString() const {
return fullMessage;
}
virtual const char* what() const noexcept {
return fullMessage.c_str();
}
};
#endif // ASSERT_H

109
comdel/parser/ast_nodes.cpp Normal file
View File

@ -0,0 +1,109 @@
#include "ast_nodes.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, 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);
}
}
/*************************** 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;
}

392
comdel/parser/ast_nodes.h Normal file
View File

@ -0,0 +1,392 @@
#ifndef AST_NODE_H
#define AST_NODE_H
#include "token.h"
#include "source_error.h"
#include <optional>
#include <utility>
#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(std::move(first)), second(std::move(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() const {
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;
long long int asInt(std::vector<SourceError> *errors, const std::string &property, long long int _default = 0) {
for (auto &prop: values) {
if (prop.key.value == property) {
if (prop.value.is(ValueNode::INT)) {
return prop.value.asInt();
} else {
if (errors != nullptr) {
errors->emplace_back(prop.value.span, "expected number");
}
}
}
}
return _default;
}
std::string asIdentifier(std::vector<SourceError> *errors, const std::string &property, std::string _default = "") {
for (auto &prop: values) {
if (prop.key.value == property) {
if (prop.value.is(ValueNode::IDENTIFIER)) {
return prop.value.asIdentifier();
} else {
if (errors != nullptr) {
errors->emplace_back(prop.value.span, "expected identifier");
}
}
}
}
return _default;
}
std::string asString(std::vector<SourceError> *errors, const std::string &property, std::string _default = "") {
for (auto &prop: values) {
if (prop.key.value == property) {
if (prop.value.is(ValueNode::STRING)) {
return prop.value.asString();
} else {
if (errors != nullptr) {
errors->emplace_back(prop.value.span, "expected string");
}
}
}
}
return _default;
}
};
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<IdentifierNode> 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<IdentifierNode> instanceName;
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

View File

@ -1,17 +0,0 @@
#include "astnode.h"
AstNode::~AstNode() = default;
NumberNode::NumberNode(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);
}
}

View File

@ -1,403 +0,0 @@
#ifndef ASTNODE_H
#define ASTNODE_H
#include "token.h"
#include <optional>
#include <vector>
/**
* AST base class, all AST node classes extand this class. Class contains basic
* information about a nodes location in file.
*/
class AstNode {
public:
Span span;
AstNode() = default;
virtual ~AstNode(); // this is defined in Ast.cpp just so that the
// compiler doesn't complain about not knowing which
// object file to include the vtable in
AstNode(AstNode&&) = default;
AstNode& operator=(AstNode&&) = default;
AstNode(const AstNode&) = default;
AstNode& operator=(const AstNode&) = default;
};
struct StringNode: public AstNode
{
std::string value;
std::string asString() {
return value.substr(1, value.length() - 2);
}
};
struct IdentifierNode: public AstNode
{
std::string value;
};
struct NumberNode: public AstNode {
long long int value;
NumberNode(std::string expression);
NumberNode(): value(0) {}
};
struct CountNode: public AstNode
{
NumberNode first;
NumberNode second;
CountNode(NumberNode first, NumberNode second): first(first), second(second) {}
CountNode() {}
};
struct AddressSpaceNode: public AstNode
{
IdentifierNode name;
NumberNode start;
NumberNode end;
};
class ValueNode: AstNode
{
public:
enum ValueType {
INT,
STRING,
BOOL,
WIRE,
IDENTIFIER
};
private:
ValueType type;
std::optional<long long> intValue;
std::optional<std::string> stringValue;
std::optional<bool> boolValue;
std::optional<std::string> identifierValue;
public:
ValueNode() {};
ValueType getType() {
return type;
}
long long asInt() {
if(is(INT)) {
return intValue.value();
}
throw "cannot convert type to int";
}
std::string asString() {
if(is(STRING)) {
return stringValue.value();
}
throw "cannot convert type to string";
}
std::string asIdentifier() {
if(is(IDENTIFIER) || is(WIRE)) {
return identifierValue.value();
}
throw "cannot convert type to identifier";
}
bool asBool() {
if(is(BOOL)) {
return boolValue.value();
}
throw "cannot convert type to bool";
}
bool is(ValueType type) {
return this->type == type;
}
static ValueNode ofBool(bool _value) {
ValueNode value;
value.type = BOOL;
value.boolValue = std::optional<bool>(_value);
return value;
}
static ValueNode ofInt(long long _value) {
ValueNode value;
value.type = INT;
value.intValue = std::optional<long long>(_value);
return value;
}
static ValueNode ofString(std::string _value) {
ValueNode value;
value.type = STRING;
value.stringValue = std::optional<std::string>(_value);
return value;
}
static ValueNode ofIdentifier(std::string _value) {
ValueNode value;
value.type = IDENTIFIER;
value.identifierValue = std::optional<std::string>(_value);
return value;
}
static ValueNode ofWire(std::string _value) {
ValueNode value;
value.type = WIRE;
value.identifierValue = std::optional<std::string>(_value);
return value;
}
};
struct ConditionNode
{
bool negated;
IdentifierNode functionName;
std::vector<ValueNode> params;
};
class ActionNode: AstNode {
public:
enum ActionType {
ERROR,
WARNING
};
ActionType type;
StringNode message;
};
struct IfStatementnode: AstNode
{
ConditionNode condition;
ActionNode action;
};
struct RuleNode: AstNode
{
std::vector<IfStatementnode> statements;
};
struct EnumerationNode: AstNode
{
StringNode key;
ValueNode value;
};
struct PopupNode: AstNode
{
enum PopupType {
AUTOMATIC,
ON_DEMAND
};
std::optional<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: AstNode
{
IdentifierNode type;
std::vector<PropertyNode> values;
};
struct DisplayNode: AstNode
{
std::vector<DisplayItemNode> items;
};
struct PinConnectionNode: AstNode
{
enum ConnectionType {
CHECK_ONLY,
AUTOMATICALLY
};
StringNode message;
ConnectionType type;
};
struct PinNode: AstNode
{
enum PinType {
IN_OUT,
IN,
OUT
};
IdentifierNode name;
PinType type;
std::optional<StringNode> tooltip;
std::optional<PinConnectionNode> connection;
std::optional<DisplayNode> display;
};
struct WireNode: public AstNode
{
enum WireType {
WIRE,
WIRED_AND,
WIRED_OR,
R_WIRE
};
WireType type;
IdentifierNode name;
NumberNode size;
bool hidden;
bool hasTermination;
long long isUnterminated;
};
struct AttributeNode: AstNode
{
ValueNode::ValueType type;
IdentifierNode name;
std::optional<ValueNode> defaultValue;
std::optional<PopupNode> popup;
};
struct ConnectionNode: AstNode
{
IdentifierNode component;
IdentifierNode pin;
IdentifierNode bus;
std::vector<AttributeNode> attributes;
std::vector<IdentifierNode> wires;
};
struct ComponentNode: AstNode
{
enum ComponentType {
OTHER,
PROCESSOR,
MEMORY
};
IdentifierNode name;
std::optional<StringNode> tooltip;
std::optional<StringNode> source;
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: AstNode
{
enum BusType {
AUTOMATIC,
REGULAR
};
BusType type;
IdentifierNode name;
std::optional<StringNode> tooltip;
std::optional<CountNode> count;
std::optional<DisplayNode> display;
std::vector<WireNode> wires;
};
struct LibraryNode: AstNode
{
std::optional<StringNode> name;
std::optional<StringNode> libraryInfo;
std::optional<StringNode> header;
std::optional<StringNode> componentDirectory;
std::vector<AddressSpaceNode> addressSpaces;
std::vector<ComponentNode> components;
std::vector<BusNode> buses;
std::vector<ConnectionNode> connections;
std::vector<PropertyNode> messages;
};
// SCHEMA models
struct WireInstanceNode: AstNode
{
IdentifierNode name;
std::optional<CountNode> position;
std::optional<DisplayNode> display;
};
struct InstanceAttributeNode: AstNode
{
IdentifierNode name;
ValueNode value;
};
struct InstanceNode: AstNode
{
IdentifierNode name;
IdentifierNode component;
std::optional<CountNode> position;
std::vector<InstanceAttributeNode> attributes;
std::optional<NumberNode> size;
};
struct ConnectionInstanceNode: AstNode
{
IdentifierNode instance;
IdentifierNode pin;
IdentifierNode bus;
std::optional<IdentifierNode> wire;
std::vector<InstanceAttributeNode> attributes;
};
struct SchemaNode: AstNode
{
std::optional<StringNode> source;
std::vector<InstanceNode> instances;
std::vector<WireInstanceNode> wires;
std::vector<ConnectionInstanceNode> connections;
std::optional<LibraryNode> library;
};
#endif // ASTNODE_H

View File

@ -1,6 +1,6 @@
#include "comdellexer.h"
#include "comdel_lexer.h"
#include "token.h"
#include "tokenstype.h"
#include "tokens_type.h"
#include <fstream>
#include <cctype>
@ -21,7 +21,7 @@ inline bool identifierContinue(char ch) {
}
inline bool numberStart(char ch) {
return isdigit(ch);
return isdigit(ch) || ch == '-';
}
inline bool isWhitespace(char ch) {
@ -36,14 +36,13 @@ inline bool isWhitespace(char ch) {
*************************************************************************/
ComdelLexer::ComdelLexer(std::string fileName, std::string source,
ParseContext* parseContext)
: source(std::move(source)),
parseContext(parseContext),
// qqq zamijeniti poziv path_absolute sa Qt-ovim pozivom
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() {
@ -51,11 +50,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;
}
@ -64,12 +63,12 @@ LexerResult ComdelLexer::tokenize() {
tokenType = from_token(text, tokenType.value());
tokens.push_back(Token(*tokenType, Span(tokenBegin, position), text));
tokens.emplace_back(*tokenType, Span(tokenBegin, position), text);
}
tokens.push_back(Token( TokenType::END_OF_FILE, Span(position), ""));
tokens.emplace_back(TokenType::END_OF_FILE, Span(position), "");
return LexerResult { tokens, errors };
return LexerResult{tokens, errors};
}
@ -86,11 +85,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;
@ -101,28 +100,28 @@ unsigned ComdelLexer::takeNumberInRadix(Radix radix) {
bool ComdelLexer::digitIsValid(char ch, Radix radix) {
// Check digits in normal numbers
//digit is 0..1
if(ch == '1' || ch == '0') {
// Check valid digits
// digit is 0..1
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') {
@ -137,11 +136,11 @@ ComdelLexer::Radix ComdelLexer::takeRadix(){
}
// color is sequence of hex-digits (preceeded with # which is already consumed)
// color is sequence of hex-digits (preceded with # which is already consumed)
unsigned ComdelLexer::takeHexColor() {
unsigned digitsTaken = 0;
while(true) {
while (true) {
if (digitIsValid(ch, Radix::HEX_NUMBER)) { // skip and count hex digits
bump();
digitsTaken++;
@ -159,13 +158,13 @@ PResult<TokenType> ComdelLexer::takeString() {
return PError({Span(lo), "expected string here"});
bump(); // skip starting "
// Check ecsape-sequences \t \n \\ \" but leave them in string.
// 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"});
@ -177,19 +176,18 @@ 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 != '`')
return PError({Span(lo), "expected string here"});
bump(); // skip starting '
// Ignore ecsape-sequences - take all characters until closing '
// Ignore escape-sequences - take all characters until closing '
while (ch != '`' && !eof()) {
bump(); // skip characters
}
@ -198,7 +196,7 @@ PResult<TokenType> ComdelLexer::takeRawString()
return PError({Span(lo, position), "unterminated string"});
}
bump(); // skip closing '
return TokenType::STRING;
return TokenType::STRING;
}
@ -237,173 +235,116 @@ 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))
{
return TokenType::IDENTIFIER;
} else if (numberStart(ch)) {
if (ch == '-') {
bump();
}
unsigned takenDigits;
Radix radix = takeRadix();
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 #"});;
"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 == '.')
{
"unexpected /"});
} 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 if (ch == '<')
{
bump();
return TokenType::LT;
}
else if (ch == '>')
{
return TokenType::GT;
}
else
{
} else {
std::stringstream message;
message << "unexpected character `" << ch << "`";
bump();
@ -415,11 +356,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;
}
@ -431,12 +372,12 @@ void ComdelLexer::bump(unsigned count) {
// Fetch and return next character without moving position.
// Fetch does not cross line boundary.
// Returns \n when next char does not exists (end of line or end of file)
// 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];
}

View File

@ -1,9 +1,9 @@
#ifndef COMDELLEXER_H
#define COMDELLEXER_H
#ifndef COMDEL_LEXER_H
#define COMDEL_LEXER_H
#include "parsecontext.h"
#include "parse_context.h"
#include "presult.h"
#include "sourceerror.h"
#include "source_error.h"
#include "token.h"
@ -16,8 +16,7 @@ struct LexerResult {
std::vector<SourceError> errors;
};
class ComdelLexer
{
class ComdelLexer {
enum Radix {
BIN_NUMBER = 2,
@ -28,19 +27,23 @@ class ComdelLexer
std::string source;
std::vector<Token> tokens;
std::vector<SourceError> errors;
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:
void skipWhitespace();
unsigned takeNumberInRadix(Radix radix);
unsigned takeHexColor();
bool digitIsValid(char ch, Radix radix);
Radix takeRadix();
PResult<TokenType> nextTokenType();
@ -50,14 +53,18 @@ private:
char ch;
void skipComment();
bool skipMultilineComment();
PResult<TokenType> takeString();
PResult<TokenType> takeRawString();
void bump(unsigned count = 1);
char peek();
bool eof();
};
#endif // COMDELLEXER_H
#endif // COMDEL_LEXER_H

View File

@ -1,10 +1,10 @@
#ifndef COMDELPARSER_H
#define COMDELPARSER_H
#ifndef COMDEL_PARSER_H
#define COMDEL_PARSER_H
#include "sourceerror.h"
#include "source_error.h"
#include "presult.h"
#include "token.h"
#include "astnode.h"
#include "ast_nodes.h"
#include <optional>
#include <set>
@ -16,24 +16,23 @@
/// Spanner's call operator MOVES from the node so it should
/// be always used last.
class Spanner {
const Span lo; // the low end of the span, beginning of the node
// 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:
Spanner(Span lo, Span& prevSpan) : lo(lo), prevSpan(prevSpan) {}
const Span lo; // the low end of the span, beginning of the node
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::move(astNode);
return std::forward<T>(astNode);
}
};
class ComdelParser
{
class ComdelParser {
private:
std::vector<Token> tokens;
std::set<TokenType> expectedTokens;
@ -46,56 +45,90 @@ private:
void bump();
bool consume(TokenType tokenType);
bool check(TokenType tokenType);
void skipUntilNextKeyword();
Token &current();
[[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();
void parseBlock();
// used to parse library and schema
PResult<StringNode> parseString();
PResult<IdentifierNode> parseIdentifier();
PResult<NumberNode> parseNumber();
PResult<CountNode> parseCount();
PResult<PropertyNode> parseProperty(std::optional<TokenType> valueType);
PResult<EnumerationNode> parseEnumeration();
PResult<ValueNode> parseConnectionWire();
PResult<ComponentNode> parseComponent();
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<DisplayItemNode> parseDisplayItem();
PResult<IfStatementnode> parseIfStatement();
PResult<IfStatementNode> parseIfStatement();
PResult<ValueNode> parseValue();
PResult<WireInstanceNode> parseWireInstance();
// used to parse schema
PResult<CountNode> parsePosition();
PResult<InstanceNode> parseInstance();
PResult<InstanceAttributeNode> parseInstanceAttribute();
PResult<ConnectionInstanceNode> parseConnectionInstance();
PResult<EnumNode<ComponentNode::ComponentType>> parseComponentType();
PResult<EnumNode<BusNode::BusType>> parseBusType();
PResult<EnumNode<PinConnectionNode::ConnectionType>> parseConnectionType();
public:
ComdelParser(std::vector<Token> tokens);
explicit ComdelParser(std::vector<Token> tokens);
std::optional<SchemaNode> parseSchema();
std::optional<LibraryNode> parse();
const std::vector<SourceError>& getErrors();
std::optional<LibraryNode> parseLibrary();
const std::vector<SourceError> &getErrors();
};
#endif // COMDELPARSER_H
#endif // COMDEL_PARSER_H

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
#include "parsecontext.h"
#include "parse_context.h"
#include "assert.h"
#include <iostream>
@ -6,31 +6,29 @@
#include <cmath>
ParseContext::ParseContext()
{
ParseContext::ParseContext() {
applicationDir = std::string();
}
unsigned ParseContext::addFile(const std::string& fileName,
const std::string& source)
{
fileMap.push_back(SourceFile(fileName, source));
unsigned ParseContext::addFile(const std::string &fileName,
const std::string &source) {
fileMap.emplace_back(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;
}
@ -40,16 +38,13 @@ 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);
SourceFile sourceFile = getFile(sourceError.span.lo.fileId);
stream << ErrorOrWarning << sourceError.message << std::endl;
stream << errorOrWarning << sourceError.message << std::endl;
Span span = sourceError.span;
@ -100,21 +95,17 @@ 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;
}
const std::string SourceFile::getLine(unsigned line) const
{
auto lineOffset = lineOffsets[line-1];
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);
@ -122,7 +113,6 @@ const 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);
}

View File

@ -0,0 +1,41 @@
#ifndef PARSE_CONTEXT_H
#define PARSE_CONTEXT_H
#include "source_error.h"
#include <string>
#include <vector>
class SourceFile {
std::string fileName;
std::string source;
std::vector<unsigned> lineOffsets;
public:
SourceFile(std::string fileName, std::string source);
const std::string &getFileName() const;
std::string getLine(unsigned line) const;
void addLineOffset(unsigned offset);
};
class ParseContext {
std::string applicationDir;
std::vector<SourceFile> fileMap;
public:
ParseContext();
unsigned addFile(const std::string &fileName, const std::string &source);
SourceFile &getFile(unsigned file);
void formatError(const SourceError &sourceError, std::ostream &stream, const std::string &errorOrWarning);
};
#endif // PARSECONTEXT_H

View File

@ -1,42 +0,0 @@
#ifndef PARSECONTEXT_H
#define PARSECONTEXT_H
#include "sourceerror.h"
#include <string>
#include <vector>
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;
const std::string getLine(unsigned line) const;
void addLineOffset(unsigned offset);
};
class ParseContext
{
std::string applicationDir;
std::vector<SourceFile> fileMap;
public:
ParseContext();
unsigned addFile(const std::string& fileName, const std::string& source);
SourceFile& getFile(unsigned file);
void formatError(const SourceError &sourceError, std::ostream &stream, const std::string& ErrorOrWarning);
};
#endif // PARSECONTEXT_H

View File

@ -1,6 +1,92 @@
#include "comdel_lexer.h"
#include "comdel_parser.h"
#include "parser_util.h"
parser_util::parser_util()
{
#include <iostream>
#include <fstream>
#include <string>
#include <QDir>
std::optional<LibraryNode> load_library_from_file(ParseContext *parseContext,
const char *name,
std::ostream &stream) {
std::ifstream in(name, std::ios::in | std::ios::binary);
if (!in) {
stream << "ERROR: cannot open file '" << name
<< "' (file does not exist or is unreadable)" << std::endl;
return std::nullopt;
}
std::string source((std::istreambuf_iterator<char>(in)),
std::istreambuf_iterator<char>());
ComdelLexer lexer(name, source, parseContext);
LexerResult lexerResult = lexer.tokenize();
if (!lexerResult.errors.empty()) {
for (auto &error: lexerResult.errors) {
parseContext->formatError(error, stream, "ERROR: ");
}
return std::nullopt; // if lexer has found errors => don't parseLibrary
}
ComdelParser parser(lexerResult.tokens);
auto unit = parser.parseLibrary();
if (!unit) {
for (auto &error: parser.getErrors()) {
parseContext->formatError(error, stream, "ERROR: ");
}
return std::nullopt;
}
return *unit;
}
std::optional<SchemaNode> load_schema_from_file(ParseContext *parseContext,
const char *name,
std::ostream &stream) {
std::ifstream in(name, std::ios::in | std::ios::binary);
if (!in) {
stream << "ERROR: cannot open file '" << name
<< "' (file does not exist or is unreadable)" << std::endl;
return std::nullopt;
}
std::string source((std::istreambuf_iterator<char>(in)),
std::istreambuf_iterator<char>());
ComdelLexer lexer(name, source, parseContext);
LexerResult lexerResult = lexer.tokenize();
if (!lexerResult.errors.empty()) {
for (auto &error: lexerResult.errors) {
parseContext->formatError(error, stream, "ERROR: ");
}
return std::nullopt; // if lexer has found errors => don't parseLibrary
}
ComdelParser parser(lexerResult.tokens);
auto unit = parser.parseSchema();
if (!unit) {
for (auto &error: parser.getErrors()) {
parseContext->formatError(error, stream, "ERROR: ");
}
return std::nullopt;
}
if (unit->source) {
QFileInfo info(name);
auto filepath = info.absolutePath();
QDir::setCurrent(filepath);
QDir dir;
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) {
return std::nullopt;
}
}
return *unit;
}

View File

@ -1,11 +1,15 @@
#ifndef PARSER_UTIL_H
#define PARSER_UTIL_H
#include "ast_nodes.h"
#include "parse_context.h"
class parser_util
{
public:
parser_util();
};
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

View File

@ -1,83 +0,0 @@
#include "comdellexer.h"
#include "comdelparser.h"
#include "parserutil.h"
#include <iostream>
#include <fstream>
#include <string>
std::optional<LibraryNode> loadLibraryFromFile(ParseContext * parseContext,
const char* name,
std::ostream& stream)
{
std::ifstream in(name, std::ios::in | std::ios::binary);
if( ! in ) {
stream << "ERROR: cannot open file '" << name
<< "' (file does not exist or is unreadable)" << std::endl;
return std::nullopt;
}
std::string source((std::istreambuf_iterator<char>(in)),
std::istreambuf_iterator<char>());
ComdelLexer lexer(name, source, parseContext);
LexerResult lexerResult = lexer.tokenize();
if (lexerResult.errors.size()) {
for (auto& error : lexerResult.errors) {
parseContext->formatError(error, stream, "ERROR: ");
}
return std::nullopt; // if lexer has found errors => don't parse
}
ComdelParser parser(lexerResult.tokens);
auto unit = parser.parse();
if (!unit) {
for (auto& error : parser.getErrors()) {
parseContext->formatError(error, stream, "ERROR: ");
}
return std::nullopt;
}
return *unit;
}
std::optional<SchemaNode> loadSchemaFromFile(ParseContext * parseContext,
const char* name,
std::ostream& stream)
{
std::ifstream in(name, std::ios::in | std::ios::binary);
if( ! in ) {
stream << "ERROR: cannot open file '" << name
<< "' (file does not exist or is unreadable)" << std::endl;
return std::nullopt;
}
std::string source((std::istreambuf_iterator<char>(in)),
std::istreambuf_iterator<char>());
ComdelLexer lexer(name, source, parseContext);
LexerResult lexerResult = lexer.tokenize();
if (lexerResult.errors.size()) {
for (auto& error : lexerResult.errors) {
parseContext->formatError(error, stream, "ERROR: ");
}
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()) {
parseContext->formatError(error, stream, "ERROR: ");
}
return std::nullopt;
}
if(unit->source) {
unit->library = loadLibraryFromFile(parseContext, unit->source->asString().c_str(), stream);
}
return *unit;
}

View File

@ -1,15 +0,0 @@
#ifndef PARSERUTIL_H
#define PARSERUTIL_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

View File

@ -30,142 +30,119 @@ 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 {
};
@ -173,23 +150,25 @@ 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:
@ -204,17 +183,14 @@ 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;
}
@ -227,7 +203,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;
}
@ -236,10 +212,8 @@ public:
// Copy-constructors
//
poly(const poly& p)
{
if (!p)
{
poly(const poly &p) {
if (!p) {
return;
}
auto tmp_cb = p.cb_->clone();
@ -251,8 +225,7 @@ public:
// Move-constructors
//
poly(poly&& p) noexcept
{
poly(poly &&p) noexcept {
ptr_ = p.ptr_;
cb_ = std::move(p.cb_);
p.ptr_ = nullptr;
@ -262,25 +235,23 @@ 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;
}
@ -288,14 +259,13 @@ 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();
}
@ -303,15 +273,12 @@ 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;
@ -328,10 +295,8 @@ 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;
}
@ -346,8 +311,7 @@ public:
// Modifiers
//
void swap(poly& p) noexcept
{
void swap(poly &p) noexcept {
using std::swap;
swap(ptr_, p.ptr_);
swap(cb_, p.cb_);
@ -358,31 +322,26 @@ 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_;
}
@ -391,18 +350,17 @@ 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)...);
@ -410,32 +368,30 @@ 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;

View File

@ -2,7 +2,7 @@
#define PRESULT_H
#include "expected.h"
#include "sourceerror.h"
#include "source_error.h"
#include <optional>
@ -32,19 +32,18 @@ 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 parse* functions
/// Alternative to PResult that is returned from parseLibrary* functions
/// that only consume one token so they can fail without affecting
/// the parser state
template<typename T>

View File

@ -0,0 +1,5 @@
#include "source_error.h"
SourceError::SourceError(Span span, std::string message)
: span(span), message(std::move(message)) {}

View File

@ -1,5 +1,5 @@
#ifndef SOURCEERROR_H
#define SOURCEERROR_H
#ifndef SOURCE_ERROR_H
#define SOURCE_ERROR_H
#include "token.h"
#include <string>
@ -11,4 +11,4 @@ struct SourceError {
SourceError(Span span, std::string message);
};
#endif // SOURCEERROR_H
#endif // SOURCE_ERROR_H

View File

@ -1,6 +0,0 @@
#include "sourceerror.h"
SourceError::SourceError(Span span, std::string message)
: span(std::move(span)), message(std::move(message))
{}

View File

@ -4,32 +4,23 @@
Position::Position()
: fileId(0), line(0), col(0), offset(0)
{}
: fileId(0), line(0), col(0), offset(0) {}
Position::Position(unsigned file, unsigned line, unsigned col, unsigned offset)
: fileId(file), line(line), col(col), offset(offset)
{}
: fileId(file), line(line), col(col), offset(offset) {}
Span::Span()
: lo(0, 0, 0, 0), hi(0, 0, 0, 0)
{}
: lo(0, 0, 0, 0), hi(0, 0, 0, 0) {}
Span::Span(Position begin, Position end)
: lo(begin), hi(end)
{}
: lo(begin), hi(end) {}
Span::Span(Position begin)
: Span(begin, Position(begin.fileId, begin.line, begin.col+1, begin.offset+1))
{}
: Span(begin, Position(begin.fileId, begin.line, begin.col + 1, begin.offset + 1)) {}
Span Span::to(const Span &span) const
{
return Span(this->lo, span.hi);
Span Span::to(const Span &span) const {
return {this->lo, span.hi};
}
Token::Token(TokenType type, Span span, std::string text)
: type(type)
, span(std::move(span))
, text(std::move(text))
{}
: type(type), span(span), text(std::move(text)) {}

View File

@ -12,6 +12,7 @@ struct Position {
unsigned offset;
Position();
Position(unsigned fileId, unsigned line, unsigned col, unsigned offset);
};
@ -23,10 +24,12 @@ struct Span {
Position hi;
Span();
Span(Position lo, Position hi);
Span(Position lo);
Span to(const Span& span) const;
Span to(const Span &span) const;
};
enum class TokenType {
@ -65,10 +68,14 @@ enum class TokenType {
TRUE,
FALSE,
// NULL
NIL,
// KEYWORDS
KW_NAME,
KW_INFO,
KW_HEADER,
KW_COMPONENT_HEADER,
KW_DIRECTORY,
KW_LIBRARY,
KW_ADDRESS,
@ -121,6 +128,10 @@ enum class TokenType {
ERROR,
WARNING,
// WIRE SETTINGS
HIDDEN,
TERMINATE_WITH,
// OTHER
END_OF_FILE
};

View File

@ -0,0 +1,173 @@
#include "tokens_type.h"
enum TokenClass {
KEYWORD_NAME = 4,
TOKENIZABLE = 8
};
struct TokenInfo {
std::string text;
unsigned short attributes;
};
struct TokenTables {
std::unordered_map<TokenType, TokenInfo> allTokensInfo;
std::unordered_map<std::string, TokenType> keywords;
TokenType tokenize(std::string value, TokenType initial);
bool is_keyword(TokenType token);
void add(TokenType tokenType, const std::string &txt,
unsigned short attribs = 0);
TokenTables();
};
static TokenTables tokenTables;
void TokenTables::add(TokenType tokenType, const std::string &txt,
unsigned short attribs) {
allTokensInfo[tokenType] = TokenInfo{txt, attribs};
if (attribs & KEYWORD_NAME)
keywords[txt] = tokenType;
}
TokenTables::TokenTables() {
add(TokenType::IDENTIFIER, "identifier");
add(TokenType::KEYWORD, "keyword", KEYWORD_NAME);
// Literals (bool is not here, it has two keywords: false and true)
add(TokenType::NUMBER, "number");
add(TokenType::STRING, "string");
add(TokenType::COLOR, "color");
// Parentheses of all kinds
add(TokenType::LPAREN, "(");
add(TokenType::RPAREN, ")");
add(TokenType::LBRACKET, "[");
add(TokenType::RBRACKET, "]");
add(TokenType::LBRACE, "{");
add(TokenType::RBRACE, "}");
add(TokenType::LT, "<");
add(TokenType::GT, ">");
// assignments
add(TokenType::EQUALS, "=");
// miscellaneous
add(TokenType::DOT, ".");
add(TokenType::COLON, ":");
add(TokenType::SEMICOLON, ";");
add(TokenType::COMMA, ",");
add(TokenType::WHITESPACE, "whitespace");
add(TokenType::COMMENT, "comment");
add(TokenType::TRUE, "true", TOKENIZABLE);
add(TokenType::FALSE, "false", TOKENIZABLE);
add(TokenType::IF, "if", TOKENIZABLE);
add(TokenType::ELSE, "else", TOKENIZABLE);
add(TokenType::DEFAULT, "default", TOKENIZABLE);
add(TokenType::NIL, "null", TOKENIZABLE);
// all keywords
add(TokenType::KW_NAME, "@name", TOKENIZABLE | KEYWORD_NAME);
add(TokenType::KW_INFO, "@info", TOKENIZABLE | KEYWORD_NAME);
add(TokenType::KW_HEADER, "@header", TOKENIZABLE | KEYWORD_NAME);
add(TokenType::KW_COMPONENT_HEADER, "@componentHeader", TOKENIZABLE | KEYWORD_NAME);
add(TokenType::KW_DIRECTORY, "@directory", TOKENIZABLE | KEYWORD_NAME);
add(TokenType::KW_LIBRARY, "@library", TOKENIZABLE | KEYWORD_NAME);
add(TokenType::KW_ADDRESS, "@address", TOKENIZABLE | KEYWORD_NAME);
add(TokenType::KW_COMPONENT, "@component", TOKENIZABLE | KEYWORD_NAME);
add(TokenType::KW_MESSAGES, "@messages", TOKENIZABLE | KEYWORD_NAME);
add(TokenType::KW_INSTANCE_NAME, "@instanceName", TOKENIZABLE | KEYWORD_NAME);
add(TokenType::KW_COUNT, "@count", TOKENIZABLE | KEYWORD_NAME);
add(TokenType::KW_DISPLAY, "@display", TOKENIZABLE | KEYWORD_NAME);
add(TokenType::KW_PIN, "@pin", TOKENIZABLE | KEYWORD_NAME);
add(TokenType::KW_TOOLTIP, "@tooltip", TOKENIZABLE | KEYWORD_NAME);
add(TokenType::KW_CONNECTION, "@connection", TOKENIZABLE | KEYWORD_NAME);
add(TokenType::KW_ATTRIBUTE, "@attribute", TOKENIZABLE | KEYWORD_NAME);
add(TokenType::KW_SOURCE, "@source", TOKENIZABLE | KEYWORD_NAME);
add(TokenType::KW_POPUP, "@popup", TOKENIZABLE | KEYWORD_NAME);
add(TokenType::KW_RULE, "@rule", TOKENIZABLE | KEYWORD_NAME);
add(TokenType::KW_TITLE, "@title", TOKENIZABLE | KEYWORD_NAME);
add(TokenType::KW_TEXT, "@text", TOKENIZABLE | KEYWORD_NAME);
add(TokenType::KW_BUS, "@bus", TOKENIZABLE | KEYWORD_NAME);
add(TokenType::KW_WIRES, "@wires", TOKENIZABLE | KEYWORD_NAME);
add(TokenType::KW_ENUMERATED, "@enumerated", TOKENIZABLE | KEYWORD_NAME);
add(TokenType::KW_WIRE, "@wire", TOKENIZABLE | KEYWORD_NAME);
add(TokenType::KW_INSTANCE, "@instance", TOKENIZABLE | KEYWORD_NAME);
add(TokenType::KW_SCHEMA, "@schema", TOKENIZABLE | KEYWORD_NAME);
add(TokenType::KW_POSITION, "@position", TOKENIZABLE | KEYWORD_NAME);
add(TokenType::KW_SIZE, "@size", TOKENIZABLE | KEYWORD_NAME);
// All types
add(TokenType::INT_TYPE, "int", TOKENIZABLE);
add(TokenType::STRING_TYPE, "string", TOKENIZABLE);
add(TokenType::BOOL_TYPE, "bool", TOKENIZABLE);
add(TokenType::WIRE_TYPE, "wire", TOKENIZABLE);
// WireNode types
add(TokenType::WIRE_DEFAULT, "normal_wire", TOKENIZABLE);
add(TokenType::WIRE_AND, "wired_and", TOKENIZABLE);
add(TokenType::WIRE_OR, "wired_or", TOKENIZABLE);
add(TokenType::R_WIRE, "r_wire", TOKENIZABLE);
// ComponentNode types
add(TokenType::CT_MEMORY, "memory", TOKENIZABLE);
add(TokenType::CT_PROCESSOR, "processor", TOKENIZABLE);
// PinNode type
add(TokenType::PIN_IN, "in", TOKENIZABLE);
add(TokenType::PIN_OUT, "out", TOKENIZABLE);
add(TokenType::PIN_IN_OUT, "inOut", TOKENIZABLE);
// ActionNode types
add(TokenType::ERROR, "error", TOKENIZABLE);
add(TokenType::WARNING, "warning", TOKENIZABLE);
// WireNode settings types
add(TokenType::HIDDEN, "hidden", TOKENIZABLE);
add(TokenType::TERMINATE_WITH, "terminate_with", TOKENIZABLE);
// Miscelaneous
add(TokenType::END_OF_FILE, "eof");
}
const std::string &tokenTypeToString(TokenType tokenType) {
return tokenTables.allTokensInfo[tokenType].text;
}
TokenType TokenTables::tokenize(std::string value, TokenType initial) {
for (auto &[key, param]: allTokensInfo) {
if (param.attributes & TOKENIZABLE && param.text == value) {
return key;
}
}
return initial;
}
bool TokenTables::is_keyword(TokenType token) {
for (auto &[key, param]: allTokensInfo) {
if (param.attributes & KEYWORD_NAME && key == token) {
return true;
}
}
return false;
}
TokenType from_token(std::string value, TokenType initial) {
return tokenTables.tokenize(value, initial);
}
bool is_keyword(TokenType tokenType) {
return tokenTables.is_keyword(tokenType);
}

View File

@ -0,0 +1,15 @@
#ifndef TOKENS_TYPE_H
#define TOKENS_TYPE_H
#include "token.h"
#include <unordered_map>
#include <string>
const std::string &tokenTypeToString(TokenType tokenType);
TokenType from_token(std::string value, TokenType initial);
bool is_keyword(TokenType tokenType);
#endif // TOKENS_TYPE_H

Some files were not shown because too many files have changed in this diff Show More