Compare commits
47 Commits
562b77ea0a
...
master
Author | SHA1 | Date |
---|---|---|
Borna Rajković | 947f6e464b | |
Borna Rajković | 9c332ac3e7 | |
Borna Rajković | edfd7fdf37 | |
Borna Rajković | 6ed60a2c26 | |
Borna Rajković | 9129a4bf43 | |
Borna Rajković | 350aa95da5 | |
Borna Rajković | d2fc849cc2 | |
Borna Rajković | eaa115d115 | |
Borna Rajković | 7be3a1b5bc | |
Borna Rajković | fe4a39803c | |
Borna Rajković | 1ec0433cfe | |
Borna Rajković | ae2a3c64ef | |
Borna Rajković | 09991904e9 | |
Borna Rajković | e6bbaabde4 | |
Borna Rajković | 6dfe86335d | |
Borna Rajković | 4d4cf136fb | |
Borna Rajković | f66fc1db26 | |
Borna Rajković | 1759adf25a | |
Borna Rajković | 1ec8b10ef5 | |
Borna Rajković | 9b7ede933a | |
Borna Rajković | 3172d7e4cf | |
Borna Rajković | f93a2afa63 | |
Borna Rajković | 86b8861533 | |
Borna Rajković | 0c4afe87d9 | |
Borna Rajković | aac972c6ca | |
Borna Rajković | 5cf8235608 | |
Borna Rajković | cbff8ff5f2 | |
Borna Rajković | 0a658a4aba | |
Borna Rajković | 1100a9f0b9 | |
Borna Rajković | f11551fef6 | |
Borna Rajković | 281926cb8b | |
Borna Rajković | e2e0506041 | |
Borna Rajković | 59b19062ff | |
Borna Rajković | bb423c2184 | |
Borna Rajković | 65020c2b7f | |
Borna Rajković | 23764776f1 | |
Borna Rajković | 05fa2abbb0 | |
Borna Rajković | e7fd7df154 | |
Borna Rajković | 45a668fc46 | |
Borna Rajković | 74a7ef3e7a | |
Borna Rajković | fb8aafb2a9 | |
Borna Rajković | 9ff6633777 | |
Borna Rajković | 5ccd9b2fa4 | |
Borna Rajković | 344fe7cfa6 | |
Borna Rajković | dde9bb8af8 | |
Borna Rajkovic | d6c1023df2 | |
Borna Rajkovic | 9e2b0f6c3c |
|
@ -0,0 +1 @@
|
||||||
|
{"buildTargets":[],"launchTargets":[],"customConfigurationProvider":{"workspaceBrowse":{"browsePath":[],"compilerArgs":[]},"fileIndex":[]}}
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -14,30 +14,28 @@ add_executable(SchemeEditor
|
||||||
comdel/domain/value.cpp
|
comdel/domain/value.cpp
|
||||||
comdel/domain/schema.cpp
|
comdel/domain/schema.cpp
|
||||||
comdel/domain/component.cpp
|
comdel/domain/component.cpp
|
||||||
comdel/domain/connectioninstance.cpp
|
comdel/domain/connection_instance.cpp
|
||||||
comdel/domain/rule.cpp
|
comdel/domain/rule.cpp
|
||||||
comdel/domain/wireinstance.cpp
|
|
||||||
comdel/domain/attribute.cpp
|
comdel/domain/attribute.cpp
|
||||||
comdel/domain/bus.cpp
|
comdel/domain/bus.cpp
|
||||||
comdel/domain/pin.cpp
|
comdel/domain/pin.cpp
|
||||||
comdel/domain/display.cpp
|
comdel/domain/display.cpp
|
||||||
comdel/domain/library.cpp
|
comdel/domain/library.cpp
|
||||||
comdel/domain/functionsignature.cpp
|
comdel/domain/function_signature.cpp
|
||||||
comdel/domain/addressspace.cpp
|
comdel/domain/address_space.cpp
|
||||||
comdel/domain/instanceattribute.cpp
|
comdel/domain/instance_attribute.cpp
|
||||||
comdel/domain/connection.cpp
|
comdel/domain/connection.cpp
|
||||||
comdel/domain/instance.cpp
|
comdel/domain/instance.cpp
|
||||||
comdel/domain/schemacreator.cpp
|
comdel/domain/schema_creator.cpp
|
||||||
comdel/parser/comdelparser.cpp
|
comdel/parser/comdel_parser.cpp
|
||||||
comdel/parser/token.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/parser_util.cpp
|
||||||
comdel/parser/sourceerror.cpp
|
comdel/parser/comdel_lexer.cpp
|
||||||
comdel/parser/parsecontext.cpp
|
|
||||||
comdel/parser/tokenstype.cpp
|
|
||||||
comdel/parser/astnode.cpp
|
|
||||||
comdel/parser/parserutil.cpp
|
|
||||||
comdel/parser/comdellexer.cpp
|
|
||||||
main.cpp
|
main.cpp
|
||||||
mainwindow.ui
|
mainwindow.ui
|
||||||
comdel/domain/comdelvalidator.cpp comdel/domain/comdelvalidator.h comdel/display/dialogmanager.cpp comdel/display/dialogmanager.h comdel/display/attribute_dialog.cpp comdel/display/attribute_dialog.h comdel/display/name_dialog.cpp comdel/display/name_dialog.h)
|
comdel/domain/comdel_validator.cpp comdel/domain/comdel_validator.h comdel/display/dialog/attribute_dialog.cpp comdel/display/dialog/attribute_dialog.h comdel/display/dialog/name_dialog.cpp comdel/display/dialog/name_dialog.h comdel/domain/comdel_generator.cpp comdel/domain/comdel_generator.h comdel/display/library_list.cpp comdel/display/library_list.h application.cpp application.h comdel/display/dialog/single_automatic_dialog.cpp comdel/display/dialog/single_automatic_dialog.h comdel/parser/color.h comdel/display/dialog/generic_dialog.cpp comdel/display/dialog/generic_dialog.h comdel/display/dialog/warning_dialog.cpp comdel/display/dialog/warning_dialog.h comdel/display/dialog/error_dialog.cpp comdel/display/dialog/error_dialog.h comdel/display/dialog/memory_dialog.cpp comdel/display/dialog/memory_dialog.h comdel/display/dialog/success_dialog.cpp comdel/display/dialog/success_dialog.h message_source.cpp message_source.h)
|
||||||
target_link_libraries(SchemeEditor Qt5::Core Qt5::Gui Qt5::Widgets)
|
target_link_libraries(SchemeEditor Qt5::Core Qt5::Gui Qt5::Widgets)
|
||||||
|
|
|
@ -9,77 +9,92 @@ CONFIG += c++17
|
||||||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
|
comdel/display/dialog/attribute_dialog.cpp \
|
||||||
|
comdel/display/dialog/error_dialog.cpp \
|
||||||
|
comdel/display/dialog/generic_dialog.cpp \
|
||||||
|
comdel/display/dialog/memory_dialog.cpp \
|
||||||
|
comdel/display/dialog/name_dialog.cpp \
|
||||||
|
comdel/display/dialog/single_automatic_dialog.cpp \
|
||||||
|
comdel/display/dialog/success_dialog.cpp \
|
||||||
|
comdel/display/dialog/warning_dialog.cpp \
|
||||||
comdel/display/component_display.cpp \
|
comdel/display/component_display.cpp \
|
||||||
comdel/display/library_display.cpp \
|
comdel/display/library_display.cpp \
|
||||||
|
comdel/display/library_list.cpp \
|
||||||
comdel/display/schema_display.cpp \
|
comdel/display/schema_display.cpp \
|
||||||
comdel/domain/addressspace.cpp \
|
comdel/domain/address_space.cpp \
|
||||||
comdel/domain/attribute.cpp \
|
comdel/domain/attribute.cpp \
|
||||||
comdel/domain/bus.cpp \
|
comdel/domain/bus.cpp \
|
||||||
comdel/domain/schemacreator.cpp \
|
comdel/domain/comdel_generator.cpp \
|
||||||
|
comdel/domain/comdel_validator.cpp \
|
||||||
comdel/domain/component.cpp \
|
comdel/domain/component.cpp \
|
||||||
comdel/domain/connection.cpp \
|
comdel/domain/connection.cpp \
|
||||||
comdel/domain/comdelvalidator.cpp \
|
comdel/domain/connection_instance.cpp \
|
||||||
comdel/domain/connectioninstance.cpp \
|
|
||||||
comdel/domain/display.cpp \
|
comdel/domain/display.cpp \
|
||||||
comdel/domain/functionsignature.cpp \
|
comdel/domain/function_signature.cpp \
|
||||||
comdel/domain/instance.cpp \
|
comdel/domain/instance.cpp \
|
||||||
comdel/domain/instanceattribute.cpp \
|
comdel/domain/instance_attribute.cpp \
|
||||||
comdel/domain/library.cpp \
|
comdel/domain/library.cpp \
|
||||||
comdel/domain/pin.cpp \
|
comdel/domain/pin.cpp \
|
||||||
comdel/domain/rule.cpp \
|
comdel/domain/rule.cpp \
|
||||||
comdel/domain/schema.cpp \
|
comdel/domain/schema.cpp \
|
||||||
|
comdel/domain/schema_creator.cpp \
|
||||||
comdel/domain/value.cpp \
|
comdel/domain/value.cpp \
|
||||||
comdel/domain/wireinstance.cpp \
|
comdel/parser/ast_nodes.cpp \
|
||||||
comdel/parser/astnode.cpp \
|
comdel/parser/comdel_lexer.cpp \
|
||||||
comdel/parser/comdellexer.cpp \
|
comdel/parser/comdel_parser.cpp \
|
||||||
comdel/parser/comdelparser.cpp \
|
comdel/parser/parse_context.cpp \
|
||||||
comdel/parser/parsecontext.cpp \
|
comdel/parser/parser_util.cpp \
|
||||||
comdel/parser/parserutil.cpp \
|
comdel/parser/source_error.cpp \
|
||||||
comdel/parser/sourceerror.cpp \
|
|
||||||
comdel/parser/token.cpp \
|
comdel/parser/token.cpp \
|
||||||
comdel/parser/tokenstype.cpp \
|
comdel/parser/tokens_type.cpp \
|
||||||
comdel/display/dialogmanager.cpp \
|
application.cpp \
|
||||||
comdel/display/attribute_dialog.cpp \
|
|
||||||
comdel/display/name_dialog.cpp \
|
|
||||||
main.cpp \
|
main.cpp \
|
||||||
|
message_source.cpp \
|
||||||
mainwindow.cpp
|
mainwindow.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
|
comdel/display/dialog/attribute_dialog.h \
|
||||||
|
comdel/display/dialog/error_dialog.h \
|
||||||
|
comdel/display/dialog/generic_dialog.h \
|
||||||
|
comdel/display/dialog/memory_dialog.h \
|
||||||
|
comdel/display/dialog/name_dialog.h \
|
||||||
|
comdel/display/dialog/single_automatic_dialog.h \
|
||||||
|
comdel/display/dialog/success_dialog.h \
|
||||||
|
comdel/display/dialog/warning_dialog.h \
|
||||||
comdel/display/component_display.h \
|
comdel/display/component_display.h \
|
||||||
comdel/display/library_display.h \
|
comdel/display/library_display.h \
|
||||||
|
comdel/display/library_list.h \
|
||||||
comdel/display/schema_display.h \
|
comdel/display/schema_display.h \
|
||||||
comdel/domain/addressspace.h \
|
comdel/domain/address_space.h \
|
||||||
comdel/domain/attribute.h \
|
comdel/domain/attribute.h \
|
||||||
comdel/domain/bus.h \
|
comdel/domain/bus.h \
|
||||||
comdel/domain/schemacreator.h \
|
comdel/domain/comdel_generator.h \
|
||||||
|
comdel/domain/comdel_validator.h \
|
||||||
comdel/domain/component.h \
|
comdel/domain/component.h \
|
||||||
comdel/domain/connection.h \
|
comdel/domain/connection.h \
|
||||||
comdel/domain/comdelvalidator.h \
|
comdel/domain/connection_instance.h \
|
||||||
comdel/domain/connectioninstance.h \
|
|
||||||
comdel/domain/display.h \
|
comdel/domain/display.h \
|
||||||
comdel/domain/functionsignature.h \
|
comdel/domain/function_signature.h \
|
||||||
comdel/domain/instance.h \
|
comdel/domain/instance.h \
|
||||||
comdel/domain/instanceattribute.h \
|
comdel/domain/instance_attribute.h \
|
||||||
comdel/domain/library.h \
|
comdel/domain/library.h \
|
||||||
comdel/domain/pin.h \
|
comdel/domain/pin.h \
|
||||||
comdel/domain/rule.h \
|
comdel/domain/rule.h \
|
||||||
comdel/domain/schema.h \
|
comdel/domain/schema.h \
|
||||||
|
comdel/domain/schema_creator.h \
|
||||||
comdel/domain/value.h \
|
comdel/domain/value.h \
|
||||||
comdel/domain/wireinstance.h \
|
comdel/parser/ast_nodes.h \
|
||||||
comdel/parser/astnode.h \
|
comdel/parser/comdel_lexer.h \
|
||||||
comdel/parser/comdellexer.h \
|
comdel/parser/comdel_parser.h \
|
||||||
comdel/parser/comdelparser.h \
|
|
||||||
comdel/parser/expected.h \
|
comdel/parser/expected.h \
|
||||||
comdel/parser/parsecontext.h \
|
comdel/parser/parse_context.h \
|
||||||
comdel/parser/parserutil.h \
|
comdel/parser/parser_util.h \
|
||||||
comdel/parser/poly.h \
|
comdel/parser/poly.h \
|
||||||
comdel/parser/presult.h \
|
comdel/parser/presult.h \
|
||||||
comdel/parser/sourceerror.h \
|
comdel/parser/source_error.h \
|
||||||
comdel/parser/token.h \
|
comdel/parser/token.h \
|
||||||
comdel/parser/tokenstype.h \
|
comdel/parser/tokens_type.h \
|
||||||
comdel/display/dialogmanager.h \
|
message_source.h \
|
||||||
comdel/display/attribute_dialog.h \
|
|
||||||
comdel/display/name_dialog.h \
|
|
||||||
mainwindow.h
|
mainwindow.h
|
||||||
|
|
||||||
FORMS += \
|
FORMS += \
|
||||||
|
|
|
@ -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 schema library" << std::endl;
|
||||||
|
return {false, errors};
|
||||||
|
}
|
||||||
|
|
||||||
|
domain::ComdelValidator validator{validators};
|
||||||
|
|
||||||
|
domain::ValidationContext context;
|
||||||
|
context.instance = nullptr;
|
||||||
|
context.attribute = nullptr;
|
||||||
|
context.addressSpaces = {};
|
||||||
|
|
||||||
|
auto memoryReferenceValidation = validator.validateMemoryReferences(*schema, *library, context);
|
||||||
|
errors.insert(errors.end(), memoryReferenceValidation.begin(), memoryReferenceValidation.end());
|
||||||
|
|
||||||
|
auto nameValidation = validator.validateInstanceNames(*schema, *library, context);
|
||||||
|
errors.insert(errors.end(), nameValidation.begin(), nameValidation.end());
|
||||||
|
|
||||||
|
if(!errors.empty()) {
|
||||||
|
clear();
|
||||||
|
return {false, errors};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {true, errors};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Application::generateSchema(std::ostringstream &output) {
|
||||||
|
if (schema == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
domain::generate_schema(libraryPath, schema, output);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<domain::ValidationError> Application::validateSchema() {
|
||||||
|
if (schema == nullptr) {
|
||||||
|
return std::vector<domain::ValidationError>{domain::ValidationError(domain::Action::ERROR, "No schema loaded")};
|
||||||
|
}
|
||||||
|
|
||||||
|
domain::ComdelValidator validator{validators};
|
||||||
|
|
||||||
|
domain::ValidationContext context;
|
||||||
|
context.instance = nullptr;
|
||||||
|
context.attribute = nullptr;
|
||||||
|
context.addressSpaces = {};
|
||||||
|
|
||||||
|
for (auto &lib: library->getAddressSpaces()) {
|
||||||
|
context.addressSpaces.insert(std::make_pair(lib.getName(), lib));
|
||||||
|
}
|
||||||
|
auto errors = validator.validateSchema(*schema, context);
|
||||||
|
|
||||||
|
auto memoryReferenceValidation = validator.validateMemoryReferences(*schema, *library, context);
|
||||||
|
errors.insert(errors.end(), memoryReferenceValidation.begin(), memoryReferenceValidation.end());
|
||||||
|
|
||||||
|
auto nameValidation = validator.validateInstanceNames(*schema, *library, context);
|
||||||
|
errors.insert(errors.end(), nameValidation.begin(), nameValidation.end());
|
||||||
|
|
||||||
|
auto countValidation = validator.validateInstanceCount(*schema, *library, context);
|
||||||
|
errors.insert(errors.end(), countValidation.begin(), countValidation.end());
|
||||||
|
|
||||||
|
auto pinValidation = validator.validatePinConnections(*schema, *library, context);
|
||||||
|
errors.insert(errors.end(), pinValidation.begin(), pinValidation.end());
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<domain::ValidationError> Application::generateComdel(std::ostringstream &output) {
|
||||||
|
|
||||||
|
auto errors = validateSchema();
|
||||||
|
if (!Application::hasErrors(errors)) {
|
||||||
|
// as long as all validation errors are warning we continue with build
|
||||||
|
domain::generate_comdel(schema, library.value(), output);
|
||||||
|
}
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Application::hasErrors(std::vector<domain::ValidationError> errors) {
|
||||||
|
for (auto &err: errors) {
|
||||||
|
if (err.type == domain::Action::ERROR) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// static instance of application
|
||||||
|
static Application *application = nullptr;
|
||||||
|
|
||||||
|
Application *Application::instance() {
|
||||||
|
if (application == nullptr) {
|
||||||
|
application = new Application();
|
||||||
|
}
|
||||||
|
return application;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<domain::ComponentInstance>
|
||||||
|
Application::addComponent(domain::Component component, std::vector<domain::InstanceAttribute> attributes, int x,
|
||||||
|
int y) {
|
||||||
|
std::set<std::string> names;
|
||||||
|
for (const auto &c: schema->componentInstances) {
|
||||||
|
names.insert(c->name);
|
||||||
|
}
|
||||||
|
std::string name = generateName(names, component.getInstanceName());
|
||||||
|
|
||||||
|
schema->componentInstances.push_back(
|
||||||
|
std::make_shared<domain::ComponentInstance>(name, attributes, std::make_pair(x, y), component));
|
||||||
|
return schema->componentInstances.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<domain::BusInstance> Application::addBus(domain::Bus bus, int x, int y) {
|
||||||
|
std::set<std::string> names;
|
||||||
|
for (const auto &b: schema->busInstances) {
|
||||||
|
names.insert(b->name);
|
||||||
|
}
|
||||||
|
std::string name = generateName(names, bus.getInstanceName());
|
||||||
|
|
||||||
|
schema->busInstances.push_back(std::make_shared<domain::BusInstance>(name, std::make_pair(x, y), bus));
|
||||||
|
return schema->busInstances.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string Application::generateName(std::set<std::string> &names, std::string instanceName) {
|
||||||
|
if (names.find(instanceName) == names.end()) {
|
||||||
|
return instanceName;
|
||||||
|
}
|
||||||
|
char buffer[4];
|
||||||
|
for (int i = 0; i < 1000; i++) {
|
||||||
|
sprintf(buffer, "%03d", i);
|
||||||
|
auto name = instanceName + "_" + buffer;
|
||||||
|
if (names.find(name) == names.end()) {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// return default value as this should never happen
|
||||||
|
return instanceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Application::removeComponent(std::string componentName) {
|
||||||
|
auto component = findComponentByName(componentName);
|
||||||
|
if (component == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::set<domain::BusInstance*> automaticBusses;
|
||||||
|
|
||||||
|
schema->connections.erase(
|
||||||
|
std::remove_if(
|
||||||
|
schema->connections.begin(),
|
||||||
|
schema->connections.end(),
|
||||||
|
[component, &automaticBusses](const std::shared_ptr<domain::ConnectionInstance> &conn) {
|
||||||
|
auto busConnection = dynamic_cast<domain::BusConnectionInstance *>(conn.get());
|
||||||
|
if (busConnection) {
|
||||||
|
if (busConnection->instance == component) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto directConnection = dynamic_cast<domain::DirectConnectionInstance *>(conn.get());
|
||||||
|
if (directConnection) {
|
||||||
|
if (directConnection->instance == component || directConnection->secondInstance == component) {
|
||||||
|
automaticBusses.insert(directConnection->bus);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}),
|
||||||
|
schema->connections.end()
|
||||||
|
);
|
||||||
|
|
||||||
|
schema->busInstances.erase(
|
||||||
|
std::remove_if(
|
||||||
|
schema->busInstances.begin(),
|
||||||
|
schema->busInstances.end(),
|
||||||
|
[&automaticBusses](const std::shared_ptr<domain::BusInstance> &bus) {
|
||||||
|
return automaticBusses.count(bus.get());
|
||||||
|
}),
|
||||||
|
schema->busInstances.end()
|
||||||
|
);
|
||||||
|
|
||||||
|
if(component->component.getType() == domain::Component::MEMORY) {
|
||||||
|
for(auto& comp: schema->componentInstances) {
|
||||||
|
if(comp->component.getType() == domain::Component::PROCESSOR) {
|
||||||
|
for(auto& attribute: comp->attributes) {
|
||||||
|
if(attribute.value.isType(domain::Value::MEMORY_REFERENCE) && attribute.value.asMemoryReference() == component->name) {
|
||||||
|
attribute.value = domain::Value::fromMemoryReference(std::nullopt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto iter = schema->componentInstances.begin(); iter != schema->componentInstances.end(); ++iter) {
|
||||||
|
if(iter->get() == component) {
|
||||||
|
schema->componentInstances.erase(iter);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::removeConnection(domain::ConnectionInstance *connectionInstance) {
|
||||||
|
if(auto directConnection = dynamic_cast<domain::DirectConnectionInstance*>(connectionInstance)) {
|
||||||
|
schema->busInstances.erase(
|
||||||
|
std::remove_if(
|
||||||
|
schema->busInstances.begin(),
|
||||||
|
schema->busInstances.end(),
|
||||||
|
[directConnection](const std::shared_ptr<domain::BusInstance> &bus) {
|
||||||
|
return directConnection->bus == bus.get();
|
||||||
|
}),
|
||||||
|
schema->busInstances.end()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
schema->connections.erase(
|
||||||
|
std::remove_if(
|
||||||
|
schema->connections.begin(),
|
||||||
|
schema->connections.end(),
|
||||||
|
[connectionInstance](const std::shared_ptr<domain::ConnectionInstance> &conn) {
|
||||||
|
return connectionInstance == conn.get();
|
||||||
|
}),
|
||||||
|
schema->connections.end()
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Application::removeBus(std::string busName) {
|
||||||
|
auto bus = findBusByName(busName);
|
||||||
|
if (bus == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
schema->connections.erase(
|
||||||
|
std::remove_if(
|
||||||
|
schema->connections.begin(),
|
||||||
|
schema->connections.end(),
|
||||||
|
[bus](const std::shared_ptr<domain::ConnectionInstance> &conn) {
|
||||||
|
auto busConnection = dynamic_cast<domain::BusConnectionInstance *>(conn.get());
|
||||||
|
if (busConnection) {
|
||||||
|
if (busConnection->bus == bus) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}),
|
||||||
|
schema->connections.end()
|
||||||
|
);
|
||||||
|
|
||||||
|
for(auto iter = schema->busInstances.begin(); iter != schema->busInstances.end(); ++iter) {
|
||||||
|
if(iter->get() == bus) {
|
||||||
|
schema->busInstances.erase(iter);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
domain::ComponentInstance *Application::findComponentByName(std::string componentName) {
|
||||||
|
for (auto &comp: schema->componentInstances) {
|
||||||
|
if (comp->name == componentName) {
|
||||||
|
return comp.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
domain::BusInstance *Application::findBusByName(std::string busName) {
|
||||||
|
for (auto &bus: schema->busInstances) {
|
||||||
|
if (bus->name == busName) {
|
||||||
|
return bus.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::renameComponent(std::string currentName, std::string newName) {
|
||||||
|
if(currentName == newName) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto component = findComponentByName(currentName);
|
||||||
|
if(component) {
|
||||||
|
component->name = newName;
|
||||||
|
if(component->component.getType() == domain::Component::MEMORY) {
|
||||||
|
for(auto& comp: schema->componentInstances) {
|
||||||
|
if(comp.get()->component.getType() == domain::Component::PROCESSOR) {
|
||||||
|
for(auto& attribute: comp.get()->attributes) {
|
||||||
|
if(attribute.value.isType(domain::Value::MEMORY_REFERENCE) && attribute.value.asMemoryReference() == currentName) {
|
||||||
|
attribute.value = domain::Value::fromMemoryReference(newName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::renameBus(std::string currentName, std::string newName) {
|
||||||
|
if(currentName == newName) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto bus = findBusByName(currentName);
|
||||||
|
if(bus) {
|
||||||
|
bus->name = newName;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
|
@ -1,5 +0,0 @@
|
||||||
//
|
|
||||||
// Created by bbr on 18. 04. 2022..
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "attribute_dialog.h"
|
|
|
@ -1,75 +0,0 @@
|
||||||
#ifndef ATTRIBUTE_DIALOG_H
|
|
||||||
#define ATTRIBUTE_DIALOG_H
|
|
||||||
|
|
||||||
#include <QIntValidator>
|
|
||||||
#include <QGroupBox>
|
|
||||||
#include <QRadioButton>
|
|
||||||
#include <QDialog>
|
|
||||||
#include <QLineEdit>
|
|
||||||
#include <QLabel>
|
|
||||||
#include <QVBoxLayout>
|
|
||||||
#include <comdel/domain/instanceattribute.h>
|
|
||||||
|
|
||||||
#include <comdel/domain/value.h>
|
|
||||||
|
|
||||||
namespace display {
|
|
||||||
|
|
||||||
class AttributeDialog: public QDialog {
|
|
||||||
|
|
||||||
public:
|
|
||||||
AttributeDialog(domain::InstanceAttribute *attribute) {
|
|
||||||
this->setWindowTitle(QString::fromStdString("Izmjeni " + attribute->attribute.getName()));
|
|
||||||
|
|
||||||
auto layout = new QVBoxLayout(this);
|
|
||||||
this->setLayout(layout);
|
|
||||||
auto popup = *attribute->attribute.getPopup();
|
|
||||||
|
|
||||||
layout->addWidget(new QLabel(popup.getTitle().c_str()));
|
|
||||||
layout->addWidget(new QLabel(popup.getText().c_str()));
|
|
||||||
|
|
||||||
auto type = attribute->attribute.getDefault().getType();
|
|
||||||
|
|
||||||
if(attribute->attribute.getPopup()->isEnumerated()) {
|
|
||||||
|
|
||||||
} else if(!(type == domain::Value::ValueType::WIRE_REFERENCE || type == domain::Value::ValueType::BOOL)) {
|
|
||||||
|
|
||||||
auto edit = new QLineEdit(this);
|
|
||||||
layout->addWidget(edit);
|
|
||||||
|
|
||||||
switch (attribute->attribute.getDefault().getType()) {
|
|
||||||
case domain::Value::ValueType::INT:
|
|
||||||
edit->setValidator(new QIntValidator(-10000000, 10000000, edit));
|
|
||||||
edit->insert(std::to_string(attribute->value.asInt()).c_str());
|
|
||||||
break;
|
|
||||||
case domain::Value::ValueType::STRING:
|
|
||||||
edit->insert(attribute->value.asString().c_str());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} else if(type == domain::Value::ValueType::BOOL) {
|
|
||||||
auto *group = new QGroupBox(this);
|
|
||||||
group->setCheckable(true);
|
|
||||||
group->setChecked(true);
|
|
||||||
|
|
||||||
auto isTrue = new QRadioButton("true", group);
|
|
||||||
auto isFalse = new QRadioButton("false", group);
|
|
||||||
|
|
||||||
if(attribute->value.asBool()) {
|
|
||||||
isTrue->setChecked(true);
|
|
||||||
} else {
|
|
||||||
isFalse->setChecked(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
layout->addWidget(group);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif //ATTRIBUTE_DIALOG_H
|
|
|
@ -1,87 +1,356 @@
|
||||||
#include "component_display.h"
|
#include "component_display.h"
|
||||||
|
#include "comdel/display/dialog/attribute_dialog.h"
|
||||||
|
#include "comdel/display/dialog/name_dialog.h"
|
||||||
|
#include "mainwindow.h"
|
||||||
|
#include "application.h"
|
||||||
|
#include "comdel/display/dialog/single_automatic_dialog.h"
|
||||||
|
#include "comdel/display/dialog/memory_dialog.h"
|
||||||
|
#include "message_source.h"
|
||||||
|
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
|
#include <QLine>
|
||||||
|
#include <QPen>
|
||||||
#include <QGraphicsSceneContextMenuEvent>
|
#include <QGraphicsSceneContextMenuEvent>
|
||||||
#include <iostream>
|
#include <set>
|
||||||
|
|
||||||
#include "dialogmanager.h"
|
|
||||||
|
|
||||||
namespace display {
|
namespace display {
|
||||||
|
|
||||||
ComponentWrapper *ComponentWrapper::ofWire(domain::WireInstance *wire) {
|
QPen connectionPen(QColor::fromRgb(150, 150, 250));
|
||||||
auto component = new ComponentWrapper();
|
|
||||||
component->wireInstance = wire;
|
|
||||||
component->redraw();
|
|
||||||
return component;
|
|
||||||
}
|
|
||||||
ComponentWrapper *ComponentWrapper::ofComponent(domain::ComponentInstance *instance) {
|
|
||||||
auto component = new ComponentWrapper();
|
|
||||||
component->componentInstance = instance;
|
|
||||||
component->setFlag(QGraphicsItem::ItemIsMovable, true);
|
|
||||||
component->componentItem = new ComponentItem(instance, component);
|
|
||||||
|
|
||||||
for(auto& pin: instance->component.getPins()) {
|
Component::Component(const std::shared_ptr<domain::ComponentInstance> &instance): instance(instance) {
|
||||||
component->pinItems.push_back(new PinItem(pin, component));
|
setFlag(ItemSendsGeometryChanges, true);
|
||||||
|
setToolTip(QString::fromStdString(instance->name + "::" + instance->component.getDisplayName()));
|
||||||
|
instance->component.getDisplay().render(this, domain::ui::DisplayContext(instance.get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
component->redraw();
|
void Component::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) {
|
||||||
return component;
|
|
||||||
}
|
|
||||||
ComponentWrapper *ComponentWrapper::ofBus(domain::BusInstance *instance) {
|
|
||||||
auto component = new ComponentWrapper();
|
|
||||||
component->busInstance = instance;
|
|
||||||
component->setFlag(QGraphicsItem::ItemIsMovable, true);
|
|
||||||
component->redraw();
|
|
||||||
return component;
|
|
||||||
}
|
|
||||||
void ComponentWrapper::redraw() {
|
|
||||||
if(componentInstance) {
|
|
||||||
componentItem->redraw();
|
|
||||||
for(auto pinItem: pinItems) {
|
|
||||||
pinItem->redraw();
|
|
||||||
}
|
|
||||||
this->addToGroup(new QGraphicsSimpleTextItem(QString::fromStdString(componentInstance->name)));
|
|
||||||
}
|
|
||||||
if(busInstance && busInstance->bus.getDisplay()) {
|
|
||||||
busInstance->bus.getDisplay()->render(this);
|
|
||||||
this->addToGroup(new QGraphicsSimpleTextItem(QString::fromStdString(busInstance->name)));
|
|
||||||
}
|
|
||||||
if(wireInstance) {
|
|
||||||
wireInstance->display.render(this);
|
|
||||||
this->addToGroup(new QGraphicsSimpleTextItem(QString::fromStdString(wireInstance->name)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ComponentItem::ComponentItem(domain::ComponentInstance *instance, QGraphicsItem *parent): componentInstance(instance) {
|
|
||||||
setParentItem(parent);
|
|
||||||
redraw();
|
|
||||||
setToolTip(QString::fromStdString(this->componentInstance->component.getTooltip()));
|
|
||||||
}
|
|
||||||
void ComponentItem::redraw() {
|
|
||||||
componentInstance->component.getDisplay().render(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ComponentItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) {
|
|
||||||
QMenu menu;
|
QMenu menu;
|
||||||
auto componentInstance = this->componentInstance;
|
menu.addAction(QMESSAGE("msg_dialog_name_update"), [this]() {
|
||||||
menu.addAction("Izmjeni ime", [componentInstance](){DialogManager::updateName(componentInstance);});
|
std::set<std::string> names;
|
||||||
|
for(const auto &component: Application::instance()->getSchema()->componentInstances) {
|
||||||
|
names.insert(component->name);
|
||||||
|
}
|
||||||
|
auto dialog = new NameDialog(this->instance->name, names);
|
||||||
|
dialog->exec();
|
||||||
|
|
||||||
|
auto currentName = this->instance->name;
|
||||||
|
auto newName = dialog->getName();
|
||||||
|
|
||||||
|
Application::instance()->renameComponent(currentName, newName);
|
||||||
|
setToolTip(QString::fromStdString(instance->name + "::" + instance->component.getDisplayName()));
|
||||||
|
});
|
||||||
menu.addSeparator();
|
menu.addSeparator();
|
||||||
for(auto attr: componentInstance->attributes) {
|
for (int i = 0; i < this->instance->attributes.size(); i++) {
|
||||||
|
auto *attr = &this->instance->attributes[i];
|
||||||
bool enabled = attr->attribute.getPopup().has_value();
|
bool enabled = attr->attribute.getPopup().has_value();
|
||||||
|
|
||||||
auto action = menu.addAction(QString::fromStdString("Izmjeni " + attr->name),
|
if(attr->value.getType() == domain::Value::MEMORY_REFERENCE) {
|
||||||
[attr](){DialogManager::updateAttribute(attr);});
|
menu.addAction(QMESSAGE("msg_dialog_memory_update"), [attr]() {
|
||||||
|
auto dialog = new MemoryDialog(MESSAGE("msg_dialog_memory_update"),
|
||||||
|
MESSAGE("msg_dialog_actions_update"),
|
||||||
|
attr,
|
||||||
|
Application::instance()->getSchema()->componentInstances);
|
||||||
|
dialog->exec();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
std::map<std::string, std::string> params = {{"attribute", attr->attribute.getDisplayName()}};
|
||||||
|
auto action = menu.addAction(QMESSAGE_PARAM("msg_dialog_attribute_update", params),
|
||||||
|
[attr]() {
|
||||||
|
std::map<std::string, std::string> params = {{"attribute", attr->attribute.getDisplayName()}};
|
||||||
|
auto dialog = new AttributeDialog(MESSAGE_PARAM("msg_dialog_attribute_update", params),
|
||||||
|
"msg_dialog_actions_update",
|
||||||
|
attr);
|
||||||
|
dialog->exec();
|
||||||
|
});
|
||||||
action->setEnabled(enabled);
|
action->setEnabled(enabled);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
menu.addSeparator();
|
||||||
|
std::map<std::string, std::string> params = {{"name", instance->name}};
|
||||||
|
menu.addAction(QMESSAGE_PARAM("msg_dialog_actions_remove_named", params), [this]() {
|
||||||
|
Application::instance()->removeComponent(this->instance->name);
|
||||||
|
auto view = dynamic_cast<Schema *>(this->scene()->views()[0]);
|
||||||
|
view->refreshContent();
|
||||||
|
});
|
||||||
|
|
||||||
|
menu.exec(event->screenPos());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pin::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) {
|
||||||
|
QMenu menu;
|
||||||
|
|
||||||
|
auto pinConnections = Application::instance()->getSchema()->getConnections(componentInstance->name, pin.getName());
|
||||||
|
|
||||||
|
if(isSingleAutomatic(pinConnections)) {
|
||||||
|
auto *update = menu.addMenu(QMESSAGE("msg_pin_update"));
|
||||||
|
auto *remove = menu.addMenu(QMESSAGE("msg_pin_remove"));
|
||||||
|
for (auto pinConnection: pinConnections) {
|
||||||
|
// this always must be true as only directConnections can be connected multiple times
|
||||||
|
if (auto directConnection = dynamic_cast<domain::DirectConnectionInstance *>(pinConnection)) {
|
||||||
|
if (directConnection->bus->bus.getType() == domain::Bus::SINGLE_AUTOMATIC) {
|
||||||
|
auto params = MessageSource::instance()->map(
|
||||||
|
{{"wire1", directConnection->attributes[0].value},
|
||||||
|
{"wire2", directConnection->attributes[1].value}}
|
||||||
|
);
|
||||||
|
update->addAction(QMESSAGE_PARAM("msg_sa_pin_update_title", params),
|
||||||
|
[directConnection]() {
|
||||||
|
auto params = MessageSource::instance()->map(
|
||||||
|
{{"wire1", directConnection->attributes[0].value},
|
||||||
|
{"wire2", directConnection->attributes[1].value}}
|
||||||
|
);
|
||||||
|
auto dialog = new SingleAutomaticDialog(MESSAGE_PARAM("msg_sa_pin_update_title", params),
|
||||||
|
MESSAGE("msg_pin_update_action"),
|
||||||
|
directConnection->attributes);
|
||||||
|
dialog->exec();
|
||||||
|
});
|
||||||
|
remove->addAction(QMESSAGE_PARAM("msg_sa_pin_remove_title", params),
|
||||||
|
[this, directConnection]() {
|
||||||
|
Application::instance()->removeConnection(directConnection);
|
||||||
|
auto view = dynamic_cast<Schema *>(this->scene()->views()[0]);
|
||||||
|
view->refreshContent();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(!pinConnections.empty()) {
|
||||||
|
auto pinConnection = pinConnections[0];
|
||||||
|
if(auto busConnection = dynamic_cast<domain::BusConnectionInstance*>(pinConnection)) {
|
||||||
|
menu.addSection(QString::fromStdString(busConnection->bus->name));
|
||||||
|
} else if(auto directConnection = dynamic_cast<domain::DirectConnectionInstance*>(pinConnection)) {
|
||||||
|
if(directConnection->instance == componentInstance.get()) {
|
||||||
|
menu.addSection(QString::fromStdString(directConnection->secondInstance->name + "." + directConnection->connection.getSecondComponent()->pin));
|
||||||
|
} else {
|
||||||
|
menu.addSection(QString::fromStdString(directConnection->instance->name + "." + directConnection->connection.getComponent().pin));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < pinConnection->attributes.size(); i++) {
|
||||||
|
auto *attr = &pinConnection->attributes[i];
|
||||||
|
std::map<std::string, std::string> params = {{"name", attr->attribute.getDisplayName()}};
|
||||||
|
menu.addAction(QMESSAGE_PARAM("msg_dialog_actions_update_named", params),
|
||||||
|
[attr]() {
|
||||||
|
std::map<std::string, std::string> params = {{"name", attr->attribute.getDisplayName()}};
|
||||||
|
auto dialog = new AttributeDialog(MESSAGE_PARAM("msg_dialog_actions_update_named", params), "msg_pin_update_action", attr);
|
||||||
|
dialog->exec();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
menu.addAction(QMESSAGE("msg_pin_remove_action"), [this, pinConnection]() {
|
||||||
|
Application::instance()->removeConnection(pinConnection);
|
||||||
|
auto view = dynamic_cast<Schema *>(this->scene()->views()[0]);
|
||||||
|
view->refreshContent();
|
||||||
|
});
|
||||||
|
}
|
||||||
menu.exec(event->screenPos());
|
menu.exec(event->screenPos());
|
||||||
}
|
}
|
||||||
|
|
||||||
PinItem::PinItem(domain::Pin pin, QGraphicsItem *parent): pin(pin) {
|
void Pin::mousePressEvent(QGraphicsSceneMouseEvent *event) {
|
||||||
setParentItem(parent);
|
if (event->button() == Qt::MouseButton::LeftButton) {
|
||||||
redraw();
|
auto view = dynamic_cast<Schema *>(this->scene()->views()[0]);
|
||||||
setToolTip(QString::fromStdString(pin.getTooltip()));
|
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 PinItem::redraw() {
|
|
||||||
pin.getDisplay().render(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Pin::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
|
||||||
|
auto view = dynamic_cast<Schema *>(this->scene()->views()[0]);
|
||||||
|
if (view->state == Schema::CREATING_CONNECTION) {
|
||||||
|
auto line = view->context.line->line();
|
||||||
|
line.setP2(event->scenePos());
|
||||||
|
view->context.line->setLine(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pin::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
|
||||||
|
if (event->button() == Qt::MouseButton::LeftButton) {
|
||||||
|
auto view = dynamic_cast<Schema *>(this->scene()->views()[0]);
|
||||||
|
view->state = Schema::DEFAULT;
|
||||||
|
this->scene()->removeItem(view->context.line);
|
||||||
|
delete view->context.line;
|
||||||
|
view->removeConnectable(event->scenePos());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
domain::Pin &Pin::getPin() {
|
||||||
|
return pin;
|
||||||
|
}
|
||||||
|
|
||||||
|
domain::ComponentInstance *Pin::getComponentInstance() {
|
||||||
|
return componentInstance.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Pin::isSingleAutomatic(std::vector<domain::ConnectionInstance *> pinConnections) {
|
||||||
|
if(pinConnections.empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto pinConnection = pinConnections[0];
|
||||||
|
if(auto directConnection = dynamic_cast<domain::DirectConnectionInstance*>(pinConnection)) {
|
||||||
|
return directConnection->bus->bus.getType() == domain::Bus::SINGLE_AUTOMATIC;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Bus::Bus(const std::shared_ptr<domain::BusInstance> &instance): busInstance(instance) {
|
||||||
|
instance->bus.getDisplayBus()->render(this, instance->size);
|
||||||
|
setToolTip(QString::fromStdString(busInstance->name + "::" + busInstance->bus.getName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bus::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) {
|
||||||
|
QMenu menu;
|
||||||
|
menu.addAction(QMESSAGE("msg_dialog_name_update"), [this]() {
|
||||||
|
std::set<std::string> names;
|
||||||
|
for(const auto &component: Application::instance()->getSchema()->busInstances) {
|
||||||
|
names.insert(component->name);
|
||||||
|
}
|
||||||
|
auto dialog = new NameDialog(this->busInstance->name, names);
|
||||||
|
dialog->exec();
|
||||||
|
|
||||||
|
auto currentName = this->busInstance->name;
|
||||||
|
auto newName = dialog->getName();
|
||||||
|
|
||||||
|
Application::instance()->renameBus(currentName, newName);
|
||||||
|
setToolTip(QString::fromStdString(busInstance->name + "::" + busInstance->bus.getDisplayName()));
|
||||||
|
});
|
||||||
|
menu.addSeparator();
|
||||||
|
|
||||||
|
std::map<std::string, std::string> params = {{"name", busInstance->name}};
|
||||||
|
menu.addAction(QMESSAGE_PARAM("msg_dialog_actions_remove_named", params), [this]() {
|
||||||
|
Application::instance()->removeBus(this->busInstance->name);
|
||||||
|
auto view = dynamic_cast<Schema *>(this->scene()->views()[0]);
|
||||||
|
view->refreshContent();
|
||||||
|
});
|
||||||
|
menu.exec(event->screenPos());
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant BusGroup::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) {
|
||||||
|
if (change == ItemPositionChange && scene()) {
|
||||||
|
// value is the new position.
|
||||||
|
QPoint newPos = value.toPointF().toPoint();
|
||||||
|
busInstance->position.first = newPos.x();
|
||||||
|
busInstance->position.second = newPos.y();
|
||||||
|
|
||||||
|
auto view = dynamic_cast<Schema *>(scene()->views()[0]);
|
||||||
|
view->updateConnections();
|
||||||
|
}
|
||||||
|
return QGraphicsItem::itemChange(change, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
BusGroup::BusGroup(const std::shared_ptr<domain::BusInstance> &instance) : busInstance(instance) {
|
||||||
|
setFlag(ItemIsMovable, true);
|
||||||
|
setFlag(ItemSendsGeometryChanges, true);
|
||||||
|
|
||||||
|
setHandlesChildEvents(false);
|
||||||
|
|
||||||
|
bus = new display::Bus(instance);
|
||||||
|
addToGroup(bus);
|
||||||
|
|
||||||
|
setPos(instance->position.first, instance->position.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QVariant ComponentGroup::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) {
|
||||||
|
if (change == ItemPositionChange && scene()) {
|
||||||
|
// value is the new position.
|
||||||
|
QPoint newPos = value.toPointF().toPoint();
|
||||||
|
componentInstance->position.first = newPos.x();
|
||||||
|
componentInstance->position.second = newPos.y();
|
||||||
|
|
||||||
|
auto view = dynamic_cast<Schema *>(scene()->views()[0]);
|
||||||
|
view->updateConnections();
|
||||||
|
}
|
||||||
|
return QGraphicsItem::itemChange(change, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<domain::ComponentInstance> ComponentGroup::getComponentInstance() {
|
||||||
|
return componentInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<display::Pin *> &ComponentGroup::getPins() {
|
||||||
|
return pins;
|
||||||
|
}
|
||||||
|
|
||||||
|
ComponentGroup::ComponentGroup(const std::shared_ptr<domain::ComponentInstance> &instance): componentInstance(
|
||||||
|
instance) {
|
||||||
|
setFlag(ItemIsMovable, true);
|
||||||
|
setFlag(ItemSendsGeometryChanges, true);
|
||||||
|
|
||||||
|
setHandlesChildEvents(false);
|
||||||
|
|
||||||
|
addToGroup(new display::Component(instance));
|
||||||
|
|
||||||
|
for (auto &pin: instance->component.getPins()) {
|
||||||
|
pins.push_back(new display::Pin(pin, componentInstance));
|
||||||
|
addToGroup(pins.back());
|
||||||
|
}
|
||||||
|
|
||||||
|
setPos(instance->position.first, instance->position.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
BusConnection::BusConnection(domain::BusConnectionInstance *connection, ComponentGroup *component, BusGroup *bus): connection(
|
||||||
|
connection), component(component), bus(bus) {
|
||||||
|
updateConnection();
|
||||||
|
setPen(connectionPen);
|
||||||
|
setZValue(-1);
|
||||||
|
setHandlesChildEvents(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusConnection::updateConnection() {
|
||||||
|
auto busPosition = bus->boundingRect();
|
||||||
|
auto pin = connection->instance->component.getPin(
|
||||||
|
connection->connection.getComponent().pin).getDisplayPin();
|
||||||
|
|
||||||
|
setLine(connection->instance->position.first + pin.getConnectionX(),
|
||||||
|
connection->instance->position.second + pin.getConnectionY(),
|
||||||
|
connection->bus->position.first + busPosition.width() / 2,
|
||||||
|
connection->bus->position.second + busPosition.height() / 2);
|
||||||
|
|
||||||
|
connection->start.first = connection->instance->position.first + pin.getConnectionX();
|
||||||
|
connection->start.second = connection->instance->position.second + pin.getConnectionY();
|
||||||
|
connection->end.first = connection->bus->position.first + busPosition.width() / 2;
|
||||||
|
connection->end.second = connection->bus->position.second + busPosition.height() / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
DirectConnection::DirectConnection(domain::DirectConnectionInstance *connection, ComponentGroup *first,
|
||||||
|
ComponentGroup *second): connection(connection), first(first), second(second) {
|
||||||
|
updateConnection();
|
||||||
|
setPen(connectionPen);
|
||||||
|
setZValue(-1);
|
||||||
|
setHandlesChildEvents(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DirectConnection::updateConnection() {
|
||||||
|
domain::ui::Pin pin1, pin2;
|
||||||
|
if(connection->connection.getComponent().component == connection->instance->component.getName()) {
|
||||||
|
pin1 = connection->instance->component.getPin(
|
||||||
|
connection->connection.getComponent().pin).getDisplayPin();
|
||||||
|
pin2 = connection->secondInstance->component.getPin(
|
||||||
|
connection->connection.getSecondComponent()->pin).getDisplayPin();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
pin1 = connection->instance->component.getPin(
|
||||||
|
connection->connection.getSecondComponent()->pin).getDisplayPin();
|
||||||
|
pin2 = connection->secondInstance->component.getPin(
|
||||||
|
connection->connection.getComponent().pin).getDisplayPin();
|
||||||
|
}
|
||||||
|
|
||||||
|
setLine(connection->instance->position.first + pin1.getConnectionX(),
|
||||||
|
connection->instance->position.second + pin1.getConnectionY(),
|
||||||
|
connection->secondInstance->position.first + pin2.getConnectionX(),
|
||||||
|
connection->secondInstance->position.second + pin2.getConnectionY());
|
||||||
|
|
||||||
|
connection->start.first = connection->instance->position.first + pin1.getConnectionX();
|
||||||
|
connection->start.second = connection->instance->position.second + pin1.getConnectionY();
|
||||||
|
connection->end.first = connection->secondInstance->position.first + pin2.getConnectionX();
|
||||||
|
connection->end.second = connection->secondInstance->position.second + pin2.getConnectionY();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace display
|
} // namespace display
|
||||||
|
|
|
@ -2,54 +2,115 @@
|
||||||
#define DISPLAY_COMPONENT_H
|
#define DISPLAY_COMPONENT_H
|
||||||
|
|
||||||
#include <comdel/domain/instance.h>
|
#include <comdel/domain/instance.h>
|
||||||
#include <comdel/domain/wireinstance.h>
|
|
||||||
|
|
||||||
#include <QGraphicsItemGroup>
|
#include <QGraphicsItemGroup>
|
||||||
|
#include <QGraphicsSceneMouseEvent>
|
||||||
|
#include <QGraphicsSceneMouseEvent>
|
||||||
|
#include <utility>
|
||||||
|
#include "comdel/domain/connection_instance.h"
|
||||||
|
|
||||||
namespace display {
|
namespace display {
|
||||||
|
|
||||||
class ComponentItem: public QGraphicsItemGroup
|
class Pin : public QGraphicsItemGroup {
|
||||||
{
|
|
||||||
public:
|
|
||||||
ComponentItem(domain::ComponentInstance *instance, QGraphicsItem *parent);
|
|
||||||
void redraw();
|
|
||||||
private:
|
private:
|
||||||
domain::ComponentInstance *componentInstance;
|
domain::Pin pin;
|
||||||
|
std::shared_ptr<domain::ComponentInstance> componentInstance;
|
||||||
|
|
||||||
public:
|
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;
|
void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PinItem: public QGraphicsItemGroup
|
class ComponentGroup : public QGraphicsItemGroup {
|
||||||
{
|
|
||||||
public:
|
|
||||||
PinItem(domain::Pin pin, QGraphicsItem *parent);
|
|
||||||
void redraw();
|
|
||||||
private:
|
private:
|
||||||
domain::Pin pin;
|
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 ComponentWrapper: public QGraphicsItemGroup
|
class BusGroup : public QGraphicsItemGroup {
|
||||||
{
|
|
||||||
public:
|
|
||||||
static ComponentWrapper *ofComponent(domain::ComponentInstance *instance);
|
|
||||||
static ComponentWrapper *ofBus(domain::BusInstance *instance);
|
|
||||||
static ComponentWrapper *ofWire(domain::WireInstance *wire);
|
|
||||||
|
|
||||||
ComponentWrapper() {
|
|
||||||
this->setHandlesChildEvents(false);
|
|
||||||
}
|
|
||||||
void redraw();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
domain::ComponentInstance *componentInstance = nullptr;
|
std::shared_ptr<domain::BusInstance> busInstance;
|
||||||
domain::BusInstance *busInstance = nullptr;
|
display::Bus *bus;
|
||||||
domain::WireInstance *wireInstance = nullptr;
|
|
||||||
|
|
||||||
ComponentItem *componentItem;
|
public:
|
||||||
std::vector<PinItem*> pinItems;
|
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
|
} // namespace display
|
||||||
|
|
||||||
#endif // DISPLAY_COMPONENT_H
|
#endif // DISPLAY_COMPONENT_H
|
||||||
|
|
|
@ -0,0 +1,182 @@
|
||||||
|
#include "attribute_dialog.h"
|
||||||
|
#include "mainwindow.h"
|
||||||
|
|
||||||
|
#include "application.h"
|
||||||
|
#include "error_dialog.h"
|
||||||
|
#include "warning_dialog.h"
|
||||||
|
#include "message_source.h"
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
namespace display {
|
||||||
|
|
||||||
|
long long int parseInt(std::string expression) {
|
||||||
|
try {
|
||||||
|
if (expression.size() > 2) {
|
||||||
|
if (expression.substr(0, 2) == "0x") {
|
||||||
|
return std::stoll(expression, nullptr, 16);
|
||||||
|
} else if (expression.substr(0, 2) == "0b") {
|
||||||
|
return std::stoll(expression, nullptr, 2);
|
||||||
|
} else {
|
||||||
|
return std::stoll(expression, nullptr, 10);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return std::stoll(expression, nullptr, 10);
|
||||||
|
}
|
||||||
|
} catch (std::exception &e) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AttributeDialog::AttributeDialog(std::string title, std::string action, domain::InstanceAttribute *attribute):
|
||||||
|
GenericDialog(title, action), attributeValue(attribute), value(attribute->value), popup(*attribute->attribute.getPopup()) {
|
||||||
|
|
||||||
|
auto *contentLayout = new QVBoxLayout();
|
||||||
|
content->setLayout(contentLayout);
|
||||||
|
|
||||||
|
contentLayout->addWidget(new QLabel(popup.getTitle().c_str()));
|
||||||
|
contentLayout->addWidget(new QLabel(popup.getText().c_str()));
|
||||||
|
|
||||||
|
auto type = attribute->value.getType();
|
||||||
|
|
||||||
|
if(popup.isEnumerated()) {
|
||||||
|
contentLayout->addWidget(setupEnumeration());
|
||||||
|
} else if(type == domain::Value::INT || type == domain::Value::STRING) {
|
||||||
|
contentLayout->addWidget(setupLineEdit(type));
|
||||||
|
} else if(type == domain::Value::BOOL) {
|
||||||
|
contentLayout->addWidget(setupBool());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AttributeDialog::onUpdate() {
|
||||||
|
auto validationErrors = validate();
|
||||||
|
if (validationErrors.empty()) {
|
||||||
|
attributeValue->value = value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<domain::ValidationError> errors, warnings;
|
||||||
|
for (auto &err: validationErrors) {
|
||||||
|
if (err.type == domain::Action::ERROR) {
|
||||||
|
errors.push_back(err);
|
||||||
|
} else {
|
||||||
|
warnings.push_back(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!errors.empty()) {
|
||||||
|
auto errorDialog = new ErrorDialog(errors);
|
||||||
|
errorDialog->exec();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool canAccept = true;
|
||||||
|
for (auto &warning: warnings) {
|
||||||
|
auto warningDialog = new WarningDialog(warning);
|
||||||
|
int response = warningDialog->exec();
|
||||||
|
if (response == QDialog::Rejected) {
|
||||||
|
canAccept = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(canAccept) {
|
||||||
|
attributeValue->value = value;
|
||||||
|
}
|
||||||
|
return canAccept;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AttributeDialog::onTextChanged(const QString &string) {
|
||||||
|
switch (value.getType()) {
|
||||||
|
case domain::Value::STRING:
|
||||||
|
value.setString(string.toStdString());
|
||||||
|
break;
|
||||||
|
case domain::Value::INT:
|
||||||
|
value = domain::Value::fromInt(parseInt(string.toStdString()));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("invalid value type in text change");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AttributeDialog::onEnumerationChanged(int index) {
|
||||||
|
value = attributeValue->attribute.getPopup()->getEnumeration()[index].getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
QComboBox *AttributeDialog::setupEnumeration() {
|
||||||
|
auto *combo = new QComboBox(this);
|
||||||
|
|
||||||
|
auto enumeration = popup.getEnumeration();
|
||||||
|
for (auto entry: enumeration) {
|
||||||
|
combo->addItem(QString::fromStdString(entry.getName()));
|
||||||
|
}
|
||||||
|
connect(combo, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
||||||
|
&AttributeDialog::onEnumerationChanged);
|
||||||
|
|
||||||
|
for (int i = 0; i < enumeration.size(); i++) {
|
||||||
|
if (attributeValue->value.equals(enumeration[i].getValue())) {
|
||||||
|
combo->setCurrentIndex(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return combo;
|
||||||
|
}
|
||||||
|
|
||||||
|
QLineEdit *AttributeDialog::setupLineEdit(domain::Value::ValueType type) {
|
||||||
|
auto edit = new QLineEdit(this);
|
||||||
|
connect(edit, &QLineEdit::textChanged, this, &AttributeDialog::onTextChanged);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case domain::Value::ValueType::INT:
|
||||||
|
edit->setValidator(new QIntValidator(-10000000, 10000000, edit));
|
||||||
|
edit->insert(std::to_string(value.asInt()).c_str());
|
||||||
|
break;
|
||||||
|
case domain::Value::ValueType::STRING:
|
||||||
|
edit->insert(value.asString().c_str());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return edit;
|
||||||
|
}
|
||||||
|
|
||||||
|
QGroupBox *AttributeDialog::setupBool() {
|
||||||
|
auto *group = new QGroupBox(this);
|
||||||
|
|
||||||
|
auto *radioLayout = new QHBoxLayout(group);
|
||||||
|
group->setLayout(radioLayout);
|
||||||
|
|
||||||
|
auto isTrue = new QRadioButton(QMESSAGE("msg_boolean_true"), group);
|
||||||
|
connect(isTrue, &QRadioButton::clicked, [this]() {
|
||||||
|
this->value = domain::Value::fromBool(true);
|
||||||
|
});
|
||||||
|
auto isFalse = new QRadioButton(QMESSAGE("msg_boolean_false"), group);
|
||||||
|
connect(isFalse, &QRadioButton::clicked, [this]() {
|
||||||
|
this->value = domain::Value::fromBool(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (value.asBool()) {
|
||||||
|
isTrue->setChecked(true);
|
||||||
|
} else {
|
||||||
|
isFalse->setChecked(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
radioLayout->addWidget(isTrue);
|
||||||
|
radioLayout->addWidget(isFalse);
|
||||||
|
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<domain::ValidationError> AttributeDialog::validate() {
|
||||||
|
domain::ComdelValidator validator(domain::getSupportedValidators());
|
||||||
|
|
||||||
|
auto currentValue = attributeValue->value;
|
||||||
|
attributeValue->value = value;
|
||||||
|
domain::ValidationContext context;
|
||||||
|
|
||||||
|
for (auto &addressSpace: Application::instance()->getLibrary()->getAddressSpaces()) {
|
||||||
|
context.addressSpaces.insert(std::make_pair(addressSpace.getName(), addressSpace));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto errors = validator.validateAttribute(attributeValue, context);
|
||||||
|
attributeValue->value = currentValue;
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
#ifndef ATTRIBUTE_DIALOG_H
|
||||||
|
#define ATTRIBUTE_DIALOG_H
|
||||||
|
|
||||||
|
#include <QIntValidator>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QComboBox>
|
||||||
|
#include <QGroupBox>
|
||||||
|
#include <QRadioButton>
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <utility>
|
||||||
|
#include "comdel/domain/instance_attribute.h"
|
||||||
|
|
||||||
|
#include "comdel/domain/value.h"
|
||||||
|
#include "comdel/domain/comdel_validator.h"
|
||||||
|
#include "generic_dialog.h"
|
||||||
|
|
||||||
|
namespace display {
|
||||||
|
|
||||||
|
class AttributeDialog : public GenericDialog {
|
||||||
|
public:
|
||||||
|
AttributeDialog(std::string title, std::string action, domain::InstanceAttribute *attribute);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void onTextChanged(const QString &string);
|
||||||
|
void onEnumerationChanged(int index);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool onUpdate() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QComboBox *setupEnumeration();
|
||||||
|
QLineEdit *setupLineEdit(domain::Value::ValueType type);
|
||||||
|
QGroupBox *setupBool();
|
||||||
|
|
||||||
|
std::vector<domain::ValidationError> validate();
|
||||||
|
|
||||||
|
domain::Value value;
|
||||||
|
domain::InstanceAttribute *attributeValue;
|
||||||
|
domain::Popup popup;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //ATTRIBUTE_DIALOG_H
|
|
@ -0,0 +1,34 @@
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QPlainTextEdit>
|
||||||
|
#include "error_dialog.h"
|
||||||
|
|
||||||
|
namespace display {
|
||||||
|
|
||||||
|
ErrorDialog::ErrorDialog(std::vector<domain::ValidationError> errors)
|
||||||
|
: GenericDialog("msg_dialog_error_title", std::nullopt, "msg_dialog_error_close") {
|
||||||
|
|
||||||
|
auto contentLayout = new QVBoxLayout();
|
||||||
|
content->setLayout(contentLayout);
|
||||||
|
|
||||||
|
for (auto &err: errors) {
|
||||||
|
contentLayout->addWidget(new QLabel(QString::fromStdString(err.message), this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorDialog::ErrorDialog(std::ostringstream& errorStream)
|
||||||
|
: GenericDialog("msg_dialog_error_title", std::nullopt, "msg_dialog_error_close") {
|
||||||
|
|
||||||
|
auto contentLayout = new QVBoxLayout();
|
||||||
|
content->setLayout(contentLayout);
|
||||||
|
|
||||||
|
setMinimumWidth(1000);
|
||||||
|
|
||||||
|
auto log = new QPlainTextEdit();
|
||||||
|
log->setFont(QFont("Courier"));
|
||||||
|
log->appendPlainText(QString::fromStdString(errorStream.str()));
|
||||||
|
log->setReadOnly(true);
|
||||||
|
contentLayout->addWidget(log);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // display
|
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef SCHEMEEDITOR_ERROR_DIALOG_H
|
||||||
|
#define SCHEMEEDITOR_ERROR_DIALOG_H
|
||||||
|
|
||||||
|
#include "generic_dialog.h"
|
||||||
|
#include "comdel/domain/comdel_validator.h"
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
|
||||||
|
namespace display {
|
||||||
|
|
||||||
|
class ErrorDialog : public GenericDialog {
|
||||||
|
public:
|
||||||
|
ErrorDialog(std::vector<domain::ValidationError> errors);
|
||||||
|
ErrorDialog(std::ostringstream& errorStream);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool onUpdate() override { return true; }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // display
|
||||||
|
|
||||||
|
#endif //SCHEMEEDITOR_ERROR_DIALOG_H
|
|
@ -0,0 +1,35 @@
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include "generic_dialog.h"
|
||||||
|
|
||||||
|
#include "message_source.h"
|
||||||
|
|
||||||
|
display::GenericDialog::GenericDialog(std::string title, std::optional<std::string> action, std::string cancel) {
|
||||||
|
setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
setWindowTitle(QMESSAGE(title));
|
||||||
|
|
||||||
|
setLayout(new QVBoxLayout());
|
||||||
|
content = new QWidget(this);
|
||||||
|
layout()->addWidget(content);
|
||||||
|
|
||||||
|
auto actionWidget = new QWidget(this);
|
||||||
|
auto actionBar = new QHBoxLayout(actionWidget);
|
||||||
|
layout()->addWidget(actionWidget);
|
||||||
|
|
||||||
|
// if action isn't defined only close button is offered
|
||||||
|
if(action.has_value()) {
|
||||||
|
okButton = new QPushButton(QMESSAGE(*action), this);
|
||||||
|
connect(okButton, &QPushButton::clicked, this, [this](){
|
||||||
|
if(this->onUpdate()) {
|
||||||
|
this->accept();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
actionBar->addWidget(okButton);
|
||||||
|
}
|
||||||
|
cancelButton = new QPushButton(QMESSAGE(cancel), this);
|
||||||
|
connect(cancelButton, &QPushButton::clicked, [this]() { reject(); });
|
||||||
|
actionBar->addWidget(cancelButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
void display::GenericDialog::setOkButtonDisabled(bool disabled) {
|
||||||
|
okButton->setDisabled(disabled);
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
#ifndef SCHEMEEDITOR_GENERIC_DIALOG_H
|
||||||
|
#define SCHEMEEDITOR_GENERIC_DIALOG_H
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QPushButton>
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
namespace display {
|
||||||
|
|
||||||
|
class GenericDialog: public QDialog {
|
||||||
|
public:
|
||||||
|
|
||||||
|
explicit GenericDialog(std::string title,
|
||||||
|
std::optional<std::string> action = "msg_dialog_actions_update",
|
||||||
|
std::string cancel = "msg_dialog_actions_cancel");
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void setOkButtonDisabled(bool disabled);
|
||||||
|
virtual bool onUpdate() = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QPushButton *okButton;
|
||||||
|
QPushButton *cancelButton;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QWidget *content;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //SCHEMEEDITOR_GENERIC_DIALOG_H
|
|
@ -0,0 +1,60 @@
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QLabel>
|
||||||
|
#include "memory_dialog.h"
|
||||||
|
#include "message_source.h"
|
||||||
|
|
||||||
|
namespace display {
|
||||||
|
|
||||||
|
|
||||||
|
MemoryDialog::MemoryDialog(std::string title, std::string action, domain::InstanceAttribute *attribute,
|
||||||
|
std::vector<std::shared_ptr<domain::ComponentInstance>> instances)
|
||||||
|
: GenericDialog(title, action), value(attribute->value), attributeValue(attribute), popup(*attribute->attribute.getPopup()) {
|
||||||
|
|
||||||
|
for (auto &instance: instances) {
|
||||||
|
if (instance->component.getType() == domain::Component::MEMORY) {
|
||||||
|
memoryInstances.push_back(instance->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto contentLayout = new QVBoxLayout(content);
|
||||||
|
content->setLayout(contentLayout);
|
||||||
|
|
||||||
|
contentLayout->addWidget(new QLabel(popup.getTitle().c_str()));
|
||||||
|
contentLayout->addWidget(new QLabel(popup.getText().c_str()));
|
||||||
|
|
||||||
|
contentLayout->addWidget(setupEnumeration());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MemoryDialog::onUpdate() {
|
||||||
|
attributeValue->value = value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QComboBox *MemoryDialog::setupEnumeration() {
|
||||||
|
auto *combo = new QComboBox(this);
|
||||||
|
|
||||||
|
for (const auto& entry: memoryInstances) {
|
||||||
|
combo->addItem(QString::fromStdString(entry));
|
||||||
|
}
|
||||||
|
combo->addItem(QMESSAGE("msg_dialog_memory_default"));
|
||||||
|
|
||||||
|
connect(combo, QOverload<int>::of(&QComboBox::currentIndexChanged), [this](int index) {
|
||||||
|
if(index == memoryInstances.size()) {
|
||||||
|
value = domain::Value::fromMemoryReference(std::nullopt);
|
||||||
|
} else {
|
||||||
|
value = domain::Value::fromMemoryReference(this->memoryInstances[index]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
combo->setCurrentIndex(memoryInstances.size());
|
||||||
|
for (int i = 0; i < memoryInstances.size(); i++) {
|
||||||
|
if (attributeValue->value.equals(domain::Value::fromMemoryReference(memoryInstances[i]))) {
|
||||||
|
combo->setCurrentIndex(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return combo;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // display
|
|
@ -0,0 +1,33 @@
|
||||||
|
#ifndef SCHEMEEDITOR_MEMORY_DIALOG_H
|
||||||
|
#define SCHEMEEDITOR_MEMORY_DIALOG_H
|
||||||
|
|
||||||
|
#include <QComboBox>
|
||||||
|
#include "generic_dialog.h"
|
||||||
|
#include "comdel/domain/instance_attribute.h"
|
||||||
|
#include "comdel/domain/instance.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace display {
|
||||||
|
|
||||||
|
class MemoryDialog : public GenericDialog {
|
||||||
|
public:
|
||||||
|
MemoryDialog(std::string title, std::string action, domain::InstanceAttribute *attribute,
|
||||||
|
std::vector<std::shared_ptr<domain::ComponentInstance>> instances);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool onUpdate() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QComboBox *setupEnumeration();
|
||||||
|
|
||||||
|
domain::Value value;
|
||||||
|
domain::InstanceAttribute *attributeValue;
|
||||||
|
std::vector<std::string> memoryInstances;
|
||||||
|
|
||||||
|
domain::Popup popup;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // display
|
||||||
|
|
||||||
|
#endif //SCHEMEEDITOR_MEMORY_DIALOG_H
|
|
@ -0,0 +1,40 @@
|
||||||
|
#include <set>
|
||||||
|
#include "name_dialog.h"
|
||||||
|
#include "message_source.h"
|
||||||
|
|
||||||
|
namespace display {
|
||||||
|
|
||||||
|
NameDialog::NameDialog(std::string currentName, std::set<std::string> &names)
|
||||||
|
: GenericDialog("msg_dialog_name_update"), currentName(currentName), usedNames(names) {
|
||||||
|
|
||||||
|
usedNames.erase(currentName);
|
||||||
|
|
||||||
|
auto *contentLayout = new QVBoxLayout();
|
||||||
|
contentLayout->addWidget(new QLabel(QMESSAGE("msg_dialog_name_update"), this));
|
||||||
|
|
||||||
|
edit = new QLineEdit(this);
|
||||||
|
edit->insert(currentName.c_str());
|
||||||
|
connect(edit, &QLineEdit::textChanged, this, &NameDialog::onNameUpdate);
|
||||||
|
contentLayout->addWidget(edit);
|
||||||
|
|
||||||
|
content->setLayout(contentLayout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NameDialog::onNameUpdate(const QString &text) {
|
||||||
|
if(usedNames.find(text.toStdString()) == usedNames.end()) {
|
||||||
|
setOkButtonDisabled(false);
|
||||||
|
} else {
|
||||||
|
setOkButtonDisabled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string NameDialog::getName() {
|
||||||
|
return currentName;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NameDialog::onUpdate() {
|
||||||
|
currentName = edit->text().toStdString();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
#ifndef NAME_DIALOG_H
|
||||||
|
#define NAME_DIALOG_H
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QPushButton>
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
#include "comdel/domain/instance.h"
|
||||||
|
#include "generic_dialog.h"
|
||||||
|
|
||||||
|
namespace display {
|
||||||
|
|
||||||
|
class NameDialog : public GenericDialog {
|
||||||
|
|
||||||
|
public:
|
||||||
|
NameDialog(std::string currentName, std::set<std::string>& names);
|
||||||
|
|
||||||
|
std::string getName();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool onUpdate() override;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void onNameUpdate(const QString& text);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::set<std::string> usedNames;
|
||||||
|
QLineEdit *edit = nullptr;
|
||||||
|
std::string currentName;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif //NAME_DIALOG_H
|
|
@ -0,0 +1,65 @@
|
||||||
|
#include "single_automatic_dialog.h"
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QComboBox>
|
||||||
|
#include <QPushButton>
|
||||||
|
|
||||||
|
namespace display {
|
||||||
|
|
||||||
|
SingleAutomaticDialog::SingleAutomaticDialog(std::string title, std::string action,
|
||||||
|
std::vector<domain::InstanceAttribute> &values)
|
||||||
|
: GenericDialog(title, action), attributes(values) {
|
||||||
|
firstValue = values[0].value;
|
||||||
|
secondValue = values[1].value;
|
||||||
|
|
||||||
|
auto *contentLayout = new QHBoxLayout();
|
||||||
|
auto *firstLayout = new QVBoxLayout();
|
||||||
|
auto *secondLayout = new QVBoxLayout();
|
||||||
|
|
||||||
|
content->setLayout(contentLayout);
|
||||||
|
contentLayout->addLayout(firstLayout);
|
||||||
|
contentLayout->addLayout(secondLayout);
|
||||||
|
|
||||||
|
setupValues(firstLayout, values[0], &SingleAutomaticDialog::onFirstEnumerationChanged);
|
||||||
|
setupValues(secondLayout, values[1], &SingleAutomaticDialog::onSecondEnumerationChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SingleAutomaticDialog::setupValues(QVBoxLayout *layout, domain::InstanceAttribute &attribute, void (display::SingleAutomaticDialog::* handler)(int)) {
|
||||||
|
|
||||||
|
auto popup = *attribute.attribute.getPopup();
|
||||||
|
|
||||||
|
layout->addWidget(new QLabel(popup.getTitle().c_str()));
|
||||||
|
layout->addWidget(new QLabel(popup.getText().c_str()));
|
||||||
|
|
||||||
|
auto *combo = new QComboBox(this);
|
||||||
|
auto enumeration = attribute.attribute.getPopup()->getEnumeration();
|
||||||
|
for (auto entry: enumeration) {
|
||||||
|
combo->addItem(QString::fromStdString(entry.getName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(combo, QOverload<int>::of(&QComboBox::currentIndexChanged), this,handler);
|
||||||
|
layout->addWidget(combo);
|
||||||
|
|
||||||
|
for (int i = 0; i < enumeration.size(); i++) {
|
||||||
|
if (attribute.value.equals(enumeration[i].getValue())) {
|
||||||
|
combo->setCurrentIndex(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SingleAutomaticDialog::onFirstEnumerationChanged(int index) {
|
||||||
|
firstValue = attributes[0].attribute.getPopup()->getEnumeration()[index].getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SingleAutomaticDialog::onSecondEnumerationChanged(int index) {
|
||||||
|
secondValue = attributes[1].attribute.getPopup()->getEnumeration()[index].getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SingleAutomaticDialog::onUpdate() {
|
||||||
|
attributes[0].value = firstValue;
|
||||||
|
attributes[1].value = secondValue;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // display
|
|
@ -0,0 +1,36 @@
|
||||||
|
#ifndef SCHEMEEDITOR_SINGLE_AUTOMATIC_DIALOG_H
|
||||||
|
#define SCHEMEEDITOR_SINGLE_AUTOMATIC_DIALOG_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include "comdel/domain/value.h"
|
||||||
|
#include "comdel/domain/instance_attribute.h"
|
||||||
|
#include "generic_dialog.h"
|
||||||
|
|
||||||
|
namespace display {
|
||||||
|
|
||||||
|
class SingleAutomaticDialog: public GenericDialog {
|
||||||
|
domain::Value firstValue;
|
||||||
|
domain::Value secondValue;
|
||||||
|
std::vector<domain::InstanceAttribute> &attributes;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit SingleAutomaticDialog(
|
||||||
|
std::string title,
|
||||||
|
std::string action,
|
||||||
|
std::vector<domain::InstanceAttribute>& values);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool onUpdate() override;
|
||||||
|
void setupValues(QVBoxLayout *layout, domain::InstanceAttribute &attribute, void (display::SingleAutomaticDialog::* handler)(int));
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
void onFirstEnumerationChanged(int index);
|
||||||
|
void onSecondEnumerationChanged(int index);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // display
|
||||||
|
|
||||||
|
#endif //SCHEMEEDITOR_SINGLE_AUTOMATIC_DIALOG_H
|
|
@ -0,0 +1,19 @@
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include "success_dialog.h"
|
||||||
|
#include "message_source.h"
|
||||||
|
|
||||||
|
namespace display {
|
||||||
|
|
||||||
|
SuccessDialog::SuccessDialog(std::string message) {
|
||||||
|
setLayout(new QVBoxLayout());
|
||||||
|
setWindowTitle(QMESSAGE("msg_dialog_success_title"));
|
||||||
|
layout()->addWidget(new QLabel(QString::fromStdString(message)));
|
||||||
|
|
||||||
|
auto button = new QPushButton(QMESSAGE("msg_dialog_actions_ok"));
|
||||||
|
connect(button, &QPushButton::clicked, [this]() {accept();});
|
||||||
|
layout()->addWidget(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // display
|
|
@ -0,0 +1,19 @@
|
||||||
|
//
|
||||||
|
// Created by bbr on 14.06.22..
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef SCHEMEEDITOR_SUCCESS_DIALOG_H
|
||||||
|
#define SCHEMEEDITOR_SUCCESS_DIALOG_H
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
|
||||||
|
namespace display {
|
||||||
|
|
||||||
|
class SuccessDialog: public QDialog {
|
||||||
|
public:
|
||||||
|
explicit SuccessDialog(std::string message);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // display
|
||||||
|
|
||||||
|
#endif //SCHEMEEDITOR_SUCCESS_DIALOG_H
|
|
@ -0,0 +1,16 @@
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QLabel>
|
||||||
|
#include "warning_dialog.h"
|
||||||
|
|
||||||
|
namespace display {
|
||||||
|
|
||||||
|
WarningDialog::WarningDialog(domain::ValidationError error)
|
||||||
|
: GenericDialog("msg_dialog_warning_title", "msg_dialog_actions_ok") {
|
||||||
|
|
||||||
|
auto contentLayout = new QVBoxLayout();
|
||||||
|
content->setLayout(contentLayout);
|
||||||
|
|
||||||
|
contentLayout->addWidget(new QLabel(QString::fromStdString(error.message), this));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // display
|
|
@ -0,0 +1,20 @@
|
||||||
|
#ifndef SCHEMEEDITOR_WARNING_DIALOG_H
|
||||||
|
#define SCHEMEEDITOR_WARNING_DIALOG_H
|
||||||
|
|
||||||
|
#include "generic_dialog.h"
|
||||||
|
#include "comdel/domain/comdel_validator.h"
|
||||||
|
|
||||||
|
namespace display {
|
||||||
|
|
||||||
|
class WarningDialog : public GenericDialog {
|
||||||
|
public:
|
||||||
|
WarningDialog(domain::ValidationError error);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool onUpdate() override { return true; };
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // display
|
||||||
|
|
||||||
|
#endif //SCHEMEEDITOR_WARNING_DIALOG_H
|
|
@ -1,21 +0,0 @@
|
||||||
//
|
|
||||||
// Created by bbr on 18. 04. 2022..
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "dialogmanager.h"
|
|
||||||
#include "attribute_dialog.h"
|
|
||||||
#include "name_dialog.h"
|
|
||||||
|
|
||||||
namespace display {
|
|
||||||
|
|
||||||
void DialogManager::updateAttribute(domain::InstanceAttribute *attribute) {
|
|
||||||
auto dialog = new AttributeDialog(attribute);
|
|
||||||
dialog->exec();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DialogManager::updateName(domain::ComponentInstance *instance) {
|
|
||||||
auto dialog = new NameDialog(instance);
|
|
||||||
dialog->exec();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
#ifndef DIALOG_MANAGER_H
|
|
||||||
#define DIALOG_MANAGER_H
|
|
||||||
|
|
||||||
#include <comdel/domain/instanceattribute.h>
|
|
||||||
#include <comdel/domain/instance.h>
|
|
||||||
|
|
||||||
namespace display {
|
|
||||||
|
|
||||||
class DialogManager {
|
|
||||||
public:
|
|
||||||
static void updateAttribute(domain::InstanceAttribute *attribute);
|
|
||||||
|
|
||||||
static void updateName(domain::ComponentInstance *instance);
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif //DIALOG_MANAGER_H
|
|
|
@ -1,30 +1,37 @@
|
||||||
#include "library_display.h"
|
#include "library_display.h"
|
||||||
|
#include "message_source.h"
|
||||||
|
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QListWidget>
|
#include <QListWidget>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
|
#include <application.h>
|
||||||
|
|
||||||
namespace display {
|
namespace display {
|
||||||
|
|
||||||
Library::Library()
|
Library::Library() {
|
||||||
{
|
|
||||||
auto layout = new QVBoxLayout();
|
auto layout = new QVBoxLayout();
|
||||||
this->setLayout(layout);
|
this->setLayout(layout);
|
||||||
|
|
||||||
componentList = new QListWidget();
|
componentList = new LibraryList(this);
|
||||||
busList = new QListWidget();
|
busList = new LibraryList(this);
|
||||||
|
|
||||||
layout->setMargin(4);
|
layout->setContentsMargins(4, 4, 4, 4);
|
||||||
layout->addWidget(new QLabel("Components:"));
|
|
||||||
|
componentsLabel = new QLabel(QMESSAGE("msg_sidebar_components"));
|
||||||
|
busLabel = new QLabel(QMESSAGE("msg_sidebar_busses"));
|
||||||
|
|
||||||
|
layout->addWidget(componentsLabel);
|
||||||
layout->addWidget(componentList, 1);
|
layout->addWidget(componentList, 1);
|
||||||
layout->addSpacing(8);
|
layout->addSpacing(8);
|
||||||
layout->addWidget(new QLabel("Buses:"));
|
layout->addWidget(busLabel);
|
||||||
layout->addWidget(busList, 1);
|
layout->addWidget(busList, 1);
|
||||||
|
|
||||||
setLibrary(library);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Library::setLibrary(std::optional<domain::Library> library) {
|
void Library::refreshContent() {
|
||||||
|
library = Application::instance()->getLibrary();
|
||||||
|
|
||||||
|
componentsLabel->setText(QMESSAGE("msg_sidebar_components"));
|
||||||
|
busLabel->setText(QMESSAGE("msg_sidebar_busses"));
|
||||||
|
|
||||||
componentList->clear();
|
componentList->clear();
|
||||||
busList->clear();
|
busList->clear();
|
||||||
|
@ -34,14 +41,15 @@ void Library::setLibrary(std::optional<domain::Library> library) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &component: library->getComponents()) {
|
for (auto &component: library->getComponents()) {
|
||||||
auto item = new QListWidgetItem{QString::fromStdString(component.getName())};
|
auto item = new LibraryListItem{component.getDisplayName(), "comdel/component", component.getName(),
|
||||||
|
componentList};
|
||||||
item->setToolTip(QString::fromStdString(component.getTooltip()));
|
item->setToolTip(QString::fromStdString(component.getTooltip()));
|
||||||
componentList->addItem(item);
|
componentList->addItem(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &bus: library->getBuses()) {
|
for (auto &bus: library->getBuses()) {
|
||||||
if (bus.getType() == domain::Bus::REGULAR) {
|
if (bus.getType() == domain::Bus::REGULAR) {
|
||||||
auto item = new QListWidgetItem{QString::fromStdString(bus.getName())};
|
auto item = new LibraryListItem{bus.getDisplayName(), "comdel/bus", bus.getName(), busList};
|
||||||
item->setToolTip(QString::fromStdString(bus.getTooltip()));
|
item->setToolTip(QString::fromStdString(bus.getTooltip()));
|
||||||
busList->addItem(item);
|
busList->addItem(item);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,22 +5,25 @@
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
#include <comdel/domain/library.h>
|
#include <comdel/domain/library.h>
|
||||||
|
#include <QLabel>
|
||||||
|
#include "library_list.h"
|
||||||
|
|
||||||
namespace display {
|
namespace display {
|
||||||
|
|
||||||
class Library: public QWidget
|
class Library : public QWidget {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
Library();
|
Library();
|
||||||
|
|
||||||
void setLibrary(std::optional<domain::Library> library);
|
void refreshContent();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::optional<domain::Library> library;
|
std::optional<domain::Library> library;
|
||||||
|
|
||||||
QListWidget *componentList;
|
LibraryList *componentList;
|
||||||
QListWidget *busList;
|
LibraryList *busList;
|
||||||
|
|
||||||
|
QLabel *componentsLabel;
|
||||||
|
QLabel *busLabel;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace display
|
} // namespace display
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -1,5 +0,0 @@
|
||||||
//
|
|
||||||
// Created by bbr on 18. 04. 2022..
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "name_dialog.h"
|
|
|
@ -1,23 +0,0 @@
|
||||||
//
|
|
||||||
// Created by bbr on 18. 04. 2022..
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef NAME_DIALOG_H
|
|
||||||
#define NAME_DIALOG_H
|
|
||||||
|
|
||||||
#include <QDialog>
|
|
||||||
#include <comdel/domain/instance.h>
|
|
||||||
|
|
||||||
namespace display {
|
|
||||||
|
|
||||||
class NameDialog: public QDialog {
|
|
||||||
public:
|
|
||||||
NameDialog(domain::ComponentInstance *instance) {
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif //sNAME_DIALOG_H
|
|
|
@ -1,40 +1,337 @@
|
||||||
#include "component_display.h"
|
#include "component_display.h"
|
||||||
#include "schema_display.h"
|
#include "schema_display.h"
|
||||||
|
#include "application.h"
|
||||||
|
#include "comdel/display/dialog/attribute_dialog.h"
|
||||||
|
#include "comdel/display/dialog/single_automatic_dialog.h"
|
||||||
|
#include "comdel/display/dialog/memory_dialog.h"
|
||||||
|
|
||||||
|
#include <QDrag>
|
||||||
|
#include <QDragEnterEvent>
|
||||||
|
#include <QMimeData>
|
||||||
|
#include "message_source.h"
|
||||||
|
|
||||||
|
|
||||||
namespace display {
|
namespace display {
|
||||||
|
|
||||||
Schema::Schema()
|
Schema::Schema() {
|
||||||
{
|
schema = nullptr;
|
||||||
|
library = std::nullopt;
|
||||||
|
setRenderHint(QPainter::Antialiasing);
|
||||||
|
setAlignment(Qt::AlignCenter);
|
||||||
this->setScene(&scene);
|
this->setScene(&scene);
|
||||||
|
this->setAcceptDrops(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Schema::setSchema(domain::Schema* schema)
|
void Schema::refreshContent() {
|
||||||
{
|
schema = Application::instance()->getSchema();
|
||||||
|
library = Application::instance()->getLibrary();
|
||||||
|
|
||||||
|
components.clear();
|
||||||
|
buses.clear();
|
||||||
scene.clear();
|
scene.clear();
|
||||||
this->schema = schema;
|
pins.clear();
|
||||||
|
busConnections.clear();
|
||||||
|
directConnections.clear();
|
||||||
|
|
||||||
if (schema != nullptr) {
|
if (schema != nullptr) {
|
||||||
for(auto &instance: schema->instances) {
|
for (auto &instance: schema->componentInstances) {
|
||||||
ComponentWrapper *group = nullptr;
|
auto group = new display::ComponentGroup(instance);
|
||||||
auto component = dynamic_cast<domain::ComponentInstance*>(instance);
|
for (auto pin: group->getPins()) {
|
||||||
if(component) {
|
display::Pin *p = pin;
|
||||||
group = ComponentWrapper::ofComponent(component);
|
domain::ConnectionComponent connection{instance->name, p->getPin().getName()};
|
||||||
|
pins.insert(std::make_pair(connection, p));
|
||||||
}
|
}
|
||||||
auto bus = dynamic_cast<domain::BusInstance*>(instance);
|
components.insert(std::make_pair(instance->name, group));
|
||||||
if(bus) {
|
scene.addItem(group);
|
||||||
group = ComponentWrapper::ofBus(bus);
|
|
||||||
}
|
}
|
||||||
if(group != nullptr) {
|
for (auto &instance: schema->busInstances) {
|
||||||
group->setPos(instance->position.first, instance->position.second);
|
if (instance->bus.getDisplayBus().has_value()) {
|
||||||
|
auto group = new display::BusGroup(instance);
|
||||||
|
buses.insert(std::make_pair(instance->name, group));
|
||||||
scene.addItem(group);
|
scene.addItem(group);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(auto &wire: schema->wires) {
|
for (auto &connection: schema->connections) {
|
||||||
auto group = ComponentWrapper::ofWire(wire);
|
auto busInstance = dynamic_cast<domain::BusConnectionInstance *>(connection.get());
|
||||||
group->setPos(wire->position.first, wire->position.second);
|
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);
|
scene.addItem(group);
|
||||||
|
for (auto pin: group->getPins()) {
|
||||||
|
display::Pin *p = pin;
|
||||||
|
domain::ConnectionComponent connection{instance->name, p->getPin().getName()};
|
||||||
|
pins.insert(std::make_pair(connection, p));
|
||||||
|
}
|
||||||
|
|
||||||
|
components[instance->name] = group;
|
||||||
|
|
||||||
|
event->acceptProposedAction();
|
||||||
|
}
|
||||||
|
if (event->mimeData()->hasFormat("comdel/bus")) {
|
||||||
|
auto bus = library->getBus(event->mimeData()->data("comdel/bus").toStdString());
|
||||||
|
|
||||||
|
auto currentPos = this->mapToScene(event->pos()).toPoint();
|
||||||
|
|
||||||
|
auto instance = Application::instance()->addBus(bus, currentPos.x(), currentPos.y());
|
||||||
|
|
||||||
|
auto group = new display::BusGroup(instance);
|
||||||
|
scene.addItem(group);
|
||||||
|
buses[instance->name] = group;
|
||||||
|
|
||||||
|
event->acceptProposedAction();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Schema::dragMoveEvent(QDragMoveEvent *event) {
|
||||||
|
event->acceptProposedAction();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Schema::removeConnectable(QPointF endPoint) {
|
||||||
|
auto instance = context.pin->getComponentInstance();
|
||||||
|
auto &pin = context.pin->getPin();
|
||||||
|
|
||||||
|
auto availableConnections = schema->availableConnections(instance->name, pin.getName(), true);
|
||||||
|
|
||||||
|
for(auto &connection: availableConnections) {
|
||||||
|
if(connection.type != domain::ConnectionEntry::BUS) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto bus = connection.busInstance.value();
|
||||||
|
if(buses[bus->name] == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto rect = buses[bus->name]->boundingRect();
|
||||||
|
rect = QRectF(buses[bus->name]->x(), buses[bus->name]->y(), rect.width(), rect.height());
|
||||||
|
|
||||||
|
if (rect.contains(endPoint)) {
|
||||||
|
auto con = library->getConnection({instance->component.getName(), pin.getName()}, bus->bus.getName());
|
||||||
|
if (con.has_value()) {
|
||||||
|
auto attributes = populateAttributes(con->getAttributes());
|
||||||
|
if(attributes.size() != con->getAttributes().size()) {
|
||||||
|
clearSelectable();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto conInstance = std::make_shared<domain::BusConnectionInstance>(instance, attributes, bus, *con);
|
||||||
|
schema->connections.push_back(conInstance);
|
||||||
|
|
||||||
|
if (conInstance != nullptr) {
|
||||||
|
auto c = new display::BusConnection(conInstance.get(), components[conInstance->instance->name],
|
||||||
|
buses[conInstance->bus->name]);
|
||||||
|
busConnections.push_back(c);
|
||||||
|
scene.addItem(c);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &connection: availableConnections) {
|
||||||
|
if(connection.type != domain::ConnectionEntry::COMPONENT) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto pinInstance = domain::ConnectionComponent{connection.componentInstance.value()->name, connection.pin.value().getName()};
|
||||||
|
auto pin = pins[pinInstance]->getPin().getDisplayPin();
|
||||||
|
auto position = pins[pinInstance]->getComponentInstance()->position;
|
||||||
|
|
||||||
|
auto rect = QRectF(position.first + pin.x, position.second + pin.y, pin.w, pin.h);
|
||||||
|
|
||||||
|
if (rect.contains(endPoint)) {
|
||||||
|
auto name = components[pinInstance.component]->getComponentInstance()->component.getName();
|
||||||
|
auto con = library->getConnection({instance->component.getName(), context.pin->getPin().getName()},
|
||||||
|
{name, pinInstance.pin});
|
||||||
|
if (con.has_value()) {
|
||||||
|
auto busInstance = Application::instance()->addBus(library->getBus(con->getBus()), 0, 0);
|
||||||
|
|
||||||
|
std::vector<domain::InstanceAttribute> attributes;
|
||||||
|
if(library->getBus(con->getBus()).getType() == domain::Bus::SINGLE_AUTOMATIC) {
|
||||||
|
attributes = populateSingleAutomaticConnection(*con);
|
||||||
|
} else {
|
||||||
|
attributes = populateAttributes(con->getAttributes());
|
||||||
|
}
|
||||||
|
if(attributes.size() != con->getAttributes().size()) {
|
||||||
|
clearSelectable();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<domain::DirectConnectionInstance> conInstance = nullptr;
|
||||||
|
if(con->getComponent() == domain::ConnectionComponent{instance->component.getName(), context.pin->getPin().getName()}) {
|
||||||
|
conInstance = std::make_shared<domain::DirectConnectionInstance>(instance,
|
||||||
|
components[pinInstance.component]->getComponentInstance().get(),
|
||||||
|
attributes, busInstance.get(),
|
||||||
|
*con);
|
||||||
|
} else {
|
||||||
|
conInstance = std::make_shared<domain::DirectConnectionInstance>(components[pinInstance.component]->getComponentInstance().get(),
|
||||||
|
instance,
|
||||||
|
attributes, busInstance.get(),
|
||||||
|
*con);
|
||||||
|
}
|
||||||
|
|
||||||
|
schema->connections.push_back(conInstance);
|
||||||
|
|
||||||
|
|
||||||
|
if (conInstance != nullptr) {
|
||||||
|
auto c = new display::DirectConnection(conInstance.get(),
|
||||||
|
components[conInstance->instance->name],
|
||||||
|
components[conInstance->secondInstance->name]);
|
||||||
|
directConnections.push_back(c);
|
||||||
|
scene.addItem(c);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clearSelectable();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Schema::showConnectable(Pin *domainPin) {
|
||||||
|
auto &pin = domainPin->getPin();
|
||||||
|
|
||||||
|
auto availableConnections = schema->availableConnections(domainPin->getComponentInstance()->name, pin.getName(), true);
|
||||||
|
|
||||||
|
for(auto &connection: availableConnections) {
|
||||||
|
if(connection.type != domain::ConnectionEntry::BUS) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto bus = connection.busInstance.value();
|
||||||
|
auto &group = buses[bus->name];
|
||||||
|
if(group == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto rect = new QGraphicsRectItem(group->boundingRect());
|
||||||
|
rect->setBrush(selectedBrush);
|
||||||
|
rect->setPos(group->scenePos());
|
||||||
|
|
||||||
|
auto _rect = rect->rect();
|
||||||
|
_rect.setWidth(_rect.width() + 1);
|
||||||
|
_rect.setHeight(_rect.height() + 1);
|
||||||
|
rect->setRect(_rect);
|
||||||
|
|
||||||
|
context.selectable.push_back(rect);
|
||||||
|
scene.addItem(rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &connection: availableConnections) {
|
||||||
|
if(connection.type != domain::ConnectionEntry::COMPONENT) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto pinInstance = domain::ConnectionComponent{connection.componentInstance.value()->name, connection.pin.value().getName()};
|
||||||
|
auto &instance = pins[pinInstance];
|
||||||
|
auto rect = new QGraphicsRectItem(instance->boundingRect());
|
||||||
|
rect->setBrush(selectedBrush);
|
||||||
|
rect->setPen(selectedPen);
|
||||||
|
rect->setPos(instance->scenePos());
|
||||||
|
|
||||||
|
auto _rect = rect->rect();
|
||||||
|
_rect.setWidth(_rect.width() + 1);
|
||||||
|
_rect.setHeight(_rect.height() + 1);
|
||||||
|
rect->setRect(_rect);
|
||||||
|
|
||||||
|
context.selectable.push_back(rect);
|
||||||
|
scene.addItem(rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<domain::InstanceAttribute> Schema::populateAttributes(std::vector<domain::Attribute>& attributes) {
|
||||||
|
std::vector<domain::InstanceAttribute> instanceAttributes;
|
||||||
|
|
||||||
|
for (auto attr: attributes) {
|
||||||
|
domain::InstanceAttribute attribute(attr.getName(), attr.getDefault(), attr);
|
||||||
|
if(attr.getPopup().has_value() && attr.getPopup()->getType() == domain::Popup::AUTOMATIC) {
|
||||||
|
if(attr.getDefault().isType(domain::Value::MEMORY_REFERENCE)) {
|
||||||
|
auto dialog = new MemoryDialog("msg_dialog_memory_set", "msg_dialog_actions_set", &attribute, schema->componentInstances);
|
||||||
|
if(dialog->exec() == QDialog::Rejected) {
|
||||||
|
// if any dialog isn't set, whole creation is rejected
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
std::map<std::string, std::string> params = {{"attribute", attribute.attribute.getDisplayName()}};
|
||||||
|
auto dialog = new AttributeDialog(MESSAGE_PARAM("msg_dialog_attribute_set", params), "msg_dialog_actions_set", &attribute);
|
||||||
|
if(dialog->exec() == QDialog::Rejected) {
|
||||||
|
// if any dialog isn't set, whole creation is rejected
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
instanceAttributes.push_back(attribute);
|
||||||
|
}
|
||||||
|
return instanceAttributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<domain::InstanceAttribute> Schema::populateSingleAutomaticConnection(domain::Connection connection) {
|
||||||
|
std::vector<domain::InstanceAttribute> instanceAttributes;
|
||||||
|
|
||||||
|
for (auto attr: connection.getAttributes()) {
|
||||||
|
instanceAttributes.emplace_back(attr.getName(), attr.getDefault(), attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto dialog = new display::SingleAutomaticDialog("msg_dialog_sa_pin_set", "msg_dialog_actions_set", instanceAttributes);
|
||||||
|
if(dialog->exec() == QDialog::Rejected) {
|
||||||
|
// if dialog is rejected, whole creation is rejected
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return instanceAttributes;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Schema::clearSelectable() {
|
||||||
|
updateConnections();
|
||||||
|
|
||||||
|
for (auto &item: this->context.selectable) {
|
||||||
|
this->scene.removeItem(item);
|
||||||
|
delete item;
|
||||||
|
}
|
||||||
|
this->context.selectable.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace display
|
} // namespace display
|
||||||
|
|
|
@ -4,23 +4,77 @@
|
||||||
|
|
||||||
#include <QGraphicsView>
|
#include <QGraphicsView>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
#include <QColor>
|
||||||
|
#include <QGraphicsLineItem>
|
||||||
|
|
||||||
#include <comdel/domain/schema.h>
|
#include <comdel/domain/schema.h>
|
||||||
|
#include <comdel/domain/library.h>
|
||||||
|
#include "component_display.h"
|
||||||
|
|
||||||
namespace display {
|
namespace display {
|
||||||
|
|
||||||
class Schema: public QGraphicsView
|
class BusConnection;
|
||||||
{
|
|
||||||
|
class Schema : public QGraphicsView {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
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();
|
Schema();
|
||||||
|
|
||||||
void setSchema(domain::Schema* 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:
|
private:
|
||||||
QGraphicsScene scene;
|
QGraphicsScene scene;
|
||||||
|
|
||||||
domain::Schema* schema;
|
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
|
} // namespace display
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -1,27 +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;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AddressSpace::contains(long long int address) {
|
|
||||||
return address >= start && address < end;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AddressSpace::contains(long long int pstart, long long int pend) {
|
|
||||||
return pstart >= start && pend < end;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace domain
|
|
|
@ -1,27 +0,0 @@
|
||||||
#ifndef DOMAIN_ADDRESS_SPACE_H
|
|
||||||
#define DOMAIN_ADDRESS_SPACE_H
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace domain {
|
|
||||||
|
|
||||||
class AddressSpace
|
|
||||||
{
|
|
||||||
std::string name;
|
|
||||||
long long start;
|
|
||||||
long long end;
|
|
||||||
|
|
||||||
public:
|
|
||||||
AddressSpace(std::string name, long long start, long long end);
|
|
||||||
|
|
||||||
std::string getName();
|
|
||||||
long long getStart();
|
|
||||||
long long getEnd();
|
|
||||||
|
|
||||||
bool contains(long long int address);
|
|
||||||
bool contains(long long int start, long long int end);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace domain
|
|
||||||
|
|
||||||
#endif // DOMAIN_ADDRESS_SPACE_H
|
|
|
@ -3,30 +3,34 @@
|
||||||
namespace domain {
|
namespace domain {
|
||||||
|
|
||||||
Enumeration::Enumeration(std::string name, Value value)
|
Enumeration::Enumeration(std::string name, Value value)
|
||||||
: name(name), value(value)
|
: name(name), value(value) {}
|
||||||
{}
|
|
||||||
|
|
||||||
std::string Enumeration::getName() {
|
std::string &Enumeration::getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value Enumeration::getValue() {
|
Value Enumeration::getValue() {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Popup::Popup(std::string title, std::string text, PopupType type, std::vector<Rule> rules, std::vector<Enumeration> enumeration)
|
Popup::Popup(std::string title, std::string text, PopupType type, std::vector<Rule> rules,
|
||||||
: title(title), text(text), type(type), rules(rules), enumerated(enumeration.size() > 0), enumeration(enumeration)
|
std::vector<Enumeration> enumeration)
|
||||||
{}
|
: title(title), text(text), type(type), rules(rules), enumerated(enumeration.size() > 0),
|
||||||
|
enumeration(enumeration) {}
|
||||||
|
|
||||||
std::string Popup::getTitle() {
|
std::string Popup::getTitle() {
|
||||||
return title;
|
return title;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Popup::getText() {
|
std::string Popup::getText() {
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
Popup::PopupType Popup::getType() {
|
Popup::PopupType Popup::getType() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Rule> Popup::getRules() {
|
std::vector<Rule> Popup::getRules() {
|
||||||
return rules;
|
return rules;
|
||||||
}
|
}
|
||||||
|
@ -34,23 +38,36 @@ std::vector<Rule> Popup::getRules() {
|
||||||
bool Popup::isEnumerated() {
|
bool Popup::isEnumerated() {
|
||||||
return enumerated;
|
return enumerated;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Enumeration> &Popup::getEnumeration() {
|
std::vector<Enumeration> &Popup::getEnumeration() {
|
||||||
return enumeration;
|
return enumeration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Attribute::Attribute(std::string name, Value defaultValue, std::optional<Popup> popup)
|
Attribute::Attribute(std::string name, std::optional<std::string> displayName, Value defaultValue, std::optional<Popup> popup)
|
||||||
: name(name), defaultValue(defaultValue), popup(popup)
|
: name(name), displayName(displayName), defaultValue(defaultValue), popup(popup) {}
|
||||||
{}
|
|
||||||
|
std::string Attribute::getDisplayName() {
|
||||||
|
if(displayName.has_value()) {
|
||||||
|
return *displayName;
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
std::string Attribute::getName() {
|
std::string Attribute::getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value Attribute::getDefault() {
|
Value Attribute::getDefault() {
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<Popup> Attribute::getPopup() {
|
std::optional<Popup> Attribute::getPopup() {
|
||||||
return popup;
|
return popup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Attribute::setPupup(std::optional<Popup> popup) {
|
||||||
|
this->popup = popup;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace domain
|
} // namespace domain
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef DOMAIN_ATTRIBUTE_H
|
#ifndef DOMAIN_ATTRIBUTE_H
|
||||||
#define DOMAIN_ATTRIBUTE_H
|
#define DOMAIN_ATTRIBUTE_H
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "rule.h"
|
#include "rule.h"
|
||||||
|
@ -14,7 +15,8 @@ class Enumeration {
|
||||||
public:
|
public:
|
||||||
Enumeration(std::string name, Value value);
|
Enumeration(std::string name, Value value);
|
||||||
|
|
||||||
std::string getName();
|
std::string &getName();
|
||||||
|
|
||||||
Value getValue();
|
Value getValue();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -35,29 +37,44 @@ private:
|
||||||
std::vector<Rule> rules;
|
std::vector<Rule> rules;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Popup(std::string title, std::string text, PopupType type, std::vector<Rule> rules, std::vector<Enumeration> enumeration);
|
Popup(std::string title, std::string text, PopupType type, std::vector<Rule> rules,
|
||||||
|
std::vector<Enumeration> enumeration);
|
||||||
|
|
||||||
std::string getTitle();
|
std::string getTitle();
|
||||||
|
|
||||||
std::string getText();
|
std::string getText();
|
||||||
|
|
||||||
PopupType getType();
|
PopupType getType();
|
||||||
|
|
||||||
std::vector<Rule> getRules();
|
std::vector<Rule> getRules();
|
||||||
|
|
||||||
bool isEnumerated();
|
bool isEnumerated();
|
||||||
|
|
||||||
std::vector<Enumeration> &getEnumeration();
|
std::vector<Enumeration> &getEnumeration();
|
||||||
|
|
||||||
|
void setEnumeration(std::vector<Enumeration> enums) {
|
||||||
|
enumerated = true;
|
||||||
|
enumeration = enums;
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Attribute
|
class Attribute {
|
||||||
{
|
|
||||||
std::string name;
|
std::string name;
|
||||||
|
std::optional<std::string> displayName;
|
||||||
Value defaultValue;
|
Value defaultValue;
|
||||||
std::optional<Popup> popup;
|
std::optional<Popup> popup;
|
||||||
public:
|
public:
|
||||||
Attribute(std::string name, Value defaultValue, std::optional<Popup> popup = std::nullopt);
|
Attribute(std::string name, std::optional<std::string> displayName, Value defaultValue, std::optional<Popup> popup = std::nullopt);
|
||||||
|
|
||||||
std::string getName();
|
std::string getName();
|
||||||
|
|
||||||
|
std::string getDisplayName();
|
||||||
|
|
||||||
Value getDefault();
|
Value getDefault();
|
||||||
|
|
||||||
std::optional<Popup> getPopup();
|
std::optional<Popup> getPopup();
|
||||||
|
void setPupup(std::optional<Popup> popup);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace domain
|
} // namespace domain
|
||||||
|
|
|
@ -2,53 +2,72 @@
|
||||||
|
|
||||||
namespace domain {
|
namespace domain {
|
||||||
|
|
||||||
Wire::Wire(std::string name, WireType type, int width, bool hidden, bool hasTermination, long long ifUnterminated)
|
Wire::Wire(std::string name, WireType type, int width, bool hidden, bool hasTerminate, Value terminateWith)
|
||||||
: name(name), type(type), width(width), hidden(hidden), hasTermination(hasTermination), ifUnterminated(ifUnterminated)
|
: name(name), type(type), width(width), hidden(hidden), hasTerminate(hasTerminate),
|
||||||
{}
|
terminateWith(terminateWith) {}
|
||||||
|
|
||||||
std::string Wire::getName() {
|
std::string Wire::getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Bus::getInstanceName() {
|
||||||
|
return instanceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int Wire::getWidth() {
|
int Wire::getWidth() {
|
||||||
return width;
|
return width;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Wire::isHidden() {
|
bool Wire::isHidden() {
|
||||||
return hidden;
|
return hidden;
|
||||||
}
|
}
|
||||||
bool Wire::getHasTermination() {
|
|
||||||
return hasTermination;
|
bool Wire::hasTerminateWith() {
|
||||||
|
return hasTerminate;
|
||||||
}
|
}
|
||||||
long long Wire::getIfUnterminated() {
|
|
||||||
return ifUnterminated;
|
Value Wire::getTerminateWith() {
|
||||||
|
return terminateWith;
|
||||||
}
|
}
|
||||||
|
|
||||||
Wire::WireType Wire::getType() {
|
Wire::WireType Wire::getType() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Bus::Bus(std::string name, std::optional<std::string> displayName, std::string instanceName, std::string tooltip, BusType type, std::pair<int, int> count, std::vector<Wire> wires,
|
||||||
|
std::optional<ui::Bus> displayBus)
|
||||||
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), displayName(displayName), instanceName(instanceName), tooltip(tooltip), type(type), count(count), wires(wires), displayBus(displayBus) {}
|
||||||
: name(name), tooltip(tooltip), type(type), count(count), wires(wires), display(display)
|
|
||||||
{}
|
|
||||||
|
|
||||||
std::string Bus::getName() {
|
std::string Bus::getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Bus::getDisplayName() {
|
||||||
|
if(displayName.has_value()) {
|
||||||
|
return *displayName;
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
std::string Bus::getTooltip() {
|
std::string Bus::getTooltip() {
|
||||||
return tooltip;
|
return tooltip;
|
||||||
}
|
}
|
||||||
|
|
||||||
Bus::BusType Bus::getType() {
|
Bus::BusType Bus::getType() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<int, int> Bus::getCount() {
|
std::pair<int, int> Bus::getCount() {
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
std::optional<Display> Bus::getDisplay() {
|
|
||||||
return display;
|
|
||||||
}
|
|
||||||
std::vector<Wire> Bus::getWires() {
|
std::vector<Wire> Bus::getWires() {
|
||||||
return wires;
|
return wires;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<ui::Bus> Bus::getDisplayBus() {
|
||||||
|
return displayBus;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace domain
|
} // namespace domain
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define DOMAIN_BUS_H
|
#define DOMAIN_BUS_H
|
||||||
|
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
|
#include "value.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
@ -10,8 +11,7 @@
|
||||||
|
|
||||||
namespace domain {
|
namespace domain {
|
||||||
|
|
||||||
class Wire
|
class Wire {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
enum WireType {
|
enum WireType {
|
||||||
WIRE_DEFAULT,
|
WIRE_DEFAULT,
|
||||||
|
@ -25,47 +25,63 @@ private:
|
||||||
std::string name;
|
std::string name;
|
||||||
WireType type;
|
WireType type;
|
||||||
int width;
|
int width;
|
||||||
bool hidden;
|
bool hidden = false;
|
||||||
bool hasTermination;
|
bool hasTerminate = false;
|
||||||
long long ifUnterminated;
|
Value terminateWith;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Wire(std::string name, WireType type, int width, bool hidden, bool hasTermination, long long ifUnterminated);
|
Wire(std::string name, WireType type, int width, bool hidden, bool hasTerminate, Value terminateWith);
|
||||||
|
|
||||||
std::string getName();
|
std::string getName();
|
||||||
|
|
||||||
int getWidth();
|
int getWidth();
|
||||||
|
|
||||||
bool isHidden();
|
bool isHidden();
|
||||||
bool getHasTermination();
|
|
||||||
long long getIfUnterminated();
|
bool hasTerminateWith();
|
||||||
|
|
||||||
|
Value getTerminateWith();
|
||||||
|
|
||||||
WireType getType();
|
WireType getType();
|
||||||
};
|
};
|
||||||
|
|
||||||
class Bus
|
class Bus {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
enum BusType {
|
enum BusType {
|
||||||
AUTOMATIC,
|
AUTOMATIC,
|
||||||
REGULAR,
|
REGULAR,
|
||||||
AUTOMATIC_SINGLE
|
SINGLE_AUTOMATIC
|
||||||
};
|
};
|
||||||
private:
|
private:
|
||||||
std::string name;
|
std::string name;
|
||||||
|
std::optional<std::string> displayName;
|
||||||
|
std::string instanceName;
|
||||||
std::string tooltip;
|
std::string tooltip;
|
||||||
BusType type;
|
BusType type;
|
||||||
|
|
||||||
std::pair<int, int> count;
|
std::pair<int, int> count;
|
||||||
std::optional<Display> display;
|
std::optional<ui::Bus> displayBus;
|
||||||
std::vector<Wire> wires;
|
std::vector<Wire> wires;
|
||||||
|
|
||||||
public:
|
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);
|
Bus(std::string name, std::optional<std::string> displayName, std::string instanceName, std::string tooltip, BusType type, std::pair<int, int> count, std::vector<Wire> wires,
|
||||||
|
std::optional<ui::Bus> display = std::nullopt);
|
||||||
|
|
||||||
std::string getName();
|
std::string getName();
|
||||||
|
|
||||||
|
std::string getDisplayName();
|
||||||
|
|
||||||
|
std::string getInstanceName();
|
||||||
|
|
||||||
std::string getTooltip();
|
std::string getTooltip();
|
||||||
|
|
||||||
BusType getType();
|
BusType getType();
|
||||||
|
|
||||||
std::pair<int, int> getCount();
|
std::pair<int, int> getCount();
|
||||||
|
|
||||||
std::vector<Wire> getWires();
|
std::vector<Wire> getWires();
|
||||||
std::optional<Display> getDisplay();
|
|
||||||
|
std::optional<ui::Bus> getDisplayBus();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace domain
|
} // namespace domain
|
||||||
|
|
|
@ -0,0 +1,417 @@
|
||||||
|
//
|
||||||
|
// Created by bbr on 08.05.22..
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
#include <QLayout>
|
||||||
|
#include "comdel_generator.h"
|
||||||
|
|
||||||
|
namespace domain {
|
||||||
|
|
||||||
|
void generate_schema(std::string &librarySource, Schema *schema, std::ostream &buffer) {
|
||||||
|
buffer << "@source \"" << librarySource << "\"" << std::endl << std::endl;
|
||||||
|
|
||||||
|
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) {
|
||||||
|
|
||||||
|
auto x1 = connection->start.first;
|
||||||
|
auto y1 = connection->start.second;
|
||||||
|
auto x2 = connection->end.first;
|
||||||
|
auto y2 = connection->end.second;
|
||||||
|
|
||||||
|
buffer << "\t\tpath {\n";
|
||||||
|
buffer << "\t\t\tx:0; y:0;\n";
|
||||||
|
buffer << "\t\t\tpoints: (";
|
||||||
|
buffer << "(" << x1 << ", " << y1 << "),";
|
||||||
|
buffer << "(" << (x2 - x1) << "," << (y2 - y1) << "));\n";
|
||||||
|
buffer << "\t\t}" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void generateBus(BusInstance *bus, ostream &buffer) {
|
||||||
|
buffer << "\n";
|
||||||
|
buffer << "\t\t// " << bus->name << " bus\n\n";
|
||||||
|
|
||||||
|
if (bus->bus.getDisplayBus().has_value()) {
|
||||||
|
bus->bus.getDisplayBus()->comdel(buffer, bus->position.first, bus->position.second, bus->size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void generateWire(std::string &name, Wire &wire, ostream &buffer);
|
||||||
|
|
||||||
|
std::map<string, string> generateWires(Schema *schema, ostream &buffer) {
|
||||||
|
std::set<string> usedNames;
|
||||||
|
std::map<string, string> usedMappings;
|
||||||
|
for (auto &bus: schema->busInstances) {
|
||||||
|
buffer << "\t//" << bus->name << std::endl;
|
||||||
|
for (auto &wire: bus->bus.getWires()) {
|
||||||
|
auto name = wire.getName();
|
||||||
|
if (usedNames.count(name) > 0) {
|
||||||
|
name = bus->name + "__" + wire.getName();
|
||||||
|
}
|
||||||
|
usedNames.insert(name);
|
||||||
|
usedMappings.insert(std::make_pair(bus->name + "." + wire.getName(), name));
|
||||||
|
|
||||||
|
generateWire(name, wire, buffer);
|
||||||
|
}
|
||||||
|
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 << " " << (wire.isHidden() ? "--" : "") << name;
|
||||||
|
if(wire.hasTerminateWith()) {
|
||||||
|
buffer << " = " << wire.getTerminateWith().asInt();
|
||||||
|
}
|
||||||
|
buffer << ";" << 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 generateSingleAutomaticPin(std::vector<ConnectionInstance*> connections, ComponentInstance *instance, string pin,
|
||||||
|
map<string, string> &wireNames, stringstream &buffer);
|
||||||
|
|
||||||
|
void generateComponent(Schema *schema, map<string, string> &wires, ostream &buffer,
|
||||||
|
shared_ptr<ComponentInstance> &component);
|
||||||
|
|
||||||
|
void 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 connections = schema->getConnections(component->name, pin.getName());
|
||||||
|
if(connections.size() == 1) {
|
||||||
|
auto conn = connections[0];
|
||||||
|
auto busConn = dynamic_cast<BusConnectionInstance *>(conn);
|
||||||
|
if (busConn != nullptr) {
|
||||||
|
for (auto wire: busConn->connection.getWires()) {
|
||||||
|
if (wire.isType(Value::ATTRIBUTE_REFERENCE)) {
|
||||||
|
auto attribute = busConn->getAttribute(wire.asReference());
|
||||||
|
if (wire.isType(Value::WIRE_REFERENCE)) {
|
||||||
|
tempOutput << wires[busConn->bus->name + "." + attribute.value.asReference()] << ", ";
|
||||||
|
} else if (wire.isType(Value::NIL)) {
|
||||||
|
tempOutput << "*, ";
|
||||||
|
} else {
|
||||||
|
tempOutput << attribute.value.stringify() << ", ";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (wire.isType(Value::WIRE_REFERENCE)) {
|
||||||
|
tempOutput << wires[busConn->bus->name + "." + wire.asReference()] << ", ";
|
||||||
|
} else if (wire.isType(Value::NIL)) {
|
||||||
|
tempOutput << "*, ";
|
||||||
|
} else {
|
||||||
|
tempOutput << wire.stringify() << ", ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto dirConn = dynamic_cast<DirectConnectionInstance *>(conn);
|
||||||
|
if (dirConn != nullptr) {
|
||||||
|
if (dirConn->bus->bus.getType() == Bus::AUTOMATIC) {
|
||||||
|
generateAutomaticPin(dirConn, component->name, pin.getName(), wires, tempOutput);
|
||||||
|
} else {
|
||||||
|
generateSingleAutomaticPin(dirConn, component->name, pin.getName(), wires, tempOutput);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
generateSingleAutomaticPin(connections, component.get(), pin.getName(), wires, tempOutput);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// if no connection exists than defaults must exist
|
||||||
|
for (auto &wire: *pin.getWires()) {
|
||||||
|
if(wire.isType(Value::NIL)) {
|
||||||
|
tempOutput << "*, ";
|
||||||
|
} else {
|
||||||
|
tempOutput << wire.stringify() << ", ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto wireList = tempOutput.str();
|
||||||
|
wireList.pop_back();
|
||||||
|
wireList.pop_back(); // remove last COMMA(", ")
|
||||||
|
|
||||||
|
buffer << "(" << wireList << ")";
|
||||||
|
|
||||||
|
if (memory.has_value()) {
|
||||||
|
buffer << " uses " << *memory->value.asMemoryReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer << ";" << std::endl;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void generateSingleAutomaticPin(DirectConnectionInstance *connection, string name, string pin,
|
||||||
|
map<string, string> &wireNames, stringstream &buffer) {
|
||||||
|
std::vector<Value> wires;
|
||||||
|
std::string selected;
|
||||||
|
std::vector<Value> defaults;
|
||||||
|
if (connection->instance->name == name && connection->connection.getComponent().pin == pin) {
|
||||||
|
wires = connection->connection.getWires();
|
||||||
|
selected = connection->attributes[0].value.asString();
|
||||||
|
defaults = *connection->instance->component.getPin(pin).getWires();
|
||||||
|
} else {
|
||||||
|
wires = *connection->connection.getSecondWires();
|
||||||
|
selected = connection->attributes[1].value.asString();
|
||||||
|
defaults = *connection->secondInstance->component.getPin(pin).getWires();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < wires.size(); i++) {
|
||||||
|
if (wires[i].isType(Value::STRING)) {
|
||||||
|
if (wires[i].asString() == selected) {
|
||||||
|
auto wireName = connection->bus->name + "." + connection->bus->bus.getWires()[0].getName();
|
||||||
|
buffer << wireNames[wireName] << ", ";
|
||||||
|
} else if(defaults[i].isType(Value::NIL)) {
|
||||||
|
buffer << "*, ";
|
||||||
|
} else {
|
||||||
|
buffer << defaults[i].stringify() << ", ";
|
||||||
|
}
|
||||||
|
} else if(defaults[i].isType(Value::NIL)) {
|
||||||
|
buffer << "*, ";
|
||||||
|
} else {
|
||||||
|
buffer << wires[i].stringify() << ", ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void generateSingleAutomaticPin(std::vector<ConnectionInstance*> connections, ComponentInstance *instance, string pin,
|
||||||
|
map<string, string> &wireNames, stringstream &buffer) {
|
||||||
|
std::map<int, BusInstance*> selectedValues;
|
||||||
|
for(auto conn: connections) {
|
||||||
|
auto dirConn = dynamic_cast<DirectConnectionInstance*>(conn);
|
||||||
|
auto index = dirConn->getSelected(ConnectionComponent{instance->name, pin});
|
||||||
|
selectedValues.insert(std::make_pair(index, dirConn->bus));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Value> defaultWires = instance->component.getPin(pin).getWires().value();
|
||||||
|
|
||||||
|
for (int i=0; i<defaultWires.size(); i++) {
|
||||||
|
if(selectedValues.count(i) > 0) {
|
||||||
|
auto wireName = selectedValues[i]->name + "." + selectedValues[i]->bus.getWires()[0].getName();
|
||||||
|
buffer << wireNames[wireName] << ", ";
|
||||||
|
} else if(defaultWires[i].isType(Value::NIL)) {
|
||||||
|
buffer << "*, ";
|
||||||
|
} else {
|
||||||
|
buffer << defaultWires[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
|
|
@ -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
|
|
@ -0,0 +1,240 @@
|
||||||
|
#include <set>
|
||||||
|
#include "comdel_validator.h"
|
||||||
|
#include "library.h"
|
||||||
|
#include "message_source.h"
|
||||||
|
|
||||||
|
namespace domain {
|
||||||
|
|
||||||
|
std::vector<ValidationError> ComdelValidator::validateSchema(Schema &schema, ValidationContext context) {
|
||||||
|
std::vector<ValidationError> errors;
|
||||||
|
|
||||||
|
context.instance = nullptr;
|
||||||
|
context.attribute = nullptr;
|
||||||
|
|
||||||
|
for (auto &instance: schema.componentInstances) {
|
||||||
|
auto result = validateComponent(instance.get(), context);
|
||||||
|
errors.insert(errors.end(), result.begin(), result.end());
|
||||||
|
}
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ValidationError>
|
||||||
|
ComdelValidator::validateInstanceCount(Schema &schema, Library &library, ValidationContext context) {
|
||||||
|
std::vector<ValidationError> errors;
|
||||||
|
|
||||||
|
// validate instance count
|
||||||
|
std::map<std::string, int> instanceMap;
|
||||||
|
for (auto &inst: schema.componentInstances) {
|
||||||
|
instanceMap[inst->component.getName()]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto comp: library.getComponents()) {
|
||||||
|
int count = instanceMap[comp.getName()];
|
||||||
|
|
||||||
|
context.attributes["componentName"] = Value::fromString(comp.getDisplayName());
|
||||||
|
context.attributes["min"] = Value::fromInt(comp.getCount().first);
|
||||||
|
context.attributes["max"] = Value::fromInt(comp.getCount().second);
|
||||||
|
context.attributes["count"] = Value::fromInt(count);
|
||||||
|
|
||||||
|
if (count < comp.getCount().first) {
|
||||||
|
auto message = MESSAGE_PARAM("msg_validators_component_min_count", context.map());
|
||||||
|
errors.emplace_back(Action::ERROR, message);
|
||||||
|
} else if (count > comp.getCount().second) {
|
||||||
|
auto message = MESSAGE_PARAM("msg_validators_component_max_count", context.map());
|
||||||
|
errors.emplace_back(Action::ERROR, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate bus instance count
|
||||||
|
std::map<std::string, int> busInstanceMap;
|
||||||
|
for (auto &inst: schema.busInstances) {
|
||||||
|
busInstanceMap[inst->bus.getName()]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto bus: library.getBuses()) {
|
||||||
|
int count = busInstanceMap[bus.getName()];
|
||||||
|
|
||||||
|
context.attributes["busName"] = Value::fromString(bus.getDisplayName());
|
||||||
|
context.attributes["min"] = Value::fromInt(bus.getCount().first);
|
||||||
|
context.attributes["max"] = Value::fromInt(bus.getCount().second);
|
||||||
|
context.attributes["count"] = Value::fromInt(count);
|
||||||
|
|
||||||
|
if (count < bus.getCount().first) {
|
||||||
|
auto message = MESSAGE_PARAM("msg_validators_bus_min_count", context.map());
|
||||||
|
errors.emplace_back(Action::ERROR, message);
|
||||||
|
} else if (count > bus.getCount().second) {
|
||||||
|
auto message = MESSAGE_PARAM("msg_validators_bus_max_count", context.map());
|
||||||
|
errors.emplace_back(Action::ERROR, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ValidationError>
|
||||||
|
ComdelValidator::validatePinConnections(Schema &schema, Library &library, ValidationContext context) {
|
||||||
|
std::vector<ValidationError> errors;
|
||||||
|
|
||||||
|
for (auto &inst: schema.componentInstances) {
|
||||||
|
for (auto &pin: inst->component.getPins()) {
|
||||||
|
if (pin.getConnection().has_value()) {
|
||||||
|
if (!connectionExists(schema, inst, pin)) {
|
||||||
|
context.instance = inst.get();
|
||||||
|
auto message = MESSAGE_PARAM(pin.getConnection().value(), context.map());
|
||||||
|
errors.emplace_back(context.instance, nullptr, Action::ERROR, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ValidationError>
|
||||||
|
ComdelValidator::validateComponent(ComponentInstance *instance, ValidationContext context) {
|
||||||
|
std::vector<ValidationError> errors;
|
||||||
|
|
||||||
|
context.instance = instance;
|
||||||
|
context.attributes.clear();
|
||||||
|
|
||||||
|
for (auto &attribute: instance->attributes) {
|
||||||
|
context.attributes[attribute.name] = attribute.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &rule: instance->component.getRules()) {
|
||||||
|
auto result = validateRule(rule, context);
|
||||||
|
if (result) {
|
||||||
|
errors.push_back(*result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &attribute: instance->attributes) {
|
||||||
|
auto result = validateAttribute(&attribute, context);
|
||||||
|
errors.insert(errors.end(), result.begin(), result.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ValidationError>
|
||||||
|
ComdelValidator::validateAttribute(InstanceAttribute *attribute, ValidationContext context) {
|
||||||
|
std::vector<ValidationError> errors;
|
||||||
|
if (attribute->attribute.getPopup()) {
|
||||||
|
Popup popup = *attribute->attribute.getPopup();
|
||||||
|
context.attribute = attribute;
|
||||||
|
context.attributes = std::map<std::string, Value>{{attribute->name, attribute->value}};
|
||||||
|
|
||||||
|
for (auto &rule: popup.getRules()) {
|
||||||
|
auto result = validateRule(rule, context);
|
||||||
|
if (result) {
|
||||||
|
errors.push_back(*result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<ValidationError> ComdelValidator::validateRule(Rule rule, ValidationContext context) {
|
||||||
|
RuleContext ruleContext;
|
||||||
|
ruleContext.addressSpaces = context.addressSpaces;
|
||||||
|
ruleContext.attributes = context.attributes;
|
||||||
|
ruleContext.function = validators;
|
||||||
|
auto action = rule.evaluate(ruleContext);
|
||||||
|
if (action) {
|
||||||
|
auto message = MESSAGE_PARAM(action->getMessage(), context.map());
|
||||||
|
return ValidationError{context.instance, context.attribute, action->getType(), message};
|
||||||
|
}
|
||||||
|
return nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<ValidationError>
|
||||||
|
ComdelValidator::validateMemoryReferences(Schema &schema, Library &library, ValidationContext context) {
|
||||||
|
std::set<std::string> memoryInstances;
|
||||||
|
for(auto& component: schema.componentInstances) {
|
||||||
|
if(component->component.getType() == Component::MEMORY) {
|
||||||
|
memoryInstances.insert(component->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ValidationError> errors;
|
||||||
|
for(auto& component: schema.componentInstances) {
|
||||||
|
if(component->component.getType() == Component::PROCESSOR) {
|
||||||
|
for(auto& attribute: component->attributes) {
|
||||||
|
if(attribute.value.isType(Value::MEMORY_REFERENCE)) {
|
||||||
|
auto memoryReference = attribute.value.asMemoryReference();
|
||||||
|
if(memoryReference != nullopt) {
|
||||||
|
if(memoryInstances.count(*memoryReference) == 0) {
|
||||||
|
context.attributes["memoryReference"] = domain::Value::fromString(memoryReference.value());
|
||||||
|
auto message = MESSAGE_PARAM("msg_validators_memory_not_found", context.map());
|
||||||
|
errors.emplace_back(component.get(), nullptr, Action::ERROR, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ValidationError>
|
||||||
|
ComdelValidator::validateInstanceNames(Schema &schema, Library &library, ValidationContext context) {
|
||||||
|
std::set<std::string> names;
|
||||||
|
std::vector<ValidationError> errors;
|
||||||
|
|
||||||
|
for(auto& component: schema.componentInstances) {
|
||||||
|
if(names.find(component->name) != names.end()) {
|
||||||
|
context.instance = component.get();
|
||||||
|
auto message = MESSAGE_PARAM("msg_validators_duplicates_found", context.map());
|
||||||
|
errors.emplace_back(Action::ERROR, message);
|
||||||
|
}
|
||||||
|
names.insert(component->name);
|
||||||
|
}
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ComdelValidator::connectionExists(Schema &schema, shared_ptr<ComponentInstance> &component, Pin &pin) {
|
||||||
|
for (auto conn: schema.connections) {
|
||||||
|
auto busConnection = dynamic_cast<BusConnectionInstance *>(conn.get());
|
||||||
|
if (busConnection != nullptr) {
|
||||||
|
if (busConnection->instance->name == component->name &&
|
||||||
|
busConnection->connection.getComponent().pin == pin.getName()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto directConnection = dynamic_cast<DirectConnectionInstance *>(conn.get());
|
||||||
|
if (directConnection != nullptr) {
|
||||||
|
if ((directConnection->instance->name == component->name && directConnection->connection.getComponent().pin == pin.getName()) ||
|
||||||
|
(directConnection->secondInstance->name == component->name) && directConnection->connection.getSecondComponent()->pin == pin.getName()) {
|
||||||
|
return directConnection->connection.isConnecting({component->component.getName(), pin.getName()});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ComdelValidator::ComdelValidator(std::vector<FunctionValidator *> validators) {
|
||||||
|
for (auto *validator: validators) {
|
||||||
|
validator->clear();
|
||||||
|
this->validators.insert(std::make_pair(validator->getName(), validator));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<std::string, std::string> ValidationContext::map() {
|
||||||
|
std::map<std::string, std::string> parametars;
|
||||||
|
if(instance != nullptr) {
|
||||||
|
parametars["instanceName"] = instance->name;
|
||||||
|
parametars["componentName"] = instance->component.getDisplayName();
|
||||||
|
}
|
||||||
|
if(attribute != nullptr) {
|
||||||
|
parametars["attributeName"] = attribute->name;
|
||||||
|
parametars["attribute"] = attribute->value.string();
|
||||||
|
}
|
||||||
|
for(auto [key, value]: attributes) {
|
||||||
|
parametars[key] = value.string();
|
||||||
|
}
|
||||||
|
return parametars;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
#ifndef COMDEL_VALIDATOR_H
|
||||||
|
#define COMDEL_VALIDATOR_H
|
||||||
|
|
||||||
|
#include "instance.h"
|
||||||
|
#include "schema.h"
|
||||||
|
#include "library.h"
|
||||||
|
|
||||||
|
namespace domain {
|
||||||
|
|
||||||
|
struct ValidationError {
|
||||||
|
ComponentInstance *instance;
|
||||||
|
InstanceAttribute *attribute;
|
||||||
|
Action::ActionType type;
|
||||||
|
std::string message;
|
||||||
|
|
||||||
|
ValidationError(Action::ActionType type, std::string message): instance(nullptr), attribute(nullptr), type(type), message(message) {}
|
||||||
|
|
||||||
|
ValidationError(ComponentInstance* instance, InstanceAttribute* attribute, Action::ActionType type, std::string message): instance(instance), attribute(attribute), type(type), message(message) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ValidationContext {
|
||||||
|
ComponentInstance *instance;
|
||||||
|
InstanceAttribute *attribute;
|
||||||
|
std::map<std::string, AddressSpace> addressSpaces;
|
||||||
|
std::map<std::string, Value> attributes;
|
||||||
|
|
||||||
|
std::map<std::string, std::string> map();
|
||||||
|
};
|
||||||
|
|
||||||
|
class ComdelValidator {
|
||||||
|
public:
|
||||||
|
std::vector<ValidationError> validateSchema(Schema &schema, ValidationContext context);
|
||||||
|
|
||||||
|
std::vector<ValidationError> validateComponent(ComponentInstance *instance, ValidationContext context);
|
||||||
|
|
||||||
|
std::vector<ValidationError> validateAttribute(InstanceAttribute *attribute, ValidationContext context);
|
||||||
|
|
||||||
|
std::optional<ValidationError> validateRule(Rule rule, ValidationContext context);
|
||||||
|
|
||||||
|
std::vector<ValidationError> validateMemoryReferences(Schema &schema, Library &library, ValidationContext context);
|
||||||
|
|
||||||
|
std::vector<ValidationError> validateInstanceNames(Schema &schema, Library &library, ValidationContext context);
|
||||||
|
|
||||||
|
std::vector<ValidationError> validateInstanceCount(Schema &schema, Library &library, ValidationContext context);
|
||||||
|
|
||||||
|
std::vector<ValidationError> validatePinConnections(Schema &schema, Library &library, ValidationContext context);
|
||||||
|
|
||||||
|
ComdelValidator(std::vector<FunctionValidator *> validators);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::map<std::string, FunctionValidator *> validators;
|
||||||
|
|
||||||
|
bool connectionExists(Schema &schema, shared_ptr<ComponentInstance> &component, Pin &pin);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif //COMDEL_VALIDATOR_H
|
|
@ -1,95 +0,0 @@
|
||||||
#include "comdelvalidator.h"
|
|
||||||
|
|
||||||
namespace domain {
|
|
||||||
|
|
||||||
std::vector<ValidationError> ComdelValidator::validateSchema(Schema &schema, ValidationContext context) {
|
|
||||||
std::vector<ValidationError> errors;
|
|
||||||
|
|
||||||
context.instance = nullptr;
|
|
||||||
context.attribute = nullptr;
|
|
||||||
|
|
||||||
for(auto &inst: schema.instances) {
|
|
||||||
auto *instance = dynamic_cast<ComponentInstance*>(inst);
|
|
||||||
if(instance) {
|
|
||||||
auto result = validateComponent(instance, context);
|
|
||||||
errors.insert(errors.end(), result.begin(), result.end());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return errors;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<ValidationError> ComdelValidator::validateComponent(ComponentInstance *instance, ValidationContext context) {
|
|
||||||
std::vector<ValidationError> errors;
|
|
||||||
|
|
||||||
context.instance = instance;
|
|
||||||
context.attributes.clear();
|
|
||||||
|
|
||||||
for(auto &attribute: instance->attributes) {
|
|
||||||
context.attributes[attribute->name] = attribute->value;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(auto &rule: instance->component.getRules()) {
|
|
||||||
auto result = validateRule(rule, context);
|
|
||||||
if(result) {
|
|
||||||
errors.push_back(*result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(auto &attribute: instance->attributes) {
|
|
||||||
auto result = validateAttribute(attribute, context);
|
|
||||||
errors.insert(errors.end(), result.begin(), result.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
return errors;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<ValidationError> ComdelValidator::validateAttribute(InstanceAttribute *attribute, ValidationContext context) {
|
|
||||||
std::vector<ValidationError> errors;
|
|
||||||
if(attribute->attribute.getPopup()) {
|
|
||||||
Popup popup = *attribute->attribute.getPopup();
|
|
||||||
context.attribute = attribute;
|
|
||||||
context.attributes = std::map<std::string, Value>{{attribute->name, attribute->value}};
|
|
||||||
|
|
||||||
for(auto &rule: popup.getRules()) {
|
|
||||||
auto result = validateRule(rule, context);
|
|
||||||
if(result) {
|
|
||||||
errors.push_back(*result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return errors;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<ValidationError> ComdelValidator::validateRule(Rule rule, ValidationContext context) {
|
|
||||||
RuleContext ruleContext;
|
|
||||||
ruleContext.addressSpaces = context.addressSpaces;
|
|
||||||
ruleContext.attributes = context.attributes;
|
|
||||||
ruleContext.function = callbacks;
|
|
||||||
auto action = rule.evaluate(ruleContext);
|
|
||||||
if (action) {
|
|
||||||
std::string message = this->populateMessage(action->getMessage(), context);
|
|
||||||
return ValidationError{context.instance, context.attribute, action->getType(), message};
|
|
||||||
}
|
|
||||||
return nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string ComdelValidator::populateMessage(string source, ValidationContext context) {
|
|
||||||
for(auto &[key, value]: context.attributes) {
|
|
||||||
source = replacePlaceholder(source, key, value);
|
|
||||||
}
|
|
||||||
return source;
|
|
||||||
}
|
|
||||||
|
|
||||||
string ComdelValidator::replacePlaceholder(string source, string key, Value value) {
|
|
||||||
key = "{" + key + "}";
|
|
||||||
auto placeholderValue = value.string();
|
|
||||||
|
|
||||||
auto found = source.find(key);
|
|
||||||
while(found != string::npos) {
|
|
||||||
source.replace(found, key.length(), placeholderValue);
|
|
||||||
found = source.find(key);
|
|
||||||
}
|
|
||||||
return source;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
#ifndef COMDEL_VALIDATOR_H
|
|
||||||
#define COMDEL_VALIDATOR_H
|
|
||||||
|
|
||||||
#include "instance.h"
|
|
||||||
#include "schema.h"
|
|
||||||
|
|
||||||
namespace domain {
|
|
||||||
|
|
||||||
struct ValidationError
|
|
||||||
{
|
|
||||||
Instance *instance;
|
|
||||||
InstanceAttribute *attribute;
|
|
||||||
Action::ActionType type;
|
|
||||||
std::string message;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ValidationContext {
|
|
||||||
Instance *instance;
|
|
||||||
InstanceAttribute *attribute;
|
|
||||||
std::map<std::string, AddressSpace> addressSpaces;
|
|
||||||
std::map<std::string, Value> attributes;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ComdelValidator
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
std::vector<ValidationError> validateSchema(Schema& schema, ValidationContext context);
|
|
||||||
std::vector<ValidationError> validateComponent(ComponentInstance *instance, ValidationContext context);
|
|
||||||
std::vector<ValidationError> validateAttribute(InstanceAttribute *attribute, ValidationContext context);
|
|
||||||
std::optional<ValidationError> validateRule(Rule rule, ValidationContext context);
|
|
||||||
|
|
||||||
ComdelValidator(std::map<std::string, FunctionCallback> callbacks): callbacks(callbacks) {}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::map<std::string, FunctionCallback> callbacks;
|
|
||||||
|
|
||||||
std::string populateMessage(string basicString, ValidationContext context);
|
|
||||||
|
|
||||||
string replacePlaceholder(string basicString, const string basicString1, Value value);
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif //COMDEL_VALIDATOR_H
|
|
|
@ -1,34 +1,49 @@
|
||||||
#include "component.h"
|
#include "component.h"
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace domain {
|
namespace domain {
|
||||||
|
|
||||||
Component::Component(string name, string tooltip, string source, ComponentType type,
|
Component::Component(string name, optional<string> displayName, string tooltip, string source, ComponentType type,
|
||||||
vector<Rule> rules, string instanceName, pair<int, int> count, Display display,
|
vector<Rule> rules, string instanceName, pair<int, int> count, Display display,
|
||||||
vector<Pin> pins, vector<Attribute> attributes)
|
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)
|
: name(name), displayName(displayName), tooltip(tooltip), source(source), type(type), rules(rules), instanceName(instanceName),
|
||||||
{}
|
count(count), display(display), pins(pins), attributes(attributes) {}
|
||||||
|
|
||||||
std::string Component::getName() {
|
std::string Component::getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Component::getDisplayName() {
|
||||||
|
if(displayName.has_value()) {
|
||||||
|
return displayName.value();
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
std::string Component::getTooltip() {
|
std::string Component::getTooltip() {
|
||||||
return tooltip;
|
return tooltip;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Component::getSource() {
|
std::string Component::getSource() {
|
||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
|
|
||||||
Component::ComponentType Component::getType() {
|
Component::ComponentType Component::getType() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Rule> Component::getRules() {
|
std::vector<Rule> Component::getRules() {
|
||||||
return rules;
|
return rules;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Component::getInstanceName() {
|
std::string Component::getInstanceName() {
|
||||||
return instanceName;
|
return instanceName;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<int, int> Component::getCount() {
|
std::pair<int, int> Component::getCount() {
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
Display Component::getDisplay() {
|
Display Component::getDisplay() {
|
||||||
return display;
|
return display;
|
||||||
}
|
}
|
||||||
|
@ -36,13 +51,14 @@ Display Component::getDisplay() {
|
||||||
std::vector<Pin> Component::getPins() {
|
std::vector<Pin> Component::getPins() {
|
||||||
return pins;
|
return pins;
|
||||||
}
|
}
|
||||||
|
|
||||||
Pin Component::getPin(std::string pin) {
|
Pin Component::getPin(std::string pin) {
|
||||||
for(uint i=0; i<pins.size(); i++) {
|
for (auto & p: pins) {
|
||||||
if(pins[i].getName() == pin) {
|
if (p.getName() == pin) {
|
||||||
return pins[i];
|
return p;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw std::exception();
|
throw std::runtime_error("no pin with name '" + pin + "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Component::hasPin(std::string name) {
|
bool Component::hasPin(std::string name) {
|
||||||
|
@ -54,26 +70,36 @@ bool Component::hasPin(std::string name) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Attribute> Component::getAttributes() {
|
std::vector<Attribute>& Component::getAttributes() {
|
||||||
return attributes;
|
return attributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
Attribute Component::getAttribute(std::string attribute) {
|
Attribute Component::getAttribute(std::string attribute) {
|
||||||
for(uint i=0; i<attributes.size(); i++) {
|
for (auto & attr : attributes) {
|
||||||
if(attributes[i].getName() == attribute) {
|
if (attr.getName() == attribute) {
|
||||||
return attributes[i];
|
return attr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw std::exception();
|
throw std::runtime_error("no attribute with name '" + attribute + "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Component::hasAttribute(std::string name, Value::ValueType type) {
|
bool Component::hasAttribute(std::string name, Value::ValueType type) {
|
||||||
for(uint i=0; i<attributes.size(); i++) {
|
for (auto & attribute : attributes) {
|
||||||
if(attributes[i].getName() == name && attributes[i].getDefault().getType() == type) {
|
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 true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace domain
|
} // namespace domain
|
||||||
|
|
|
@ -13,8 +13,7 @@ namespace domain {
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
class Component
|
class Component {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
enum ComponentType {
|
enum ComponentType {
|
||||||
OTHER,
|
OTHER,
|
||||||
|
@ -24,6 +23,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string name;
|
std::string name;
|
||||||
|
std::optional<std::string> displayName;
|
||||||
std::string tooltip;
|
std::string tooltip;
|
||||||
std::string source;
|
std::string source;
|
||||||
ComponentType type;
|
ComponentType type;
|
||||||
|
@ -37,24 +37,36 @@ private:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Component(string name, string tooltip, string source, ComponentType type,
|
Component(string name, optional<string> displayName, string tooltip, string source, ComponentType type,
|
||||||
vector<Rule> rules, string instanceName, pair<int, int> count, Display display,
|
vector<Rule> rules, string instanceName, pair<int, int> count, Display display,
|
||||||
vector<Pin> pins, vector<Attribute> attributes);
|
vector<Pin> pins, vector<Attribute> attributes);
|
||||||
|
|
||||||
std::string getName();
|
std::string getName();
|
||||||
|
|
||||||
|
std::string getDisplayName();
|
||||||
|
|
||||||
std::string getTooltip();
|
std::string getTooltip();
|
||||||
|
|
||||||
std::string getSource();
|
std::string getSource();
|
||||||
|
|
||||||
ComponentType getType();
|
ComponentType getType();
|
||||||
|
|
||||||
std::vector<Rule> getRules();
|
std::vector<Rule> getRules();
|
||||||
|
|
||||||
std::string getInstanceName();
|
std::string getInstanceName();
|
||||||
|
|
||||||
std::pair<int, int> getCount();
|
std::pair<int, int> getCount();
|
||||||
|
|
||||||
Display getDisplay();
|
Display getDisplay();
|
||||||
|
|
||||||
std::vector<Pin> getPins();
|
std::vector<Pin> getPins();
|
||||||
|
|
||||||
Pin getPin(std::string pin);
|
Pin getPin(std::string pin);
|
||||||
|
|
||||||
std::vector<Attribute> getAttributes();
|
std::vector<Attribute>& getAttributes();
|
||||||
|
|
||||||
Attribute getAttribute(std::string attribute);
|
Attribute getAttribute(std::string attribute);
|
||||||
|
|
||||||
bool hasAttribute(std::string name, Value::ValueType type);
|
bool hasAttribute(std::string name, Value::ValueType type);
|
||||||
|
|
||||||
bool hasPin(std::string name);
|
bool hasPin(std::string name);
|
||||||
|
|
|
@ -1,30 +1,34 @@
|
||||||
#include "connection.h"
|
#include "connection.h"
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace domain {
|
namespace domain {
|
||||||
|
|
||||||
Connection::Connection(ConnectionComponent first, std::optional<ConnectionComponent> second,
|
Connection::Connection(ConnectionComponent first, std::optional<ConnectionComponent> second,
|
||||||
std::string bus, std::vector<Attribute> attributes,
|
std::string bus, std::vector<Attribute> attributes,
|
||||||
std::vector<Value> firstWires, std::optional<std::vector<Value>> secondWires)
|
std::vector<Value> firstWires, std::optional<std::vector<Value>> secondWires)
|
||||||
: first(first), second(second), bus(bus), attributes(attributes), firstWires(firstWires), secondWires(secondWires)
|
: first(first), second(second), bus(bus), attributes(attributes), firstWires(firstWires),
|
||||||
{}
|
secondWires(secondWires) {}
|
||||||
|
|
||||||
ConnectionComponent Connection::getComponent() {
|
ConnectionComponent Connection::getComponent() {
|
||||||
return first;
|
return first;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<ConnectionComponent> Connection::getSecondComponent() {
|
std::optional<ConnectionComponent> Connection::getSecondComponent() {
|
||||||
return second;
|
return second;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Connection::getBus() {
|
std::string &Connection::getBus() {
|
||||||
return bus;
|
return bus;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Attribute> Connection::getAttributes() {
|
std::vector<Attribute>& Connection::getAttributes() {
|
||||||
return attributes;
|
return attributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Value> Connection::getWires() {
|
std::vector<Value> Connection::getWires() {
|
||||||
return firstWires;
|
return firstWires;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::vector<Value>> Connection::getSecondWires() {
|
std::optional<std::vector<Value>> Connection::getSecondWires() {
|
||||||
return secondWires;
|
return secondWires;
|
||||||
}
|
}
|
||||||
|
@ -35,7 +39,7 @@ Attribute Connection::getAttribute(std::string name) {
|
||||||
return attributes[i];
|
return attributes[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw std::exception();
|
throw std::runtime_error("no attribute with name '" + name + "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Connection::hasAttribute(std::string name) {
|
bool Connection::hasAttribute(std::string name) {
|
||||||
|
@ -63,4 +67,14 @@ bool Connection::isConnecting(ConnectionComponent component, std::string bus, Co
|
||||||
(this->first == secondComponent && this->bus == bus && this->second == component);
|
(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
|
} // namespace domain
|
||||||
|
|
|
@ -8,23 +8,31 @@
|
||||||
|
|
||||||
namespace domain {
|
namespace domain {
|
||||||
|
|
||||||
struct ConnectionComponent
|
struct ConnectionComponent {
|
||||||
{
|
|
||||||
std::string component;
|
std::string component;
|
||||||
std::string pin;
|
std::string pin;
|
||||||
|
|
||||||
bool operator==(const ConnectionComponent& rhs) const
|
bool operator==(const ConnectionComponent &rhs) const {
|
||||||
{
|
|
||||||
return (component == rhs.component) && (pin == rhs.pin);
|
return (component == rhs.component) && (pin == rhs.pin);
|
||||||
}
|
}
|
||||||
bool operator!=(const ConnectionComponent& rhs) const
|
|
||||||
{
|
bool operator!=(const ConnectionComponent &rhs) const {
|
||||||
return !operator==(rhs);
|
return !operator==(rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class Connection
|
class Connection {
|
||||||
{
|
|
||||||
ConnectionComponent first;
|
ConnectionComponent first;
|
||||||
std::optional<ConnectionComponent> second;
|
std::optional<ConnectionComponent> second;
|
||||||
std::string bus;
|
std::string bus;
|
||||||
|
@ -38,21 +46,31 @@ public:
|
||||||
std::vector<Value> firstWires, std::optional<std::vector<Value>> secondWires);
|
std::vector<Value> firstWires, std::optional<std::vector<Value>> secondWires);
|
||||||
|
|
||||||
bool isConnecting(ConnectionComponent first);
|
bool isConnecting(ConnectionComponent first);
|
||||||
|
|
||||||
bool isConnecting(ConnectionComponent first, std::string bus);
|
bool isConnecting(ConnectionComponent first, std::string bus);
|
||||||
|
|
||||||
bool isConnecting(ConnectionComponent first, std::string bus, ConnectionComponent second);
|
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();
|
ConnectionComponent getComponent();
|
||||||
|
|
||||||
std::optional<ConnectionComponent> getSecondComponent();
|
std::optional<ConnectionComponent> getSecondComponent();
|
||||||
|
|
||||||
std::string getBus();
|
std::string &getBus();
|
||||||
|
|
||||||
std::vector<Attribute> getAttributes();
|
std::vector<Attribute>& getAttributes();
|
||||||
|
|
||||||
std::vector<Value> getWires();
|
std::vector<Value> getWires();
|
||||||
|
|
||||||
std::optional<std::vector<Value>> getSecondWires();
|
std::optional<std::vector<Value>> getSecondWires();
|
||||||
|
|
||||||
Attribute getAttribute(std::string name);
|
Attribute getAttribute(std::string name);
|
||||||
|
|
||||||
bool hasAttribute(std::string name);
|
bool hasAttribute(std::string name);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
#include "connection_instance.h"
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
namespace domain {
|
||||||
|
|
||||||
|
|
||||||
|
ConnectionInstance::ConnectionInstance(ComponentInstance *instance, std::vector<InstanceAttribute> attributes,
|
||||||
|
Connection connection)
|
||||||
|
: instance(instance), attributes(attributes), connection(connection) {}
|
||||||
|
|
||||||
|
InstanceAttribute ConnectionInstance::getAttribute(string attribute) {
|
||||||
|
for (auto &attr: attributes) {
|
||||||
|
if (attr.name == attribute) {
|
||||||
|
return attr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw std::runtime_error("no attribute with name '" + attribute + "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BusConnectionInstance::BusConnectionInstance(ComponentInstance *instance, std::vector<InstanceAttribute> attributes,
|
||||||
|
BusInstance *bus, Connection connection)
|
||||||
|
: ConnectionInstance(instance, attributes, connection), bus(bus) {}
|
||||||
|
|
||||||
|
DirectConnectionInstance::DirectConnectionInstance(ComponentInstance *instance, ComponentInstance *secondInstance,
|
||||||
|
std::vector<InstanceAttribute> attributes, BusInstance *bus,
|
||||||
|
Connection connection)
|
||||||
|
: ConnectionInstance(instance, attributes, connection), secondInstance(secondInstance), bus(bus) {}
|
||||||
|
|
||||||
|
int DirectConnectionInstance::getSelected(ConnectionComponent conn) {
|
||||||
|
if(this->instance->name == conn.component) {
|
||||||
|
auto selected = attributes[0].value.asString();
|
||||||
|
for(int i=0; i<connection.getWires().size(); i++) {
|
||||||
|
if(connection.getWires()[i].isType(Value::STRING) && connection.getWires()[i].asString() == selected) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
auto selected = attributes[1].value.asString();
|
||||||
|
for(int i=0; i<connection.getSecondWires()->size(); i++) {
|
||||||
|
if(connection.getSecondWires().value()[i].isType(Value::STRING) && connection.getSecondWires().value()[i].asString() == selected) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace domain
|
|
@ -0,0 +1,51 @@
|
||||||
|
#ifndef DOMAIN_CONNECTION_INSTANCE_H
|
||||||
|
#define DOMAIN_CONNECTION_INSTANCE_H
|
||||||
|
|
||||||
|
#include "connection.h"
|
||||||
|
#include "instance.h"
|
||||||
|
|
||||||
|
namespace domain {
|
||||||
|
|
||||||
|
class ConnectionInstance {
|
||||||
|
public:
|
||||||
|
ComponentInstance *instance;
|
||||||
|
Connection connection;
|
||||||
|
|
||||||
|
virtual ~ConnectionInstance() = default;
|
||||||
|
|
||||||
|
std::vector<InstanceAttribute> attributes;
|
||||||
|
|
||||||
|
std::pair<int, int> start;
|
||||||
|
std::pair<int, int> end;
|
||||||
|
|
||||||
|
ConnectionInstance(ComponentInstance *instance, std::vector<InstanceAttribute> attributes,
|
||||||
|
Connection connection);
|
||||||
|
|
||||||
|
InstanceAttribute getAttribute(string attribute);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class BusConnectionInstance : public ConnectionInstance {
|
||||||
|
public:
|
||||||
|
BusInstance *bus;
|
||||||
|
|
||||||
|
BusConnectionInstance(ComponentInstance *instance, std::vector<InstanceAttribute> attributes, BusInstance *bus,
|
||||||
|
Connection connection);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class DirectConnectionInstance : public ConnectionInstance {
|
||||||
|
public:
|
||||||
|
BusInstance *bus;
|
||||||
|
ComponentInstance *secondInstance;
|
||||||
|
|
||||||
|
DirectConnectionInstance(ComponentInstance *instance, ComponentInstance *secondsInstance,
|
||||||
|
std::vector<InstanceAttribute> attributes, BusInstance *bus, Connection connection);
|
||||||
|
|
||||||
|
int getSelected(ConnectionComponent connection);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace domain
|
||||||
|
|
||||||
|
#endif // DOMAIN_CONNECTIONINSTANCE_H
|
|
@ -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 *secondInstance, std::vector<InstanceAttribute*> attributes, BusInstance *bus, WireInstance *wire, Connection connection)
|
|
||||||
: ConnectionInstance(instance, attributes, wire, connection), secondInstance(secondInstance), bus(bus)
|
|
||||||
{}
|
|
||||||
|
|
||||||
} // namespace domain
|
|
|
@ -1,46 +0,0 @@
|
||||||
#ifndef DOMAIN_CONNECTION_INSTANCE_H
|
|
||||||
#define DOMAIN_CONNECTION_INSTANCE_H
|
|
||||||
|
|
||||||
#include "connection.h"
|
|
||||||
#include "instance.h"
|
|
||||||
#include "wireinstance.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace domain {
|
|
||||||
|
|
||||||
class ConnectionInstance
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ComponentInstance *instance;
|
|
||||||
Connection connection;
|
|
||||||
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
|
|
|
@ -1,7 +1,265 @@
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
|
|
||||||
|
#include <QBrush>
|
||||||
|
#include <QPen>
|
||||||
|
#include <QFont>
|
||||||
|
|
||||||
|
#include "comdel/domain/instance.h"
|
||||||
|
|
||||||
namespace domain {
|
namespace domain {
|
||||||
|
|
||||||
Display::Display(std::vector<ui::Item> items) : items(items) {}
|
Display::Display(std::vector<ui::Item> items) : items(items) {}
|
||||||
|
|
||||||
|
void Display::render(QGraphicsItemGroup *group, ui::DisplayContext context) {
|
||||||
|
for (auto &item: items) {
|
||||||
|
item.render(group, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Display::comdel(std::ostream &buffer, int x, int y, int size) {
|
||||||
|
for (auto &item: items) {
|
||||||
|
item.comdel(buffer, x, y, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui::Text::render(QGraphicsItemGroup *group, ui::DisplayContext context) {
|
||||||
|
auto formattedText = context.populateMessage(text);
|
||||||
|
|
||||||
|
auto content = new QGraphicsTextItem(QString::fromStdString(formattedText));
|
||||||
|
content->setDefaultTextColor(color);
|
||||||
|
content->setPos(x, y);
|
||||||
|
content->setFont(QFont("arial", 8));
|
||||||
|
group->addToGroup(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui::Text::comdel(std::ostream &buffer, int x, int y) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ui::Rect::render(QGraphicsItemGroup *group) {
|
||||||
|
auto rect = new QGraphicsRectItem(x, y, w, h);
|
||||||
|
rect->setPen(QPen(config.lineColor));
|
||||||
|
rect->setBrush(QBrush(config.fillColor));
|
||||||
|
group->addToGroup(rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui::Rect::comdel(std::ostream &buffer, int x, int y) {
|
||||||
|
buffer << "\t\trectangle {\n";
|
||||||
|
buffer << "\t\t\tx: " << (this->x + x) << "; y: " << (this->y + y) << ";\n";
|
||||||
|
buffer << "\t\t\twidth: " << w << "; height: " << h << ";\n";
|
||||||
|
buffer << "\t\t\tfill_color: " << this->config.fillColor.name().toStdString() << ";\n";
|
||||||
|
buffer << "\t\t\tline_color: " << this->config.lineColor.name().toStdString() << ";\n";
|
||||||
|
buffer << "\t\t}\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui::Ellipse::render(QGraphicsItemGroup *group) {
|
||||||
|
auto ellipse = new QGraphicsEllipseItem(x, y, w, h);
|
||||||
|
ellipse->setPen(QPen(config.lineColor));
|
||||||
|
ellipse->setBrush(QBrush(config.fillColor));
|
||||||
|
group->addToGroup(ellipse);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui::Ellipse::comdel(std::ostream &buffer, int x, int y) {
|
||||||
|
buffer << "\t\tellipse {\n";
|
||||||
|
buffer << "\t\t\tx: " << (this->x + x) << "; y: " << (this->y + y) << ";\n";
|
||||||
|
buffer << "\t\t\twidth: " << w << "; height: " << h << ";\n";
|
||||||
|
buffer << "\t\t}\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ui::Line::render(QGraphicsItemGroup *group) {
|
||||||
|
auto line = new QGraphicsLineItem(x1, y1, x2, y2);
|
||||||
|
line->setPen(QPen(config.lineColor));
|
||||||
|
group->addToGroup(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui::Line::comdel(std::ostream &buffer, int x, int y) {
|
||||||
|
buffer << "\t\tpath {\n";
|
||||||
|
buffer << "\t\t\tx:0; y:0;\n";
|
||||||
|
buffer << "\t\t\tpoints: (";
|
||||||
|
buffer << "(" << (x1 + x) << ", " << (y1 + y) << "),";
|
||||||
|
buffer << "(" << (x2 - x1) << "," << (y2 - y1) << "));\n";
|
||||||
|
buffer << "\t\t}" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui::Bus::render(QGraphicsItemGroup *group, int size) {
|
||||||
|
int _w = w, _h = h;
|
||||||
|
if (orientation == HORIZONTAL) {
|
||||||
|
_w = size;
|
||||||
|
} else {
|
||||||
|
_h = size;
|
||||||
|
}
|
||||||
|
auto rect = new QGraphicsRectItem(x, y, _w, _h);
|
||||||
|
rect->setBrush(QBrush(config.fillColor));
|
||||||
|
rect->setPen(QPen(config.lineColor));
|
||||||
|
group->addToGroup(rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ui::Bus::getDefaultSize() {
|
||||||
|
if (orientation == HORIZONTAL) {
|
||||||
|
return w;
|
||||||
|
} else {
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui::Bus::comdel(std::ostream &buffer, int x, int y, int size) {
|
||||||
|
buffer << "\t\trectangle {\n";
|
||||||
|
buffer << "\t\t\tx: " << (this->x + x) << "; y: " << (this->y + y) << ";\n";
|
||||||
|
if (orientation == HORIZONTAL) {
|
||||||
|
buffer << "\t\t\twidth: " << size << "; height: " << h << ";\n";
|
||||||
|
} else {
|
||||||
|
buffer << "\t\t\twidth: " << w << "; height: " << size << ";\n";
|
||||||
|
}
|
||||||
|
buffer << "\t\t\tfill_color: " << this->config.fillColor.name().toStdString() << ";\n";
|
||||||
|
buffer << "\t\t\tline_color: " << this->config.lineColor.name().toStdString() << ";\n";
|
||||||
|
buffer << "\t\t}\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui::Pin::renderIn(QGraphicsItemGroup *group) {
|
||||||
|
QPolygon polygon;
|
||||||
|
|
||||||
|
switch (orientation) {
|
||||||
|
case PinOrientation::TOP:
|
||||||
|
polygon << QPoint(x, y) << QPoint(x, y + h) << QPoint(x + w, y + h) << QPoint(x + w, y)
|
||||||
|
<< QPoint(x + w / 2, y + h / 2);
|
||||||
|
break;
|
||||||
|
case PinOrientation::BOTTOM:
|
||||||
|
polygon << QPoint(x, y) << QPoint(x, y + h) << QPoint(x + w / 2, y + h / 2)
|
||||||
|
<< QPoint(x + w, y + h) << QPoint(x + w, y);
|
||||||
|
break;
|
||||||
|
case PinOrientation::LEFT:
|
||||||
|
polygon << QPoint(x, y) << QPoint(x + w / 2, y + h / 2) << QPoint(x, y + h)
|
||||||
|
<< QPoint(x + w, y + h) << QPoint(x + w, y);
|
||||||
|
break;
|
||||||
|
case PinOrientation::RIGHT:
|
||||||
|
polygon << QPoint(x, y) << QPoint(x, y + h) << QPoint(x + w, y + h)
|
||||||
|
<< QPoint(x + w / 2, y + h / 2) << QPoint(x + w, y);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
auto item = new QGraphicsPolygonItem(polygon);
|
||||||
|
item->setFillRule(Qt::OddEvenFill);
|
||||||
|
item->setBrush(QBrush(config.fillColor));
|
||||||
|
item->setPen(QPen(config.lineColor));
|
||||||
|
group->addToGroup(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui::Pin::renderOut(QGraphicsItemGroup *group) {
|
||||||
|
QPolygon polygon;
|
||||||
|
|
||||||
|
switch (orientation) {
|
||||||
|
case PinOrientation::TOP:
|
||||||
|
polygon << QPoint(x, y + h / 2) << QPoint(x, y + h) << QPoint(x + w, y + h)
|
||||||
|
<< QPoint(x + w, y + h / 2) << QPoint(x + w / 2, y);
|
||||||
|
break;
|
||||||
|
case PinOrientation::BOTTOM:
|
||||||
|
polygon << QPoint(x, y) << QPoint(x, y + h / 2) << QPoint(x + w / 2, y + h)
|
||||||
|
<< QPoint(x + w, y + h / 2) << QPoint(x + w, y);
|
||||||
|
break;
|
||||||
|
case PinOrientation::LEFT:
|
||||||
|
polygon << QPoint(x + w, y) << QPoint(x + w / 2, y) << QPoint(x, y + h / 2)
|
||||||
|
<< QPoint(x + w / 2, y + h) << QPoint(x + w, y + w);
|
||||||
|
break;
|
||||||
|
case PinOrientation::RIGHT:
|
||||||
|
polygon << QPoint(x, y) << QPoint(x, y + h) << QPoint(x + w / 2, y + h)
|
||||||
|
<< QPoint(x + w, y + h / 2) << QPoint(x + w / 2, y);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
auto item = new QGraphicsPolygonItem(polygon);
|
||||||
|
item->setFillRule(Qt::OddEvenFill);
|
||||||
|
item->setBrush(QBrush(config.fillColor));
|
||||||
|
item->setPen(QPen(config.lineColor));
|
||||||
|
group->addToGroup(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui::Pin::renderInOut(QGraphicsItemGroup *group) {
|
||||||
|
auto rect = new QGraphicsRectItem(x, y, w, h);
|
||||||
|
rect->setBrush(QBrush(config.fillColor));
|
||||||
|
rect->setPen(QPen(config.lineColor));
|
||||||
|
group->addToGroup(rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui::Pin::render(QGraphicsItemGroup *group) {
|
||||||
|
switch (pinType) {
|
||||||
|
case PinType::IN:
|
||||||
|
renderIn(group);
|
||||||
|
break;
|
||||||
|
case PinType::OUT:
|
||||||
|
renderOut(group);
|
||||||
|
break;
|
||||||
|
case PinType::IN_OUT:
|
||||||
|
renderInOut(group);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int ui::Pin::getConnectionX() {
|
||||||
|
switch (orientation) {
|
||||||
|
case ui::PinOrientation::TOP:
|
||||||
|
case ui::PinOrientation::BOTTOM:
|
||||||
|
return x + w / 2;
|
||||||
|
case ui::PinOrientation::LEFT:
|
||||||
|
return x;
|
||||||
|
case ui::PinOrientation::RIGHT:
|
||||||
|
return x + w;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ui::Pin::getConnectionY() {
|
||||||
|
switch (orientation) {
|
||||||
|
case ui::PinOrientation::LEFT:
|
||||||
|
case ui::PinOrientation::RIGHT:
|
||||||
|
return y + h / 2;
|
||||||
|
case ui::PinOrientation::TOP:
|
||||||
|
return y;
|
||||||
|
case ui::PinOrientation::BOTTOM:
|
||||||
|
return y + h;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui::Item::render(QGraphicsItemGroup *group, ui::DisplayContext context, int size) {
|
||||||
|
if (rect) rect->render(group);
|
||||||
|
if (line) line->render(group);
|
||||||
|
if (pin) pin->render(group);
|
||||||
|
if (bus) bus->render(group, size);
|
||||||
|
if (text) text->render(group, context);
|
||||||
|
if (ellipse) ellipse->render(group);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui::Item::comdel(std::ostream &buffer, int x, int y, int size) {
|
||||||
|
if (rect) rect->comdel(buffer, x, y);
|
||||||
|
if (line) line->comdel(buffer, x, y);
|
||||||
|
// pins aren't exported
|
||||||
|
if (bus) bus->comdel(buffer, x, y, size);
|
||||||
|
// text currently isn't exported TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
ui::DisplayContext::DisplayContext(ComponentInstance *instance) {
|
||||||
|
for(auto attr: instance->attributes) {
|
||||||
|
this->values[attr.name] = attr.value;
|
||||||
|
}
|
||||||
|
this->values["instanceName"] = Value::fromString(instance->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
string replacePlaceholder(string source, string key, Value value) {
|
||||||
|
key = "{" + key + "}";
|
||||||
|
auto placeholderValue = value.string();
|
||||||
|
|
||||||
|
auto found = source.find(key);
|
||||||
|
while (found != string::npos) {
|
||||||
|
source.replace(found, key.length(), placeholderValue);
|
||||||
|
found = source.find(key);
|
||||||
|
}
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ui::DisplayContext::populateMessage(std::string source) {
|
||||||
|
for (auto &[key, value]: values) {
|
||||||
|
source = replacePlaceholder(source, key, value);
|
||||||
|
}
|
||||||
|
return source;
|
||||||
|
}
|
||||||
} // namespace domain
|
} // namespace domain
|
||||||
|
|
|
@ -4,82 +4,165 @@
|
||||||
#include <QGraphicsItem>
|
#include <QGraphicsItem>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
|
#include <ostream>
|
||||||
|
#include "comdel/parser/color.h"
|
||||||
|
#include "value.h"
|
||||||
|
|
||||||
namespace domain {
|
namespace domain {
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
|
class DisplayContext {
|
||||||
|
std::map<std::string, domain::Value> values;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit DisplayContext(ComponentInstance *instance);
|
||||||
|
std::string populateMessage(std::string message);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DisplayConfig {
|
||||||
|
QColor lineColor;
|
||||||
|
QColor fillColor;
|
||||||
|
|
||||||
|
DisplayConfig(Color lineColor, Color fillColor) {
|
||||||
|
this->lineColor = QColor::fromRgb(lineColor.r, lineColor.g, lineColor.b, lineColor.a);
|
||||||
|
this->fillColor = QColor::fromRgb(fillColor.r, fillColor.g, fillColor.b, fillColor.a);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Text {
|
||||||
|
public:
|
||||||
|
int x, y, w, h;
|
||||||
|
QColor color;
|
||||||
|
std::string text;
|
||||||
|
|
||||||
|
Text(int x, int y, int w, int h, std::string text, Color color) : x(x), y(y), w(w), h(h), text(text),
|
||||||
|
color(QColor::fromRgb(color.r, color.g, color.b, color.a)) {}
|
||||||
|
|
||||||
|
void render(QGraphicsItemGroup *group, ui::DisplayContext context);
|
||||||
|
|
||||||
|
void comdel(std::ostream &buffer, int x, int y);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
class Rect {
|
class Rect {
|
||||||
public:
|
public:
|
||||||
int x, y, w, h;
|
int x, y, w, h;
|
||||||
|
DisplayConfig config;
|
||||||
|
|
||||||
Rect(int x, int y, int w, int h): x(x), y(y), w(w), h(h) {}
|
Rect(int x, int y, int w, int h, DisplayConfig config) : x(x), y(y), w(w), h(h), config(config) {}
|
||||||
|
|
||||||
|
void render(QGraphicsItemGroup *group);
|
||||||
|
|
||||||
|
void comdel(std::ostream &buffer, int x, int y);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class Ellipse {
|
||||||
|
public:
|
||||||
|
int x, y, w, h;
|
||||||
|
DisplayConfig config;
|
||||||
|
|
||||||
|
Ellipse(int x, int y, int w, int h, DisplayConfig config) : x(x), y(y), w(w), h(h), config(config) {}
|
||||||
|
|
||||||
|
void render(QGraphicsItemGroup *group);
|
||||||
|
|
||||||
|
void comdel(std::ostream &buffer, int x, int y);
|
||||||
|
|
||||||
void render(QGraphicsItemGroup *group) {
|
|
||||||
group->addToGroup(new QGraphicsRectItem(x,y,w,h));
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Line {
|
class Line {
|
||||||
public:
|
public:
|
||||||
int x1, y1, x2, y2;
|
int x1, y1, x2, y2;
|
||||||
|
DisplayConfig config;
|
||||||
|
|
||||||
Line(int x1, int y1, int x2, int y2): x1(x1), y1(y1), x2(x2), y2(y2) {}
|
Line(int x1, int y1, int x2, int y2, DisplayConfig config) : x1(x1), y1(y1), x2(x2), y2(y2), config(config) {}
|
||||||
|
|
||||||
void render(QGraphicsItemGroup *group) {
|
void render(QGraphicsItemGroup *group);
|
||||||
group->addToGroup(new QGraphicsLineItem(x1, y1, x2, y2));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
enum Orientation {
|
void comdel(std::ostream &buffer, int x, int y);
|
||||||
LEFT, RIGHT, TOP, BOTTOM
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum PinType {
|
enum PinType {
|
||||||
IN, OUT, IN_OUT
|
IN, OUT, IN_OUT
|
||||||
};
|
};
|
||||||
|
enum PinOrientation {
|
||||||
|
LEFT, RIGHT, TOP, BOTTOM
|
||||||
|
};
|
||||||
|
enum BusOrientation {
|
||||||
|
VERTICAL, HORIZONTAL
|
||||||
|
};
|
||||||
|
|
||||||
|
class Bus {
|
||||||
|
public:
|
||||||
|
int x, y, w, h;
|
||||||
|
BusOrientation orientation;
|
||||||
|
DisplayConfig config;
|
||||||
|
|
||||||
|
Bus(int x, int y, int w, int h, BusOrientation orientation, DisplayConfig config) : x(x), y(y), w(w), h(h),
|
||||||
|
orientation(orientation),
|
||||||
|
config(config) {}
|
||||||
|
|
||||||
|
void render(QGraphicsItemGroup *group, int size);
|
||||||
|
|
||||||
|
int getDefaultSize();
|
||||||
|
|
||||||
|
void comdel(std::ostream &buffer, int x, int y, int size);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
class Pin {
|
class Pin {
|
||||||
public:
|
public:
|
||||||
Orientation orientation;
|
PinOrientation orientation;
|
||||||
PinType pinType;
|
PinType pinType;
|
||||||
int x, y, w, h;
|
int x, y, w, h;
|
||||||
|
DisplayConfig config;
|
||||||
|
|
||||||
Pin(int x, int y, int w, int h): x(x), y(y), w(w), h(h) {}
|
Pin(int x, int y, int w, int h, PinOrientation orientation, PinType pinType, DisplayConfig config)
|
||||||
|
: x(x), y(y), w(w), h(h), orientation(orientation), pinType(pinType), config(config) {}
|
||||||
|
|
||||||
void render(QGraphicsItemGroup *group) {
|
Pin(): config(DisplayConfig(Color(), Color())) {};
|
||||||
group->addToGroup(new QGraphicsRectItem(x,y,w,h));
|
|
||||||
}
|
public:
|
||||||
|
void render(QGraphicsItemGroup *group);
|
||||||
|
|
||||||
|
int getConnectionX();
|
||||||
|
int getConnectionY();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void renderIn(QGraphicsItemGroup *group);
|
||||||
|
void renderOut(QGraphicsItemGroup *group);
|
||||||
|
void renderInOut(QGraphicsItemGroup *group);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class Item {
|
class Item {
|
||||||
public:
|
public:
|
||||||
Item(): rect(std::nullopt), line(std::nullopt), pin(std::nullopt) {}
|
Item() : rect(std::nullopt), line(std::nullopt), pin(std::nullopt), bus(std::nullopt) {}
|
||||||
|
|
||||||
void render(QGraphicsItemGroup *group) {
|
|
||||||
if(rect) rect->render(group);
|
|
||||||
if(line) line->render(group);
|
|
||||||
if(pin) pin->render(group);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<Rect> rect = std::nullopt;
|
std::optional<Rect> rect = std::nullopt;
|
||||||
std::optional<Line> line = std::nullopt;
|
std::optional<Line> line = std::nullopt;
|
||||||
std::optional<Pin> pin = std::nullopt;
|
std::optional<Pin> pin = std::nullopt;
|
||||||
|
std::optional<Bus> bus = std::nullopt;
|
||||||
|
std::optional<Text> text = std::nullopt;
|
||||||
|
std::optional<Ellipse> ellipse = std::nullopt;
|
||||||
|
|
||||||
|
void render(QGraphicsItemGroup *group, ui::DisplayContext context, int size = 0);
|
||||||
|
void comdel(std::ostream &buffer, int x, int y, int size = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Display
|
class Display {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Display(std::vector<ui::Item> items);
|
Display(std::vector<ui::Item> items);
|
||||||
|
|
||||||
void render(QGraphicsItemGroup *group) {
|
void render(QGraphicsItemGroup *group, ui::DisplayContext context);
|
||||||
for(auto &item: items) {
|
|
||||||
item.render(group);
|
void comdel(std::ostream &buffer, int x, int y, int size = 0);
|
||||||
}
|
|
||||||
}
|
std::vector<ui::Item> &getItems() { return items; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<ui::Item> items;
|
std::vector<ui::Item> items;
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -1,45 +0,0 @@
|
||||||
#include "functionsignature.h"
|
|
||||||
|
|
||||||
namespace domain {
|
|
||||||
|
|
||||||
FunctionSignature add(std::string name, std::vector<Value::ValueType> types, FunctionCallback callback) {
|
|
||||||
return {name, types, callback};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<FunctionSignature> getSupportedFunctions() {
|
|
||||||
std::vector<FunctionSignature> s;
|
|
||||||
s.push_back(add("divisible", std::vector<Value::ValueType>{Value::INT, Value::INT},[](std::vector<Value> values) {
|
|
||||||
long long first = values[0].asInt();
|
|
||||||
long long second = values[1].asInt();
|
|
||||||
return (first % second) == 0;
|
|
||||||
}));
|
|
||||||
s.push_back(add("less_then", std::vector<Value::ValueType>{Value::INT, Value::INT}, [](std::vector<Value> values) {
|
|
||||||
long long first = values[0].asInt();
|
|
||||||
long long second = values[1].asInt();
|
|
||||||
return first < second;
|
|
||||||
}));
|
|
||||||
s.push_back(add("greater_then", std::vector<Value::ValueType>{Value::INT, Value::INT}, [](std::vector<Value> values) {
|
|
||||||
long long first = values[0].asInt();
|
|
||||||
long long second = values[1].asInt();
|
|
||||||
return first > second;
|
|
||||||
}));
|
|
||||||
s.push_back(add("contains_address", std::vector<Value::ValueType>{Value::ADDRESS_SPACE, Value::INT}, [](std::vector<Value> values) {
|
|
||||||
AddressSpace space = values[0].asAddressSpace();
|
|
||||||
long long address = values[1].asInt();
|
|
||||||
return space.contains(address);
|
|
||||||
}));
|
|
||||||
s.push_back(add("contains", std::vector<Value::ValueType>{Value::ADDRESS_SPACE, Value::INT, Value::INT}, [](std::vector<Value> values) {
|
|
||||||
AddressSpace space = values[0].asAddressSpace();
|
|
||||||
long long start = values[1].asInt();
|
|
||||||
long long size = values[1].asInt();
|
|
||||||
return space.contains(start, start + size);
|
|
||||||
}));
|
|
||||||
s.push_back(add("unique", std::vector<Value::ValueType>{Value::ADDRESS_SPACE, Value::INT, Value::INT}, [](std::vector<Value> values) {
|
|
||||||
return true;
|
|
||||||
}));
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace domain
|
|
|
@ -1,25 +0,0 @@
|
||||||
#ifndef DOMAIN_FUNCTION_SIGNATURE_H
|
|
||||||
#define DOMAIN_FUNCTION_SIGNATURE_H
|
|
||||||
|
|
||||||
#include<functional>
|
|
||||||
#include<vector>
|
|
||||||
|
|
||||||
#include "value.h"
|
|
||||||
|
|
||||||
namespace domain {
|
|
||||||
|
|
||||||
typedef std::function<bool (std::vector<Value>)> FunctionCallback;
|
|
||||||
|
|
||||||
struct FunctionSignature {
|
|
||||||
std::string name;
|
|
||||||
std::vector<Value::ValueType> params;
|
|
||||||
FunctionCallback callback;
|
|
||||||
|
|
||||||
FunctionSignature(std::string name, std::vector<Value::ValueType> params, FunctionCallback callback): name(name), params(params), callback(callback) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<FunctionSignature> getSupportedFunctions();
|
|
||||||
|
|
||||||
} // namespace domain
|
|
||||||
|
|
||||||
#endif // DOMAIN_FUNCTIONSIGNATURE_H
|
|
|
@ -2,16 +2,18 @@
|
||||||
|
|
||||||
namespace domain {
|
namespace domain {
|
||||||
|
|
||||||
|
|
||||||
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)
|
BusInstance::BusInstance(std::string name, std::pair<int, int> position, Bus bus, int size)
|
||||||
: Instance(name, vector<InstanceAttribute*>(), position), bus(bus), size(size)
|
: name(name), position(position), bus(bus), size(size) {
|
||||||
{}
|
if (size < 0 && bus.getDisplayBus().has_value()) {
|
||||||
ComponentInstance::ComponentInstance(std::string name, std::vector<InstanceAttribute*> attributes, std::pair<int, int> position, Component component)
|
this->size = bus.getDisplayBus()->getDefaultSize();
|
||||||
: 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
|
} // namespace domain
|
||||||
|
|
|
@ -3,50 +3,40 @@
|
||||||
|
|
||||||
#include "bus.h"
|
#include "bus.h"
|
||||||
#include "component.h"
|
#include "component.h"
|
||||||
#include "instanceattribute.h"
|
#include "instance_attribute.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace domain {
|
namespace domain {
|
||||||
|
|
||||||
class Instance
|
class BusInstance {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
std::string name;
|
std::string name;
|
||||||
std::vector<InstanceAttribute*> attributes;
|
|
||||||
std::pair<int, int> position;
|
std::pair<int, int> position;
|
||||||
|
|
||||||
virtual ~Instance() {};
|
|
||||||
|
|
||||||
Instance(std::string name, std::vector<InstanceAttribute*> attributes, std::pair<int, int> position);
|
|
||||||
};
|
|
||||||
|
|
||||||
class BusInstance: public Instance
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Bus bus;
|
Bus bus;
|
||||||
int size;
|
int size;
|
||||||
|
|
||||||
BusInstance(std::string name, std::pair<int, int> position, Bus bus, int size);
|
BusInstance(std::string name, Bus bus);
|
||||||
|
|
||||||
virtual ~BusInstance() {
|
BusInstance(std::string name, std::pair<int, int> position, Bus bus, int size = -1);
|
||||||
Instance::~Instance();
|
|
||||||
}
|
virtual ~BusInstance() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ComponentInstance: public Instance
|
class ComponentInstance {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
|
std::string name;
|
||||||
|
std::vector<InstanceAttribute> attributes;
|
||||||
|
std::pair<int, int> position;
|
||||||
|
|
||||||
Component component;
|
Component component;
|
||||||
|
|
||||||
ComponentInstance(std::string name, std::vector<InstanceAttribute*> attributes, std::pair<int, int> position, Component component);
|
ComponentInstance(std::string name, std::vector<InstanceAttribute> attributes, std::pair<int, int> position, Component component);
|
||||||
|
|
||||||
virtual ~ComponentInstance() {
|
virtual ~ComponentInstance() = default;
|
||||||
Instance::~Instance();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace domain
|
} // namespace domain
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
|
@ -1,26 +0,0 @@
|
||||||
#ifndef DOMAIN_INSTANCE_ATTRIBUTE_H
|
|
||||||
#define DOMAIN_INSTANCE_ATTRIBUTE_H
|
|
||||||
|
|
||||||
#include "attribute.h"
|
|
||||||
#include "value.h"
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace domain {
|
|
||||||
|
|
||||||
class InstanceAttribute
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
InstanceAttribute(std::string name, Value value, Attribute attribute);
|
|
||||||
|
|
||||||
std::string name;
|
|
||||||
Value value;
|
|
||||||
Attribute attribute;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace domain
|
|
||||||
|
|
||||||
#endif // DOMAIN_INSTANCE_ATTRIBUTE_H
|
|
|
@ -1,35 +1,48 @@
|
||||||
#include "library.h"
|
#include "library.h"
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace domain {
|
namespace domain {
|
||||||
|
|
||||||
Library::Library(string name, string libraryInfo, string header, string componentDirectory,
|
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)
|
std::optional<std::string> componentHeader,
|
||||||
: name(name), libraryInfo(libraryInfo), header(header), componentDirectory(componentDirectory), addressSpaces(addressSpaces),
|
vector<AddressSpace> addressSpaces, vector<Component> components, vector<Bus> buses,
|
||||||
components(components), buses(buses), connections(connections), messages(messages)
|
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() {
|
std::string Library::getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Library::getLibraryInfo() {
|
std::string Library::getLibraryInfo() {
|
||||||
return libraryInfo;
|
return libraryInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Library::getHeader() {
|
std::string Library::getHeader() {
|
||||||
return header;
|
return header;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Library::getComponentDirectory() {
|
std::string Library::getComponentDirectory() {
|
||||||
return componentDirectory;
|
return componentDirectory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<std::string> Library::getComponentHeader() {
|
||||||
|
return componentHeader;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<AddressSpace> Library::getAddressSpaces() {
|
std::vector<AddressSpace> Library::getAddressSpaces() {
|
||||||
return addressSpaces;
|
return addressSpaces;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Component> Library::getComponents() {
|
std::vector<Component> Library::getComponents() {
|
||||||
return components;
|
return components;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Bus> Library::getBuses() {
|
std::vector<Bus> Library::getBuses() {
|
||||||
return buses;
|
return buses;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Connection> Library::getConnections() {
|
std::vector<Connection> Library::getConnections() {
|
||||||
return connections;
|
return connections;
|
||||||
}
|
}
|
||||||
|
@ -39,15 +52,16 @@ std::map<std::string, std::string> Library::getMessages() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Library::hasComponent(std::string name) {
|
bool Library::hasComponent(std::string name) {
|
||||||
for(uint i=0; i<components.size(); i++) {
|
for (unsigned int i = 0; i < components.size(); i++) {
|
||||||
if (components[i].getName() == name) {
|
if (components[i].getName() == name) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Library::hasBus(std::string name) {
|
bool Library::hasBus(std::string name) {
|
||||||
for(uint i=0; i<buses.size(); i++) {
|
for (unsigned int i = 0; i < buses.size(); i++) {
|
||||||
if (buses[i].getName() == name) {
|
if (buses[i].getName() == name) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -57,36 +71,39 @@ bool Library::hasBus(std::string name) {
|
||||||
|
|
||||||
|
|
||||||
AddressSpace &Library::getAddressSpace(std::string addressSpace) {
|
AddressSpace &Library::getAddressSpace(std::string addressSpace) {
|
||||||
for(uint i=0; i<addressSpaces.size(); i++) {
|
for (unsigned int i = 0; i < addressSpaces.size(); i++) {
|
||||||
if (addressSpaces[i].getName() == addressSpace) {
|
if (addressSpaces[i].getName() == addressSpace) {
|
||||||
return addressSpaces[i];
|
return addressSpaces[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw std::exception();
|
throw std::runtime_error("no address space with name '" + addressSpace + "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
Component &Library::getComponent(std::string component) {
|
Component &Library::getComponent(std::string component) {
|
||||||
for(uint i=0; i<components.size(); i++) {
|
for (unsigned int i = 0; i < components.size(); i++) {
|
||||||
if (components[i].getName() == component) {
|
if (components[i].getName() == component) {
|
||||||
return components[i];
|
return components[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw std::exception();
|
throw std::runtime_error("no component with name '" + component + "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
Bus &Library::getBus(std::string bus) {
|
Bus &Library::getBus(std::string bus) {
|
||||||
for(uint i=0; i<buses.size(); i++) {
|
for (unsigned int i = 0; i < buses.size(); i++) {
|
||||||
if (buses[i].getName() == bus) {
|
if (buses[i].getName() == bus) {
|
||||||
return buses[i];
|
return buses[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw std::exception();
|
throw std::runtime_error("no bus with name '" + bus + "'");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Library::hasConnection(ConnectionComponent component, std::string bus) {
|
bool Library::hasConnection(ConnectionComponent component, std::string bus) {
|
||||||
return getConnection(component, bus).has_value();
|
return getConnection(component, bus).has_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<Connection> Library::getConnection(ConnectionComponent component, std::string bus) {
|
std::optional<Connection> Library::getConnection(ConnectionComponent component, std::string bus) {
|
||||||
for(uint i=0; i<connections.size(); i++) {
|
for (unsigned int i = 0; i < connections.size(); i++) {
|
||||||
if (connections[i].isConnecting(component, bus)) {
|
if (connections[i].isConnecting(component, bus)) {
|
||||||
return connections[i];
|
return connections[i];
|
||||||
}
|
}
|
||||||
|
@ -97,8 +114,10 @@ std::optional<Connection> Library::getConnection(ConnectionComponent component,
|
||||||
bool Library::hasConnection(ConnectionComponent component, std::string bus, ConnectionComponent secondComponent) {
|
bool Library::hasConnection(ConnectionComponent component, std::string bus, ConnectionComponent secondComponent) {
|
||||||
return getConnection(component, bus, secondComponent).has_value();
|
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++) {
|
std::optional<Connection>
|
||||||
|
Library::getConnection(ConnectionComponent component, std::string bus, ConnectionComponent secondComponent) {
|
||||||
|
for (unsigned int i = 0; i < connections.size(); i++) {
|
||||||
if (connections[i].isConnecting(component, bus, secondComponent)) {
|
if (connections[i].isConnecting(component, bus, secondComponent)) {
|
||||||
return connections[i];
|
return connections[i];
|
||||||
}
|
}
|
||||||
|
@ -110,4 +129,18 @@ std::string Library::getMessage(std::string key) {
|
||||||
return messages[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
|
} // namespace domain
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef DOMAIN_LIBRARY_H
|
#ifndef DOMAIN_LIBRARY_H
|
||||||
#define DOMAIN_LIBRARY_H
|
#define DOMAIN_LIBRARY_H
|
||||||
|
|
||||||
#include "addressspace.h"
|
#include "address_space.h"
|
||||||
#include "bus.h"
|
#include "bus.h"
|
||||||
#include "component.h"
|
#include "component.h"
|
||||||
#include "connection.h"
|
#include "connection.h"
|
||||||
|
@ -10,17 +10,16 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace domain {
|
namespace domain {
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
class Library
|
class Library {
|
||||||
{
|
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string libraryInfo;
|
std::string libraryInfo;
|
||||||
std::string header;
|
std::string header;
|
||||||
std::string componentDirectory;
|
std::string componentDirectory;
|
||||||
|
std::optional<std::string> componentHeader;
|
||||||
|
|
||||||
std::vector<AddressSpace> addressSpaces;
|
std::vector<AddressSpace> addressSpaces;
|
||||||
std::vector<Component> components;
|
std::vector<Component> components;
|
||||||
|
@ -31,33 +30,54 @@ class Library
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Library(string name, string libraryInfo, string header, string componentDirectory,
|
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);
|
std::optional<string> componentHeader,
|
||||||
|
vector<AddressSpace> addressSpaces, vector<Component> components, vector<Bus> buses,
|
||||||
|
vector<Connection> connection, map<string, string> messages);
|
||||||
|
|
||||||
std::string getName();
|
std::string getName();
|
||||||
|
|
||||||
std::string getLibraryInfo();
|
std::string getLibraryInfo();
|
||||||
|
|
||||||
std::string getHeader();
|
std::string getHeader();
|
||||||
|
|
||||||
std::string getComponentDirectory();
|
std::string getComponentDirectory();
|
||||||
|
|
||||||
|
std::optional<std::string> getComponentHeader();
|
||||||
|
|
||||||
std::vector<AddressSpace> getAddressSpaces();
|
std::vector<AddressSpace> getAddressSpaces();
|
||||||
|
|
||||||
std::vector<Component> getComponents();
|
std::vector<Component> getComponents();
|
||||||
|
|
||||||
std::vector<Bus> getBuses();
|
std::vector<Bus> getBuses();
|
||||||
|
|
||||||
std::vector<Connection> getConnections();
|
std::vector<Connection> getConnections();
|
||||||
|
|
||||||
bool hasComponent(std::string name);
|
bool hasComponent(std::string name);
|
||||||
|
|
||||||
bool hasBus(std::string name);
|
bool hasBus(std::string name);
|
||||||
|
|
||||||
std::map<std::string, std::string> getMessages();
|
std::map<std::string, std::string> getMessages();
|
||||||
|
|
||||||
AddressSpace &getAddressSpace(std::string name);
|
AddressSpace &getAddressSpace(std::string name);
|
||||||
|
|
||||||
Component &getComponent(std::string name);
|
Component &getComponent(std::string name);
|
||||||
|
|
||||||
Bus &getBus(std::string bus);
|
Bus &getBus(std::string bus);
|
||||||
|
|
||||||
std::string getMessage(std::string key);
|
std::string getMessage(std::string key);
|
||||||
|
|
||||||
bool hasConnection(ConnectionComponent component, std::string bus);
|
bool hasConnection(ConnectionComponent component, std::string bus);
|
||||||
|
|
||||||
std::optional<Connection> getConnection(ConnectionComponent component, std::string bus);
|
std::optional<Connection> getConnection(ConnectionComponent component, std::string bus);
|
||||||
|
|
||||||
bool hasConnection(ConnectionComponent component, std::string bus, ConnectionComponent secondComponent);
|
bool hasConnection(ConnectionComponent component, std::string bus, ConnectionComponent secondComponent);
|
||||||
|
|
||||||
std::optional<Connection> getConnection(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
|
} // namespace domain
|
||||||
|
|
|
@ -2,37 +2,30 @@
|
||||||
|
|
||||||
namespace domain {
|
namespace domain {
|
||||||
|
|
||||||
PinConnection::PinConnection(std::string message, ConnectionType type)
|
Pin::Pin(std::string name, PinType type, std::string tooltip, std::optional<std::string> connection, domain::ui::Pin pin,
|
||||||
: message(message), type(type)
|
std::optional<std::vector<Value>> wires)
|
||||||
{}
|
: name(name), type(type), tooltip(tooltip), connection(connection), displayPin(pin), wires(wires) {}
|
||||||
|
|
||||||
PinConnection::ConnectionType PinConnection::getType() {
|
std::string &Pin::getName() {
|
||||||
return type;
|
|
||||||
}
|
|
||||||
std::string PinConnection::getMessage() {
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Pin::Pin(std::string name, PinType type, std::string tooltip, PinConnection connection, Display display, std::optional<std::vector<Value>> wires)
|
|
||||||
: name(name), type(type), tooltip(tooltip), connection(connection), display(display), wires(wires)
|
|
||||||
{}
|
|
||||||
|
|
||||||
std::string Pin::getName() {
|
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
Pin::PinType Pin::getType() {
|
Pin::PinType Pin::getType() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Pin::getTooltip() {
|
std::string Pin::getTooltip() {
|
||||||
return tooltip;
|
return tooltip;
|
||||||
}
|
}
|
||||||
Display &Pin::getDisplay() {
|
|
||||||
return display;
|
ui::Pin &Pin::getDisplayPin() {
|
||||||
|
return displayPin;
|
||||||
}
|
}
|
||||||
PinConnection &Pin::getConnection() {
|
|
||||||
|
std::optional<std::string> Pin::getConnection() {
|
||||||
return connection;
|
return connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::vector<Value>> &Pin::getWires() {
|
std::optional<std::vector<Value>> &Pin::getWires() {
|
||||||
return wires;
|
return wires;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,30 +7,9 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace domain {
|
namespace domain {
|
||||||
|
|
||||||
class PinConnection
|
class Pin {
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum ConnectionType {
|
|
||||||
CHECK_ONLY,
|
|
||||||
AUTOMATICALLY
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string message;
|
|
||||||
ConnectionType type;
|
|
||||||
|
|
||||||
public:
|
|
||||||
PinConnection(std::string message, ConnectionType type);
|
|
||||||
|
|
||||||
ConnectionType getType();
|
|
||||||
std::string getMessage();
|
|
||||||
};
|
|
||||||
|
|
||||||
class Pin
|
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
enum PinType {
|
enum PinType {
|
||||||
IN_OUT,
|
IN_OUT,
|
||||||
|
@ -42,19 +21,25 @@ private:
|
||||||
std::string name;
|
std::string name;
|
||||||
PinType type;
|
PinType type;
|
||||||
std::string tooltip;
|
std::string tooltip;
|
||||||
PinConnection connection;
|
std::optional<std::string> connection;
|
||||||
Display display;
|
domain::ui::Pin displayPin;
|
||||||
|
|
||||||
std::optional<std::vector<Value>> wires;
|
std::optional<std::vector<Value>> wires;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Pin(std::string name, PinType type, std::string tooltip, PinConnection connection, Display display, std::optional<std::vector<Value>> wires);
|
Pin(std::string name, PinType type, std::string tooltip, std::optional<std::string> connection, domain::ui::Pin pin,
|
||||||
|
std::optional<std::vector<Value>> wires);
|
||||||
|
|
||||||
|
std::string &getName();
|
||||||
|
|
||||||
std::string getName();
|
|
||||||
PinType getType();
|
PinType getType();
|
||||||
|
|
||||||
std::string getTooltip();
|
std::string getTooltip();
|
||||||
Display &getDisplay();
|
|
||||||
PinConnection &getConnection();
|
ui::Pin &getDisplayPin();
|
||||||
|
|
||||||
|
std::optional<std::string> getConnection();
|
||||||
|
|
||||||
std::optional<std::vector<Value>> &getWires();
|
std::optional<std::vector<Value>> &getWires();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,42 +1,42 @@
|
||||||
#include "rule.h"
|
#include "rule.h"
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
namespace domain {
|
namespace domain {
|
||||||
|
|
||||||
Condition::Condition(std::string function, std::vector<Value> params, bool negated)
|
Condition::Condition(std::string function, std::vector<Value> params, bool negated)
|
||||||
: negated(negated), function(function), params(params)
|
: negated(negated), function(std::move(function)), params(std::move(params)) {}
|
||||||
{}
|
|
||||||
|
|
||||||
bool Condition::evaluate(RuleContext &context) {
|
bool Condition::evaluate(RuleContext &context) {
|
||||||
std::vector<Value> request;
|
std::vector<Value> request;
|
||||||
for(unsigned int i=0; i<params.size(); i++) {
|
for (auto & param : params) {
|
||||||
if(params[i].isType(Value::ADDRESS_SPACE_REFERENCE)) {
|
if (param.isType(Value::ADDRESS_SPACE_REFERENCE)) {
|
||||||
request.push_back(Value::fromAddressSpace(context.addressSpaces.at(params[i].asReference())));
|
request.push_back(Value::fromAddressSpace(context.addressSpaces.at(param.asReference())));
|
||||||
} else if(params[i].isType(Value::ATTRIBUTE_REFERENCE)) {
|
} else if (param.isType(Value::ATTRIBUTE_REFERENCE)) {
|
||||||
request.push_back(context.attributes[params[i].asReference()]);
|
request.push_back(context.attributes[param.asReference()]);
|
||||||
} else {
|
} else {
|
||||||
request.push_back(params[i]);
|
request.push_back(param);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bool result = context.function[function](request);
|
bool result = context.function[function]->validate(request);
|
||||||
return negated ? !result : result;
|
return negated ? !result : result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Action::Action(ActionType type, std::string message)
|
Action::Action(ActionType type, std::string message)
|
||||||
: type(type), message(message)
|
: type(type), message(std::move(message)) {}
|
||||||
{}
|
|
||||||
|
|
||||||
Action::ActionType Action::getType() {
|
Action::ActionType Action::getType() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Action::getMessage() {
|
std::string Action::getMessage() {
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
IfStatement::IfStatement(Condition condition, Action action)
|
IfStatement::IfStatement(Condition condition, Action action)
|
||||||
: condition(condition), action(action)
|
: condition(std::move(condition)), action(std::move(action)) {}
|
||||||
{}
|
|
||||||
|
|
||||||
std::optional<Action> IfStatement::evaluate(RuleContext &context) {
|
std::optional<Action> IfStatement::evaluate(RuleContext &context) {
|
||||||
if (condition.evaluate(context)) {
|
if (condition.evaluate(context)) {
|
||||||
|
@ -46,12 +46,11 @@ std::optional<Action> IfStatement::evaluate(RuleContext &context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Rule::Rule(std::vector<IfStatement> statements)
|
Rule::Rule(std::vector<IfStatement> statements)
|
||||||
: statements(statements)
|
: statements(std::move(statements)) {}
|
||||||
{}
|
|
||||||
|
|
||||||
std::optional<Action> Rule::evaluate(RuleContext &context) {
|
std::optional<Action> Rule::evaluate(RuleContext &context) {
|
||||||
for(unsigned int i=0; i<statements.size(); i++) {
|
for (auto & statement : statements) {
|
||||||
auto response = statements[i].evaluate(context);
|
auto response = statement.evaluate(context);
|
||||||
if (response) {
|
if (response) {
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
#ifndef DOMAIN_RULE_H
|
#ifndef DOMAIN_RULE_H
|
||||||
#define DOMAIN_RULE_H
|
#define DOMAIN_RULE_H
|
||||||
|
|
||||||
#include "addressspace.h"
|
#include "address_space.h"
|
||||||
#include "value.h"
|
#include "value.h"
|
||||||
#include "functionsignature.h"
|
#include "function_signature.h"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -15,7 +15,7 @@ namespace domain {
|
||||||
struct RuleContext {
|
struct RuleContext {
|
||||||
std::map<std::string, AddressSpace> addressSpaces;
|
std::map<std::string, AddressSpace> addressSpaces;
|
||||||
std::map<std::string, Value> attributes;
|
std::map<std::string, Value> attributes;
|
||||||
std::map<std::string, FunctionCallback> function;
|
std::map<std::string, FunctionValidator *> function;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Condition {
|
class Condition {
|
||||||
|
@ -44,6 +44,7 @@ public:
|
||||||
Action(ActionType type, std::string message);
|
Action(ActionType type, std::string message);
|
||||||
|
|
||||||
ActionType getType();
|
ActionType getType();
|
||||||
|
|
||||||
std::string getMessage();
|
std::string getMessage();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -56,11 +57,10 @@ public:
|
||||||
std::optional<Action> evaluate(RuleContext &context);
|
std::optional<Action> evaluate(RuleContext &context);
|
||||||
};
|
};
|
||||||
|
|
||||||
class Rule
|
class Rule {
|
||||||
{
|
|
||||||
std::vector<IfStatement> statements;
|
std::vector<IfStatement> statements;
|
||||||
public:
|
public:
|
||||||
Rule(std::vector<IfStatement> statements);
|
explicit Rule(std::vector<IfStatement> statements);
|
||||||
|
|
||||||
std::optional<Action> evaluate(RuleContext &context);
|
std::optional<Action> evaluate(RuleContext &context);
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,8 +2,114 @@
|
||||||
|
|
||||||
namespace domain {
|
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(library.getBus(conn.getBus()).getType() == Bus::REGULAR) {
|
||||||
|
for(auto& bus: busInstances) {
|
||||||
|
if(bus->bus.getName() == conn.getBus()) {
|
||||||
|
entries.push_back({ConnectionEntry::BUS, bus.get(), nullopt, nullopt, conn});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for(auto& component: componentInstances) {
|
||||||
|
for(auto& pin: component->component.getPins()) {
|
||||||
|
if(conn.isConnecting(connectionComponent, {component->component.getName(), pin.getName()})) {
|
||||||
|
ConnectionEntry entry{ConnectionEntry::COMPONENT, nullopt, component.get(), pin, conn};
|
||||||
|
entries.emplace_back(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(onlyConnectable) {
|
||||||
|
entries.erase(
|
||||||
|
std::remove_if(
|
||||||
|
entries.begin(),
|
||||||
|
entries.end(),
|
||||||
|
[this, instance](ConnectionEntry &entry) {
|
||||||
|
auto& bus = this->library.getBus(entry.connection.getBus());
|
||||||
|
// we allow duplicates of single automatic connections
|
||||||
|
if(bus.getType() == Bus::SINGLE_AUTOMATIC) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for(auto& conn: this->connections) {
|
||||||
|
if(conn->connection == entry.connection) {
|
||||||
|
if(bus.getType() == Bus::REGULAR) {
|
||||||
|
auto busConnection = dynamic_cast<BusConnectionInstance*>(conn.get());
|
||||||
|
if(busConnection->instance == instance && busConnection->bus == entry.busInstance.value()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
auto directConnection = dynamic_cast<DirectConnectionInstance*>(conn.get());
|
||||||
|
if(directConnection->instance == instance && directConnection->secondInstance == entry.componentInstance.value() ||
|
||||||
|
directConnection->secondInstance == instance && directConnection->instance == entry.componentInstance.value()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}),
|
||||||
|
entries.end()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return entries;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace domain
|
} // namespace domain
|
||||||
|
|
|
@ -1,45 +1,49 @@
|
||||||
#ifndef DOMAIN_SCHEMA_H
|
#ifndef DOMAIN_SCHEMA_H
|
||||||
#define DOMAIN_SCHEMA_H
|
#define DOMAIN_SCHEMA_H
|
||||||
|
|
||||||
#include "connectioninstance.h"
|
#include "connection_instance.h"
|
||||||
#include "instance.h"
|
#include "instance.h"
|
||||||
#include "wireinstance.h"
|
#include "library.h"
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace domain {
|
namespace domain {
|
||||||
|
|
||||||
class Schema
|
struct ConnectionEntry {
|
||||||
{
|
enum Type {
|
||||||
|
BUS,
|
||||||
|
COMPONENT
|
||||||
|
};
|
||||||
|
|
||||||
|
Type type;
|
||||||
|
|
||||||
|
std::optional<BusInstance*> busInstance;
|
||||||
|
std::optional<ComponentInstance*> componentInstance;
|
||||||
|
std::optional<Pin> pin;
|
||||||
|
|
||||||
|
Connection connection;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Schema {
|
||||||
|
private:
|
||||||
|
Library library;
|
||||||
public:
|
public:
|
||||||
Schema();
|
Schema(Library library): library(std::move(library)) {}
|
||||||
|
|
||||||
std::vector<Instance*> instances;
|
std::vector<shared_ptr<BusInstance>> busInstances;
|
||||||
std::vector<ConnectionInstance*> connections;
|
std::vector<shared_ptr<ComponentInstance>> componentInstances;
|
||||||
std::vector<WireInstance*> wires;
|
|
||||||
|
|
||||||
WireInstance *getWire(std::string name) {
|
std::vector<shared_ptr<ConnectionInstance>> connections;
|
||||||
for(auto wire: wires) {
|
|
||||||
if (wire->name == name) {
|
|
||||||
return wire;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasWire(std::string name) {
|
BusInstance *getBusInstance(std::string &name);
|
||||||
return getWire(name) != NULL;
|
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);
|
||||||
|
|
||||||
Instance *getInstance(std::string name) {
|
vector<ConnectionInstance *> getConnections(string &component, string &pin);
|
||||||
for(auto instance: instances) {
|
|
||||||
if (instance->name == name) {
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace domain
|
} // namespace domain
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,92 @@
|
||||||
|
#ifndef DOMAIN_COMDEL_GENERATOR_H
|
||||||
|
#define DOMAIN_COMDEL_GENERATOR_H
|
||||||
|
|
||||||
|
#include "library.h"
|
||||||
|
#include "schema.h"
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include <comdel/parser/ast_nodes.h>
|
||||||
|
#include <comdel/parser/parse_context.h>
|
||||||
|
#include <comdel/parser/presult.h>
|
||||||
|
|
||||||
|
namespace domain {
|
||||||
|
|
||||||
|
/** Context used for loading model */
|
||||||
|
struct ComdelContext {
|
||||||
|
std::vector<Attribute> attributes;
|
||||||
|
std::vector<std::string> wires;
|
||||||
|
std::string name;
|
||||||
|
bool inComponent;
|
||||||
|
bool inConnection;
|
||||||
|
bool inSingleAutomaticConnection;
|
||||||
|
|
||||||
|
ComdelContext(std::string name, bool inComponent, bool inConnection, bool inSingleAutomaticConnection);
|
||||||
|
|
||||||
|
bool doesAttributeExists(std::string name, Value::ValueType type);
|
||||||
|
bool doesWireExists(std::string name);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class SchemaCreator {
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit SchemaCreator(std::vector<FunctionValidator *> validators);
|
||||||
|
|
||||||
|
std::vector<SourceError> getErrors();
|
||||||
|
|
||||||
|
std::optional<Library> loadLibrary(LibraryNode node);
|
||||||
|
Schema *loadSchema(SchemaNode node, Library &library);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<ComdelContext> context;
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
std::string libraryInfo;
|
||||||
|
std::string header;
|
||||||
|
std::string componentDirectory;
|
||||||
|
std::optional<std::string> componentHeader = nullopt;
|
||||||
|
std::vector<AddressSpace> addressSpaces;
|
||||||
|
std::vector<Component> components;
|
||||||
|
std::vector<Bus> buses;
|
||||||
|
std::vector<Connection> connections;
|
||||||
|
std::map<std::string, std::string> messages;
|
||||||
|
|
||||||
|
std::vector<SourceError> errors;
|
||||||
|
std::vector<FunctionValidator *> validators;
|
||||||
|
|
||||||
|
|
||||||
|
std::optional<AddressSpace> loadAddressSpace(AddressSpaceNode node);
|
||||||
|
std::optional<Component> loadComponent(ComponentNode node);
|
||||||
|
std::optional<Attribute> loadAttribute(AttributeNode node);
|
||||||
|
std::optional<Rule> loadRule(RuleNode node);
|
||||||
|
std::optional<Condition> loadCondition(ConditionNode node);
|
||||||
|
std::optional<Popup> loadPopup(PopupNode node, std::string name, Value::ValueType type);
|
||||||
|
std::optional<Display> loadDisplay(DisplayNode node);
|
||||||
|
std::optional<Wire> loadWire(WireNode node);
|
||||||
|
std::optional<Pin> loadPin(PinNode pins);
|
||||||
|
std::optional<Connection> loadConnection(ConnectionNode node);
|
||||||
|
std::optional<Bus> loadBus(BusNode node);
|
||||||
|
std::shared_ptr<ComponentInstance> loadComponentInstance(InstanceNode instance, Library &library);
|
||||||
|
std::shared_ptr<BusInstance> loadBusInstance(InstanceNode instance, Library &library);
|
||||||
|
|
||||||
|
/** Utility classes */
|
||||||
|
std::optional<Bus> getBus(std::string name);
|
||||||
|
std::optional<Pin> getComponentPin(std::string name, std::string pin);
|
||||||
|
bool hasAddressSpace(std::string name);
|
||||||
|
|
||||||
|
std::optional<Attribute> createMemoryAttribute();
|
||||||
|
vector<Enumeration> createWireEnumeration(vector<Value> enumeration);
|
||||||
|
std::optional<Popup> createMemoryPopup();
|
||||||
|
|
||||||
|
/** Context stack operations */
|
||||||
|
void push(ComdelContext context);
|
||||||
|
void pushAdditional(std::string name);
|
||||||
|
ComdelContext ¤t();
|
||||||
|
void pop();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace domain
|
||||||
|
|
||||||
|
#endif // DOMAIN_COMDEL_GENERATOR_H
|
|
@ -1,902 +0,0 @@
|
||||||
#include "schemacreator.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());
|
|
||||||
} else if(node.getType() == ValueNode::NIL) {
|
|
||||||
return Value::fromNull();
|
|
||||||
}
|
|
||||||
return Value::fromReference(node.asIdentifier(), Value::UNDEFINED);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Bus::BusType toType(BusNode::BusType type) {
|
|
||||||
if(type == BusNode::AUTOMATIC) {
|
|
||||||
return Bus::AUTOMATIC;
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
SchemaCreator::SchemaCreator(std::vector<FunctionSignature> signatures)
|
|
||||||
: signatures(signatures)
|
|
||||||
{}
|
|
||||||
|
|
||||||
std::optional<Library> SchemaCreator::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].value.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> SchemaCreator::loadBus(BusNode node)
|
|
||||||
{
|
|
||||||
std::string name = node.name.value;
|
|
||||||
|
|
||||||
auto count = std::make_pair<int, int>(1, 1);
|
|
||||||
if(node.count) {
|
|
||||||
count = std::make_pair<int, int>(node.count->first.value, node.count->second.value);
|
|
||||||
}
|
|
||||||
if(count.first > count.second || count.first < 0) {
|
|
||||||
errors.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(type == 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> SchemaCreator::loadAddressSpace(AddressSpaceNode node)
|
|
||||||
{
|
|
||||||
return AddressSpace(node.name.value, node.start.value, node.end.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<Connection> SchemaCreator::loadConnection(ConnectionNode node)
|
|
||||||
{
|
|
||||||
push(ComdelContext("connection", false, true, false));
|
|
||||||
|
|
||||||
std::string bus = node.bus.value;
|
|
||||||
auto busInstance = getBus(bus);
|
|
||||||
if(!busInstance) {
|
|
||||||
errors.emplace_back(node.span, "bus does not exist");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(busInstance->getType() == Bus::REGULAR) {
|
|
||||||
ConnectionComponent first{node.first.component.value, node.first.pin.value};
|
|
||||||
|
|
||||||
auto componentInstance = getComponentPin(first.component, first.pin);
|
|
||||||
if(!componentInstance) {
|
|
||||||
errors.emplace_back(node.span, "pin does not exist");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(node.second.has_value()) {
|
|
||||||
errors.emplace_back(node.span, "regular bus doesn't allow direct connections");
|
|
||||||
}
|
|
||||||
|
|
||||||
std::set<std::string> wireNames;
|
|
||||||
for(auto &wire: busInstance->getWires()) {
|
|
||||||
wireNames.insert(wire.getName());
|
|
||||||
current().wires.push_back(wire.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Attribute> attributes;
|
|
||||||
for(auto & attribute : node.attributes) {
|
|
||||||
auto attr = loadAttribute(attribute);
|
|
||||||
if(!attr) {
|
|
||||||
return nullopt;
|
|
||||||
}
|
|
||||||
attributes.push_back(*attr);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::set<std::string> attributeNames;
|
|
||||||
for(auto attribute: attributes) {
|
|
||||||
attributeNames.insert(attribute.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Value> wires;
|
|
||||||
for(auto & firstWire : node.firstWires) {
|
|
||||||
if(firstWire.is(ValueNode::NIL)) {
|
|
||||||
wires.push_back(Value::fromNull());
|
|
||||||
} else if(firstWire.is(ValueNode::INT)) {
|
|
||||||
wires.push_back(Value::fromInt(firstWire.asInt()));
|
|
||||||
} else if(firstWire.is(ValueNode::IDENTIFIER)) {
|
|
||||||
if(attributeNames.count(firstWire.asIdentifier())) {
|
|
||||||
wires.push_back(Value::fromReference(firstWire.asIdentifier(), Value::ATTRIBUTE_REFERENCE));
|
|
||||||
} else if(wireNames.count(firstWire.asIdentifier())) {
|
|
||||||
wires.push_back(Value::fromReference(firstWire.asIdentifier(), Value::WIRE_REFERENCE));
|
|
||||||
} else {
|
|
||||||
errors.emplace_back(firstWire.span, "unknown identifier");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
errors.emplace_back(firstWire.span, "unknown value type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pop();
|
|
||||||
|
|
||||||
return Connection(first, nullopt, bus, attributes, wires, nullopt);
|
|
||||||
} else if(busInstance->getType() == Bus::AUTOMATIC || busInstance->getType() == Bus::AUTOMATIC_SINGLE) {
|
|
||||||
ConnectionComponent first{node.first.component.value, node.first.pin.value};
|
|
||||||
|
|
||||||
if(!node.second.has_value()) {
|
|
||||||
errors.emplace_back(node.span, "missing second component");
|
|
||||||
}
|
|
||||||
|
|
||||||
ConnectionComponent second{node.second->component.value, node.second->pin.value};
|
|
||||||
|
|
||||||
auto firstComponentInstance = getComponentPin(first.component, first.pin);
|
|
||||||
if(!firstComponentInstance) {
|
|
||||||
errors.emplace_back(node.span, "pin does not exist");
|
|
||||||
}
|
|
||||||
|
|
||||||
auto secondComponentInstance = getComponentPin(second.component, second.pin);
|
|
||||||
if(!secondComponentInstance) {
|
|
||||||
errors.emplace_back(node.span, "pin does not exist");
|
|
||||||
}
|
|
||||||
|
|
||||||
std::set<std::string> wireNames;
|
|
||||||
for(auto &wire: busInstance->getWires()) {
|
|
||||||
wireNames.insert(wire.getName());
|
|
||||||
current().wires.push_back(wire.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Attribute> attributes;
|
|
||||||
for(auto & attribute : node.attributes) {
|
|
||||||
auto attr = loadAttribute(attribute);
|
|
||||||
if(!attr) {
|
|
||||||
return nullopt;
|
|
||||||
}
|
|
||||||
attributes.push_back(*attr);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::set<std::string> attributeNames;
|
|
||||||
for(auto attribute: attributes) {
|
|
||||||
attributeNames.insert(attribute.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Value> firstWires;
|
|
||||||
for(auto & firstWire : node.firstWires) {
|
|
||||||
if(firstWire.is(ValueNode::NIL)) {
|
|
||||||
firstWires.push_back(Value::fromNull());
|
|
||||||
} else if(firstWire.is(ValueNode::INT)) {
|
|
||||||
firstWires.push_back(Value::fromInt(firstWire.asInt()));
|
|
||||||
} else if(firstWire.is(ValueNode::IDENTIFIER)) {
|
|
||||||
if(attributeNames.count(firstWire.asIdentifier())) {
|
|
||||||
firstWires.push_back(Value::fromReference(firstWire.asIdentifier(), Value::ATTRIBUTE_REFERENCE));
|
|
||||||
} else if(wireNames.count(firstWire.asIdentifier())) {
|
|
||||||
firstWires.push_back(Value::fromReference(firstWire.asIdentifier(), Value::WIRE_REFERENCE));
|
|
||||||
} else {
|
|
||||||
errors.emplace_back(firstWire.span, "unknown identifier");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
errors.emplace_back(firstWire.span, "unknown value type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::vector<Value> secondWires;
|
|
||||||
for(auto & secondWire : *node.secondWires) {
|
|
||||||
if(secondWire.is(ValueNode::NIL)) {
|
|
||||||
secondWires.push_back(Value::fromNull());
|
|
||||||
} else if(secondWire.is(ValueNode::INT)) {
|
|
||||||
secondWires.push_back(Value::fromInt(secondWire.asInt()));
|
|
||||||
} else if(secondWire.is(ValueNode::IDENTIFIER)) {
|
|
||||||
if(attributeNames.count(secondWire.asIdentifier())) {
|
|
||||||
secondWires.push_back(Value::fromReference(secondWire.asIdentifier(), Value::ATTRIBUTE_REFERENCE));
|
|
||||||
} else if(wireNames.count(secondWire.asIdentifier())) {
|
|
||||||
secondWires.push_back(Value::fromReference(secondWire.asIdentifier(), Value::WIRE_REFERENCE));
|
|
||||||
} else {
|
|
||||||
errors.emplace_back(secondWire.span, "unknown identifier");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
errors.emplace_back(secondWire.span, "unknown value type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pop();
|
|
||||||
|
|
||||||
return Connection(first, second, bus, attributes, firstWires, secondWires);
|
|
||||||
}
|
|
||||||
pop();
|
|
||||||
errors.emplace_back(node.span, "unsupported connection type");
|
|
||||||
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<Component> SchemaCreator::loadComponent(ComponentNode node)
|
|
||||||
{
|
|
||||||
push(ComdelContext(node.name.value, true, false, false));
|
|
||||||
|
|
||||||
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> SchemaCreator::loadWire(WireNode node) {
|
|
||||||
return Wire(
|
|
||||||
node.name.value,
|
|
||||||
toType(node.type),
|
|
||||||
node.size.value,
|
|
||||||
node.hidden,
|
|
||||||
node.hasTermination,
|
|
||||||
node.isUnterminated
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
optional<Pin> SchemaCreator::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);
|
|
||||||
|
|
||||||
std::optional<std::vector<Value>> wiresOpt = std::nullopt;
|
|
||||||
if(node.wires.has_value()) {
|
|
||||||
auto nodeWires = node.wires.value();
|
|
||||||
std::vector<Value> wires;
|
|
||||||
for(auto &nodeWire : nodeWires) {
|
|
||||||
if(nodeWire.is(ValueNode::NIL)) {
|
|
||||||
wires.push_back(Value::fromNull());
|
|
||||||
} else if(nodeWire.is(ValueNode::INT)) {
|
|
||||||
wires.push_back(Value::fromInt(nodeWire.asInt()));
|
|
||||||
} else {
|
|
||||||
errors.emplace_back(node.span, "unknown value type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
wiresOpt = wires;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Pin(name, type, tooltip, connection, *display, wiresOpt);
|
|
||||||
}
|
|
||||||
|
|
||||||
int getIntProperty(DisplayItemNode &node, std::string property) {
|
|
||||||
for(auto& prop: node.values) {
|
|
||||||
if(prop.key.value == property) {
|
|
||||||
return prop.value.asInt();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw std::exception();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<Display> SchemaCreator::loadDisplay(DisplayNode node)
|
|
||||||
{
|
|
||||||
std::vector<ui::Item> items;
|
|
||||||
for(auto &item: node.items) {
|
|
||||||
ui::Item displayItem;
|
|
||||||
std::string type = item.type.value;
|
|
||||||
if(type == "rect") {
|
|
||||||
int x, y, w, h;
|
|
||||||
x = getIntProperty(item, "x");
|
|
||||||
y = getIntProperty(item, "y");
|
|
||||||
w = getIntProperty(item, "w");
|
|
||||||
h = getIntProperty(item, "h");
|
|
||||||
displayItem.rect = ui::Rect(x, y, w, h);
|
|
||||||
} else if(type == "line") {
|
|
||||||
int x1, y1, x2, y2;
|
|
||||||
x1 = getIntProperty(item, "x1");
|
|
||||||
y1 = getIntProperty(item, "y1");
|
|
||||||
x2 = getIntProperty(item, "x2");
|
|
||||||
y2 = getIntProperty(item, "y2");
|
|
||||||
displayItem.line = ui::Line(x1, y1, x2, y2);
|
|
||||||
} else if(type == "pin") {
|
|
||||||
int x, y, w, h;
|
|
||||||
x = getIntProperty(item, "x");
|
|
||||||
y = getIntProperty(item, "y");
|
|
||||||
w = getIntProperty(item, "w");
|
|
||||||
h = getIntProperty(item, "h");
|
|
||||||
displayItem.pin = ui::Pin(x, y, w, h);
|
|
||||||
} else {
|
|
||||||
errors.push_back(SourceError{item.type.span, "unsupported display type"});
|
|
||||||
}
|
|
||||||
items.push_back(displayItem);
|
|
||||||
}
|
|
||||||
return Display(items);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PinConnection SchemaCreator::loadPinConnection(PinConnectionNode node)
|
|
||||||
{
|
|
||||||
std::string message = node.message.asString();
|
|
||||||
PinConnection::ConnectionType type = toType(node.type);
|
|
||||||
return PinConnection(message, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<Attribute> SchemaCreator::loadAttribute(AttributeNode node)
|
|
||||||
{
|
|
||||||
std::string name = node.name.value;
|
|
||||||
pushAdditional(name);
|
|
||||||
Value value;
|
|
||||||
|
|
||||||
if(current().inComponent) {
|
|
||||||
if(node.type == ValueNode::INT) {
|
|
||||||
value = Value::fromInt(node.defaultValue->asInt());
|
|
||||||
} else if (node.type == ValueNode::BOOL) {
|
|
||||||
value = Value::fromBool(node.defaultValue->asBool());
|
|
||||||
} else if (node.type == ValueNode::STRING) {
|
|
||||||
value = Value::fromString(node.defaultValue->asString());
|
|
||||||
} else {
|
|
||||||
errors.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> SchemaCreator::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(type == Value::INT || type == Value::STRING || type == Value::BOOL) {
|
|
||||||
auto value = toType(node.enumeration[i].value);
|
|
||||||
if(value.getType() == type) {
|
|
||||||
enumeration.push_back(Enumeration(node.enumeration[i].key.asString(), value));
|
|
||||||
} else {
|
|
||||||
errors.push_back(SourceError{node.enumeration[i].span, "wrong type"});
|
|
||||||
}
|
|
||||||
} else if(type == Value::WIRE_REFERENCE) {
|
|
||||||
auto value = toType(node.enumeration[i].value);
|
|
||||||
if(value.isType(Value::UNDEFINED)) {
|
|
||||||
if(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.isType(Value::WIRE_REFERENCE) || value.isType(Value::INT) || value.isType(Value::NIL)) {
|
|
||||||
enumeration.push_back(Enumeration(node.enumeration[i].key.asString(), value));
|
|
||||||
} else {
|
|
||||||
errors.push_back(SourceError{node.enumeration[i].span, "wrong type"});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if(type == Value::WIRE_REFERENCE && !current().inConnection) {
|
|
||||||
errors.push_back(SourceError{node.span, "@enumeration is required for attributes of type wire"});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pop();
|
|
||||||
|
|
||||||
return Popup(title, text, popupType, rules, enumeration);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<Rule> SchemaCreator::loadRule(RuleNode node)
|
|
||||||
{
|
|
||||||
std::vector<IfStatement> statements;
|
|
||||||
|
|
||||||
for(auto& stmt: node.statements) {
|
|
||||||
auto condition = loadCondition(stmt.condition);
|
|
||||||
if(condition) {
|
|
||||||
statements.push_back(IfStatement(*condition, Action(toType(stmt.action.type), stmt.action.message.asString())));
|
|
||||||
} else {
|
|
||||||
return nullopt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Rule(statements);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<Condition> SchemaCreator::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_REFERENCE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 parameters"});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
errors.push_back(SourceError{node.functionName.span, "unknown function name"});
|
|
||||||
return nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Schema* SchemaCreator::loadSchema(SchemaNode node, Library &library)
|
|
||||||
{
|
|
||||||
Schema *schema = new 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 firstComponent = dynamic_cast<ComponentInstance*>(schema->getInstance(conn.first.instance.value));
|
|
||||||
if(firstComponent == NULL) {
|
|
||||||
errors.push_back(SourceError{conn.first.instance.span, "unknown component"});
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if(!firstComponent->component.hasPin(conn.first.pin.value)) {
|
|
||||||
errors.push_back(SourceError{conn.first.pin.span, "unknown pin"});
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ComponentInstance *secondComponent = NULL;
|
|
||||||
if(conn.second.has_value()) {
|
|
||||||
secondComponent = dynamic_cast<ComponentInstance*>(schema->getInstance(conn.second->instance.value));
|
|
||||||
if(secondComponent == NULL) {
|
|
||||||
errors.push_back(SourceError{conn.second->instance.span, "unknown component"});
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if(!secondComponent->component.hasPin(conn.second->pin.value)) {
|
|
||||||
errors.push_back(SourceError{conn.second->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;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<Connection> connection = std::nullopt;
|
|
||||||
if(secondComponent != NULL) {
|
|
||||||
ConnectionComponent firstConn{firstComponent->component.getName(), conn.first.pin.value};
|
|
||||||
ConnectionComponent secondConn{secondComponent->component.getName(), conn.second->pin.value};
|
|
||||||
|
|
||||||
if(library.hasConnection(firstConn,
|
|
||||||
bus->bus.getName(),
|
|
||||||
secondConn)) {
|
|
||||||
connection = *library.getConnection(firstConn, bus->bus.getName(), secondConn);
|
|
||||||
} else {
|
|
||||||
errors.push_back(SourceError{conn.span, "unknown connection"});
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ConnectionComponent firstConn{firstComponent->component.getName(), conn.first.pin.value};
|
|
||||||
|
|
||||||
if(library.hasConnection(firstConn,
|
|
||||||
bus->bus.getName())) {
|
|
||||||
connection = *library.getConnection(firstConn, bus->bus.getName());
|
|
||||||
} else {
|
|
||||||
errors.push_back(SourceError{conn.span, "unknown connection"});
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(secondComponent == NULL) {
|
|
||||||
schema->connections.push_back(new BusConnectionInstance(firstComponent, attributes, bus, wire, *connection));
|
|
||||||
} else {
|
|
||||||
schema->connections.push_back(new DirectConnectionInstance(firstComponent, secondComponent, attributes, bus, wire, *connection));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return schema;
|
|
||||||
}
|
|
||||||
|
|
||||||
ComponentInstance *SchemaCreator::loadComponentInstance(InstanceNode instance, Library &library) {
|
|
||||||
|
|
||||||
auto name = instance.name.value;
|
|
||||||
auto position = std::make_pair(instance.position->first.value, instance.position->second.value);
|
|
||||||
|
|
||||||
auto component = library.getComponent(instance.component.value);
|
|
||||||
|
|
||||||
// validate attributes
|
|
||||||
std::vector<InstanceAttribute*> attributes;
|
|
||||||
for(auto& attr: instance.attributes) {
|
|
||||||
if(component.hasAttribute(attr.name.value, toType(attr.value.getType()))) {
|
|
||||||
auto attribute = component.getAttribute(attr.name.value);
|
|
||||||
attributes.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 *SchemaCreator::loadBusInstance(InstanceNode instance, Library &library) {
|
|
||||||
|
|
||||||
auto name = instance.name.value;
|
|
||||||
auto position = std::make_pair(instance.position->first.value, instance.position->second.value);
|
|
||||||
|
|
||||||
auto bus = library.getBus(instance.component.value);
|
|
||||||
|
|
||||||
long long size = 0;
|
|
||||||
if(instance.size) {
|
|
||||||
size = instance.size->value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new BusInstance(name, position, bus, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<WireInstance*> SchemaCreator::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;
|
|
||||||
}
|
|
||||||
std::pair<int, int> position = std::make_pair(0, 0);
|
|
||||||
if(node.position) {
|
|
||||||
position = std::make_pair(node.position->first.value, node.position->second.value);
|
|
||||||
}
|
|
||||||
return std::optional<WireInstance*>(new WireInstance(node.name.value, *display, position));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace domain
|
|
|
@ -1,146 +0,0 @@
|
||||||
#ifndef DOMAIN_COMDEL_GENERATOR_H
|
|
||||||
#define DOMAIN_COMDEL_GENERATOR_H
|
|
||||||
|
|
||||||
#include "library.h"
|
|
||||||
#include "schema.h"
|
|
||||||
|
|
||||||
#include <set>
|
|
||||||
|
|
||||||
#include <comdel/parser/astnode.h>
|
|
||||||
#include <comdel/parser/parsecontext.h>
|
|
||||||
#include <comdel/parser/presult.h>
|
|
||||||
|
|
||||||
namespace domain {
|
|
||||||
|
|
||||||
struct ComdelContext {
|
|
||||||
std::vector<Attribute> attributes;
|
|
||||||
std::vector<std::string> wires;
|
|
||||||
std::string name;
|
|
||||||
bool inComponent;
|
|
||||||
bool inConnection;
|
|
||||||
bool 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 SchemaCreator
|
|
||||||
{
|
|
||||||
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 ¤t() {
|
|
||||||
return this->context[this->context.size() - 1];
|
|
||||||
}
|
|
||||||
void pop() {
|
|
||||||
this->context.pop_back();
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
SchemaCreator(std::vector<FunctionSignature> signatures);
|
|
||||||
|
|
||||||
std::vector<SourceError> getErrors() {
|
|
||||||
return errors;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<Library> loadLibrary(LibraryNode node);
|
|
||||||
|
|
||||||
Schema* loadSchema(SchemaNode node, Library &library);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace domain
|
|
||||||
|
|
||||||
#endif // DOMAIN_COMDEL_GENERATOR_H
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "value.h"
|
#include "value.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace domain {
|
namespace domain {
|
||||||
|
|
||||||
|
@ -24,6 +25,12 @@ std::string Value::string() {
|
||||||
return "AddressSpace::" + reference;
|
return "AddressSpace::" + reference;
|
||||||
case ATTRIBUTE_REFERENCE:
|
case ATTRIBUTE_REFERENCE:
|
||||||
return "Attribute::" + reference;
|
return "Attribute::" + reference;
|
||||||
|
case MEMORY_REFERENCE:
|
||||||
|
if (memoryReference.has_value()) {
|
||||||
|
return "Memory::" + *memoryReference;
|
||||||
|
} else {
|
||||||
|
return "Memory::null";
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return "unknown";
|
return "unknown";
|
||||||
}
|
}
|
||||||
|
@ -33,64 +40,112 @@ std::string Value::string() {
|
||||||
Value::ValueType Value::getType() {
|
Value::ValueType Value::getType() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
bool Value::isType(Value::ValueType type) {
|
|
||||||
return this->type == type;
|
bool Value::isType(Value::ValueType _type) {
|
||||||
|
return type == _type;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Value::getTypename() {
|
||||||
|
switch (type) {
|
||||||
|
case Value::BOOL:
|
||||||
|
return "bool";
|
||||||
|
case Value::INT:
|
||||||
|
return "int";
|
||||||
|
case Value::STRING:
|
||||||
|
return "string";
|
||||||
|
case Value::ADDRESS_SPACE:
|
||||||
|
case Value::ADDRESS_SPACE_REFERENCE:
|
||||||
|
return "address space";
|
||||||
|
case Value::WIRE_REFERENCE:
|
||||||
|
return "wire reference";
|
||||||
|
case Value::ATTRIBUTE_REFERENCE:
|
||||||
|
return "attribute";
|
||||||
|
case Value::NIL:
|
||||||
|
return "null";
|
||||||
|
case Value::MEMORY:
|
||||||
|
case Value::MEMORY_REFERENCE:
|
||||||
|
return "memory";
|
||||||
|
case Value::UNDEFINED:
|
||||||
|
return "undefined";
|
||||||
|
}
|
||||||
|
return "unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
long long Value::asInt() {
|
long long Value::asInt() {
|
||||||
if (isType(Value::INT)) {
|
if (isType(Value::INT)) {
|
||||||
return intValue;
|
return intValue;
|
||||||
}
|
}
|
||||||
throw std::exception();
|
throw std::runtime_error("expected 'int' but value contains '" + getTypename() + "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Value::asString() {
|
std::string Value::asString() {
|
||||||
if (isType(Value::STRING)) {
|
if (isType(Value::STRING)) {
|
||||||
return stringValue;
|
return stringValue;
|
||||||
}
|
}
|
||||||
throw std::exception();
|
throw std::runtime_error("expected 'string' but value contains '" + getTypename() + "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Value::asBool() {
|
bool Value::asBool() {
|
||||||
if (isType(Value::BOOL)) {
|
if (isType(Value::BOOL)) {
|
||||||
return boolValue;
|
return boolValue;
|
||||||
}
|
}
|
||||||
throw std::exception();
|
throw std::runtime_error("expected 'bool' but value contains '" + getTypename() + "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
AddressSpace Value::asAddressSpace() {
|
AddressSpace Value::asAddressSpace() {
|
||||||
if (isType(Value::ADDRESS_SPACE)) {
|
if (isType(Value::ADDRESS_SPACE)) {
|
||||||
return *addressSpace;
|
return *addressSpace;
|
||||||
}
|
}
|
||||||
throw std::exception();
|
throw std::runtime_error("expected 'address space' but value contains '" + getTypename() + "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Value::asReference() {
|
std::string Value::asReference() {
|
||||||
if(isType(Value::WIRE_REFERENCE) || isType(Value::ADDRESS_SPACE_REFERENCE) || isType(Value::ATTRIBUTE_REFERENCE) || isType(Value::UNDEFINED)) {
|
if (isType(Value::WIRE_REFERENCE) || isType(Value::ADDRESS_SPACE_REFERENCE) ||
|
||||||
|
isType(Value::ATTRIBUTE_REFERENCE) || isType(Value::UNDEFINED)) {
|
||||||
return reference;
|
return reference;
|
||||||
}
|
}
|
||||||
throw std::exception();
|
throw std::runtime_error("expected 'reference' but value contains '" + getTypename() + "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<std::string> Value::asMemoryReference() {
|
||||||
|
return memoryReference;
|
||||||
|
}
|
||||||
|
|
||||||
|
domain::ComponentInstance *Value::asMemory() {
|
||||||
|
return memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Value::setInt(long long value) {
|
void Value::setInt(long long value) {
|
||||||
if (isType(Value::INT)) {
|
if (isType(Value::INT)) {
|
||||||
this->intValue = value;
|
this->intValue = value;
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("expected to set 'int' but value contains '" + getTypename() + "'");
|
||||||
}
|
}
|
||||||
throw std::exception();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Value::setString(std::string value) {
|
void Value::setString(std::string value) {
|
||||||
if (isType(Value::STRING)) {
|
if (isType(Value::STRING)) {
|
||||||
this->stringValue = value;
|
this->stringValue = value;
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("expected to set 'string' but value contains '" + getTypename() + "'");
|
||||||
}
|
}
|
||||||
throw std::exception();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Value::setBool(bool value) {
|
void Value::setBool(bool value) {
|
||||||
if (isType(Value::BOOL)) {
|
if (isType(Value::BOOL)) {
|
||||||
this->boolValue = value;
|
this->boolValue = value;
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("expected to set 'bool' but value contains '" + getTypename() + "'");
|
||||||
}
|
}
|
||||||
throw std::exception();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Value::setReference(std::string value) {
|
void Value::setReference(std::string value) {
|
||||||
if (isType(Value::WIRE_REFERENCE)) {
|
if (isType(Value::WIRE_REFERENCE)) {
|
||||||
this->reference = value;
|
this->reference = value;
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("expected to set 'wire' but value contains '" + getTypename() + "'");
|
||||||
}
|
}
|
||||||
throw std::exception();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -100,36 +155,34 @@ Value Value::fromInt(long long value) {
|
||||||
val.intValue = value;
|
val.intValue = value;
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value Value::fromString(std::string value) {
|
Value Value::fromString(std::string value) {
|
||||||
Value val;
|
Value val;
|
||||||
val.type = Value::STRING;
|
val.type = Value::STRING;
|
||||||
val.stringValue = value;
|
val.stringValue = value;
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value Value::fromBool(bool value) {
|
Value Value::fromBool(bool value) {
|
||||||
Value val;
|
Value val;
|
||||||
val.type = Value::BOOL;
|
val.type = Value::BOOL;
|
||||||
val.boolValue = value;
|
val.boolValue = value;
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value Value::fromAddressSpace(AddressSpace addressSpace) {
|
Value Value::fromAddressSpace(AddressSpace addressSpace) {
|
||||||
Value val;
|
Value val;
|
||||||
val.type = Value::ADDRESS_SPACE;
|
val.type = Value::ADDRESS_SPACE;
|
||||||
val.addressSpace = addressSpace;
|
val.addressSpace = addressSpace;
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value Value::fromReference(std::string value, Value::ValueType type) {
|
Value Value::fromReference(std::string value, Value::ValueType type) {
|
||||||
Value val;
|
Value val;
|
||||||
val.type = type;
|
val.type = type;
|
||||||
val.reference = value;
|
val.reference = value;
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
Value Value::ofType(Value::ValueType type) {
|
|
||||||
Value val;
|
|
||||||
val.type = type;
|
|
||||||
return val;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Value Value::fromNull() {
|
Value Value::fromNull() {
|
||||||
Value val;
|
Value val;
|
||||||
|
@ -137,4 +190,69 @@ Value Value::fromNull() {
|
||||||
return val;
|
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::runtime_error("unknown type couldn't stringify '" + getTypename() + "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Value Value::ofType(Value::ValueType type) {
|
||||||
|
Value val;
|
||||||
|
val.type = type;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Value::equals(Value value) {
|
||||||
|
if (value.getType() == type) {
|
||||||
|
switch (type) {
|
||||||
|
case INT:
|
||||||
|
return value.asInt() == intValue;
|
||||||
|
case STRING:
|
||||||
|
return value.asString() == stringValue;
|
||||||
|
case NIL:
|
||||||
|
case UNDEFINED:
|
||||||
|
return true;
|
||||||
|
case WIRE_REFERENCE:
|
||||||
|
case ATTRIBUTE_REFERENCE:
|
||||||
|
case ADDRESS_SPACE_REFERENCE:
|
||||||
|
return value.asReference() == reference;
|
||||||
|
case MEMORY_REFERENCE:
|
||||||
|
return value.asMemoryReference() == memoryReference;
|
||||||
|
case MEMORY:
|
||||||
|
return value.asMemory() == memory;
|
||||||
|
case BOOL:
|
||||||
|
return value.asBool() == boolValue;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace domain
|
} // namespace domain
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef DOMAIN_VALUE_H
|
#ifndef DOMAIN_VALUE_H
|
||||||
#define DOMAIN_VALUE_H
|
#define DOMAIN_VALUE_H
|
||||||
|
|
||||||
#include "addressspace.h"
|
#include "address_space.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
@ -9,8 +9,9 @@
|
||||||
|
|
||||||
namespace domain {
|
namespace domain {
|
||||||
|
|
||||||
class Value
|
class ComponentInstance;
|
||||||
{
|
|
||||||
|
class Value {
|
||||||
public:
|
public:
|
||||||
enum ValueType {
|
enum ValueType {
|
||||||
INT,
|
INT,
|
||||||
|
@ -19,48 +20,76 @@ public:
|
||||||
ADDRESS_SPACE,
|
ADDRESS_SPACE,
|
||||||
ADDRESS_SPACE_REFERENCE,
|
ADDRESS_SPACE_REFERENCE,
|
||||||
ATTRIBUTE_REFERENCE,
|
ATTRIBUTE_REFERENCE,
|
||||||
|
MEMORY_REFERENCE,
|
||||||
|
MEMORY,
|
||||||
WIRE_REFERENCE,
|
WIRE_REFERENCE,
|
||||||
NIL,
|
NIL,
|
||||||
UNDEFINED,
|
UNDEFINED,
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
long long intValue;
|
long long intValue = 0;
|
||||||
std::string stringValue;
|
std::string stringValue;
|
||||||
bool boolValue;
|
bool boolValue = false;
|
||||||
std::optional<AddressSpace> addressSpace;
|
std::optional<AddressSpace> addressSpace = std::nullopt;
|
||||||
std::string reference;
|
std::string reference;
|
||||||
|
domain::ComponentInstance *memory = nullptr;
|
||||||
|
|
||||||
ValueType type;
|
std::optional<std::string> memoryReference = std::nullopt;
|
||||||
|
|
||||||
|
ValueType type = UNDEFINED;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Value() {
|
Value() = default;
|
||||||
this->type = UNDEFINED;
|
|
||||||
}
|
bool equals(Value value);
|
||||||
|
|
||||||
std::string string();
|
std::string string();
|
||||||
|
std::string getTypename();
|
||||||
|
|
||||||
ValueType getType();
|
ValueType getType();
|
||||||
|
|
||||||
bool isType(ValueType type);
|
bool isType(ValueType type);
|
||||||
|
|
||||||
long long asInt();
|
long long asInt();
|
||||||
|
|
||||||
std::string asString();
|
std::string asString();
|
||||||
|
|
||||||
bool asBool();
|
bool asBool();
|
||||||
|
|
||||||
std::string asReference();
|
std::string asReference();
|
||||||
|
|
||||||
|
std::optional<std::string> asMemoryReference();
|
||||||
|
|
||||||
|
domain::ComponentInstance *asMemory();
|
||||||
|
|
||||||
AddressSpace asAddressSpace();
|
AddressSpace asAddressSpace();
|
||||||
|
|
||||||
void setInt(long long intValue);
|
void setInt(long long intValue);
|
||||||
|
|
||||||
void setString(std::string value);
|
void setString(std::string value);
|
||||||
|
|
||||||
void setBool(bool value);
|
void setBool(bool value);
|
||||||
|
|
||||||
void setReference(std::string value);
|
void setReference(std::string value);
|
||||||
|
|
||||||
|
std::string stringify();
|
||||||
|
|
||||||
static Value fromInt(long long value);
|
static Value fromInt(long long value);
|
||||||
|
|
||||||
static Value fromString(std::string value);
|
static Value fromString(std::string value);
|
||||||
|
|
||||||
static Value fromBool(bool value);
|
static Value fromBool(bool value);
|
||||||
|
|
||||||
static Value fromNull();
|
static Value fromNull();
|
||||||
|
|
||||||
static Value fromAddressSpace(AddressSpace addressSpace);
|
static Value fromAddressSpace(AddressSpace addressSpace);
|
||||||
|
|
||||||
static Value fromReference(std::string value, ValueType type);
|
static Value fromReference(std::string value, ValueType type);
|
||||||
|
|
||||||
|
static Value fromMemoryReference(std::optional<std::string> memoryReference);
|
||||||
|
|
||||||
static Value ofType(ValueType type);
|
static Value ofType(ValueType type);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
#include "wireinstance.h"
|
|
||||||
|
|
||||||
namespace domain {
|
|
||||||
|
|
||||||
WireInstance::WireInstance(std::string name, Display display, std::pair<int, int> position)
|
|
||||||
: name(name), display(display), position(position)
|
|
||||||
{}
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace domain
|
|
|
@ -1,24 +0,0 @@
|
||||||
#ifndef DOMAIN_WIRE_INSTANCE_H
|
|
||||||
#define DOMAIN_WIRE_INSTANCE_H
|
|
||||||
|
|
||||||
#include "display.h"
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace domain {
|
|
||||||
|
|
||||||
class WireInstance
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
std::string name;
|
|
||||||
Display display;
|
|
||||||
std::pair<int, int> position;
|
|
||||||
|
|
||||||
WireInstance(std::string name, Display display, std::pair<int, int> position);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace domain
|
|
||||||
|
|
||||||
#endif // DOMAIN_WIREINSTANCE_H
|
|
|
@ -0,0 +1,172 @@
|
||||||
|
#include "ast_nodes.h"
|
||||||
|
|
||||||
|
/*************************** NUMBER NODE ********************************/
|
||||||
|
|
||||||
|
NumberNode::NumberNode(const std::string &expression) {
|
||||||
|
if (expression.size() > 2) {
|
||||||
|
if (expression.substr(0, 2) == "0x") {
|
||||||
|
this->value = std::stoll(expression, nullptr, 16);
|
||||||
|
} else if (expression.substr(0, 2) == "0b") {
|
||||||
|
this->value = std::stoll(expression, nullptr, 2);
|
||||||
|
} else {
|
||||||
|
this->value = std::stoll(expression, nullptr, 10);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this->value = std::stoll(expression, nullptr, 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************** COLOR NODE *********************************/
|
||||||
|
|
||||||
|
ColorNode::ColorNode(const std::string &expression) {
|
||||||
|
auto value = expression.substr(1);
|
||||||
|
color.r = std::stoul(value.substr(0, 2), nullptr, 16);
|
||||||
|
color.g = std::stoul(value.substr(2, 4), nullptr, 16);
|
||||||
|
color.b = std::stoul(value.substr(4, 6), nullptr, 16);
|
||||||
|
color.a = 255;
|
||||||
|
if(value.length() == 8) {
|
||||||
|
color.a = std::stoul(value.substr(6,8), nullptr, 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************** STRING NODE ********************************/
|
||||||
|
|
||||||
|
std::string StringNode::asString() {
|
||||||
|
return value.substr(1, value.length() - 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************** VALUE NODE ********************************/
|
||||||
|
|
||||||
|
ValueNode::ValueType ValueNode::getType() const {
|
||||||
|
return type.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
long long int ValueNode::asInt() {
|
||||||
|
if (is(INT)) {
|
||||||
|
return intValue.value();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ValueNode::asString() {
|
||||||
|
if (is(STRING)) {
|
||||||
|
return stringValue.value();
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ValueNode::asIdentifier() {
|
||||||
|
if (is(IDENTIFIER) || is(WIRE)) {
|
||||||
|
return identifierValue.value();
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
Color ValueNode::asColor() {
|
||||||
|
if (is(COLOR)) {
|
||||||
|
return colorValue.value();
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool ValueNode::asBool() {
|
||||||
|
if (is(BOOL)) {
|
||||||
|
return boolValue.value();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ValueNode::is(ValueNode::ValueType valueType) {
|
||||||
|
return type.value == valueType;
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueNode ValueNode::ofBool(bool _value) {
|
||||||
|
ValueNode value;
|
||||||
|
value.type = EnumNode(BOOL);
|
||||||
|
value.boolValue = std::optional<bool>(_value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueNode ValueNode::ofInt(long long int _value) {
|
||||||
|
ValueNode value;
|
||||||
|
value.type = EnumNode(INT);
|
||||||
|
value.intValue = std::optional<long long>(_value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueNode ValueNode::ofString(std::string _value) {
|
||||||
|
ValueNode value;
|
||||||
|
value.type = EnumNode(STRING);
|
||||||
|
value.stringValue = std::optional<std::string>(_value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueNode ValueNode::ofIdentifier(std::string _value) {
|
||||||
|
ValueNode value;
|
||||||
|
value.type = EnumNode(IDENTIFIER);
|
||||||
|
value.identifierValue = std::optional<std::string>(_value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueNode ValueNode::ofNull() {
|
||||||
|
ValueNode value;
|
||||||
|
value.type = EnumNode(NIL);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueNode ValueNode::ofColor(Color color) {
|
||||||
|
ValueNode value;
|
||||||
|
value.type = EnumNode(COLOR);
|
||||||
|
value.colorValue = color;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueNode ValueNode::ofWire(std::optional<std::string> _value) {
|
||||||
|
ValueNode value;
|
||||||
|
value.type = EnumNode(WIRE);
|
||||||
|
value.identifierValue = _value;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueNode ValueNode::ofMemory(std::optional<std::string> _value) {
|
||||||
|
ValueNode value;
|
||||||
|
value.type = EnumNode(MEMORY);
|
||||||
|
value.identifierValue = _value;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************** DisplayItem NODE ********************************/
|
||||||
|
|
||||||
|
std::optional<long long int> DisplayItemNode::asInt(const std::string &property, long long int _default) {
|
||||||
|
auto prop = getProperty(property);
|
||||||
|
if(prop.has_value()) {
|
||||||
|
return prop->value.is(ValueNode::INT) ? std::optional(prop->value.asInt()) : std::nullopt;
|
||||||
|
}
|
||||||
|
return _default;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<Color> DisplayItemNode::asColor(const std::string &property, Color _default) {
|
||||||
|
auto prop = getProperty(property);
|
||||||
|
if(prop.has_value()) {
|
||||||
|
return prop->value.is(ValueNode::COLOR) ? std::optional(prop->value.asColor()) : std::nullopt;
|
||||||
|
}
|
||||||
|
return _default;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::string> DisplayItemNode::asString(const std::string &property, std::string _default) {
|
||||||
|
auto prop = getProperty(property);
|
||||||
|
if(prop.has_value()) {
|
||||||
|
return prop->value.is(ValueNode::STRING) ? std::optional(prop->value.asString()) : std::nullopt;
|
||||||
|
}
|
||||||
|
return _default;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<PropertyNode> DisplayItemNode::getProperty(const std::string &property) {
|
||||||
|
for(auto &prop: values) {
|
||||||
|
if(prop.key.value == property) {
|
||||||
|
return prop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
|
@ -0,0 +1,553 @@
|
||||||
|
#ifndef AST_NODE_H
|
||||||
|
#define AST_NODE_H
|
||||||
|
|
||||||
|
#include "token.h"
|
||||||
|
#include "color.h"
|
||||||
|
#include "source_error.h"
|
||||||
|
#include <optional>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* BASE TYPES *
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AST base class, all AST node classes extend this class. Class contains basic
|
||||||
|
* information about nodes location in file.
|
||||||
|
*/
|
||||||
|
class AstNode {
|
||||||
|
public:
|
||||||
|
/** Contains information about where in source file given node is located */
|
||||||
|
Span span;
|
||||||
|
|
||||||
|
AstNode() = default;
|
||||||
|
AstNode(AstNode &&) = default;
|
||||||
|
AstNode &operator=(AstNode &&) = default;
|
||||||
|
AstNode(const AstNode &) = default;
|
||||||
|
AstNode &operator=(const AstNode &) = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AST base enum class,
|
||||||
|
* Used to represent AST enums
|
||||||
|
* */
|
||||||
|
template<typename T>
|
||||||
|
struct EnumNode : public AstNode {
|
||||||
|
EnumNode() = default;
|
||||||
|
|
||||||
|
explicit EnumNode(T value) : value(value) {}
|
||||||
|
|
||||||
|
T value;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Represents string
|
||||||
|
* value contains quote-marks ("" or '' depending on string type)
|
||||||
|
* */
|
||||||
|
struct StringNode : public AstNode {
|
||||||
|
/** String including quote-marks*/
|
||||||
|
std::string value;
|
||||||
|
|
||||||
|
/** Returns string without quote-marks */
|
||||||
|
std::string asString();
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Represents identifiers */
|
||||||
|
struct IdentifierNode : public AstNode {
|
||||||
|
std::string value;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Represents all numbers used
|
||||||
|
* All numbers must fit into long long int
|
||||||
|
* */
|
||||||
|
struct NumberNode : public AstNode {
|
||||||
|
long long int value = 0;
|
||||||
|
|
||||||
|
explicit NumberNode(const std::string &expression);
|
||||||
|
|
||||||
|
NumberNode() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Represents color
|
||||||
|
* color comes in two formats #RRGGBB or #RRGGBBAA (AA representing opacity)
|
||||||
|
* */
|
||||||
|
struct ColorNode : public AstNode {
|
||||||
|
Color color;
|
||||||
|
|
||||||
|
explicit ColorNode(const std::string &expression);
|
||||||
|
|
||||||
|
ColorNode() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Represents ordered number pair */
|
||||||
|
struct NumberPairNode : public AstNode {
|
||||||
|
NumberNode first;
|
||||||
|
NumberNode second;
|
||||||
|
|
||||||
|
NumberPairNode(NumberNode first, NumberNode second) : first(first), second(second) {}
|
||||||
|
|
||||||
|
NumberPairNode() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Represents generic value
|
||||||
|
* Because attributes can contain different value types,
|
||||||
|
* this allows us to use one generic type for all attributes
|
||||||
|
* */
|
||||||
|
class ValueNode : public AstNode {
|
||||||
|
public:
|
||||||
|
enum ValueType {
|
||||||
|
/** Stores same content as NumberNode */
|
||||||
|
INT,
|
||||||
|
/** Stores same content as StringNode */
|
||||||
|
STRING,
|
||||||
|
/** Stores true or false */
|
||||||
|
BOOL,
|
||||||
|
/** Stores wire nam or null */
|
||||||
|
WIRE,
|
||||||
|
/** Default type assigned when node value is of type IdentifierNode and more correct type is assigned later */
|
||||||
|
IDENTIFIER,
|
||||||
|
/** Stores memory name or null */
|
||||||
|
MEMORY,
|
||||||
|
/** Stores null */
|
||||||
|
NIL,
|
||||||
|
/** Store same content as ColorNode */
|
||||||
|
COLOR,
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
/** Type determines what is stored inside ValueNode */
|
||||||
|
EnumNode<ValueType> type = EnumNode(NIL);
|
||||||
|
/** All possible values for ValueNode are stored inside optionals */
|
||||||
|
std::optional<long long> intValue = std::nullopt;
|
||||||
|
std::optional<std::string> stringValue = std::nullopt;
|
||||||
|
std::optional<bool> boolValue = std::nullopt;
|
||||||
|
std::optional<std::string> identifierValue = std::nullopt;
|
||||||
|
std::optional<Color> colorValue = std::nullopt;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ValueNode() = default;
|
||||||
|
|
||||||
|
ValueType getType() const;
|
||||||
|
|
||||||
|
/** Checks ValueNode is of requested type and returns it or returns default value for given type*/
|
||||||
|
long long int asInt();
|
||||||
|
std::string asString();
|
||||||
|
std::string asIdentifier();
|
||||||
|
Color asColor();
|
||||||
|
bool asBool();
|
||||||
|
|
||||||
|
/** Returns true if ValueNode is of given valueType */
|
||||||
|
bool is(ValueType valueType);
|
||||||
|
|
||||||
|
/** Static methods used to generate ValueNodes of requested type */
|
||||||
|
static ValueNode ofBool(bool _value);
|
||||||
|
static ValueNode ofInt(long long _value);
|
||||||
|
static ValueNode ofString(std::string _value);
|
||||||
|
static ValueNode ofIdentifier(std::string _value);
|
||||||
|
static ValueNode ofMemory(std::optional<std::string> _value);
|
||||||
|
static ValueNode ofNull();
|
||||||
|
static ValueNode ofColor(Color color);
|
||||||
|
static ValueNode ofWire(std::optional<std::string> _value);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Represents an identifier-value pair*/
|
||||||
|
struct PropertyNode : public AstNode {
|
||||||
|
IdentifierNode key;
|
||||||
|
ValueNode value;
|
||||||
|
|
||||||
|
PropertyNode() = default;
|
||||||
|
PropertyNode(IdentifierNode key, ValueNode value): key(key), value(value) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Represents a string-value pair */
|
||||||
|
struct StringPropertyNode : public AstNode {
|
||||||
|
StringNode key;
|
||||||
|
ValueNode value;
|
||||||
|
|
||||||
|
StringPropertyNode() = default;
|
||||||
|
StringPropertyNode(StringNode key, ValueNode value): key(key), value(value) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* RULE TYPES *
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
struct IfStatementNode;
|
||||||
|
|
||||||
|
/** Represents validation rule
|
||||||
|
* Rules are made from a list of
|
||||||
|
* if - else if statements
|
||||||
|
* */
|
||||||
|
struct RuleNode : public AstNode {
|
||||||
|
std::vector<IfStatementNode> statements;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Represents condition inside if statement
|
||||||
|
* Every condition is made from optional negation operator !
|
||||||
|
* Function called and list of function parameters
|
||||||
|
* */
|
||||||
|
struct ConditionNode {
|
||||||
|
bool negated;
|
||||||
|
IdentifierNode functionName;
|
||||||
|
std::vector<ValueNode> params;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Represents action executed inside if statement
|
||||||
|
* */
|
||||||
|
struct ActionNode : public AstNode {
|
||||||
|
/** There are two types of action determined by action type */
|
||||||
|
enum ActionType {
|
||||||
|
/** Error actions represent invalid state and cause validation to fail */
|
||||||
|
ERROR,
|
||||||
|
/** Warning actions represent states that can cause issue when simulating
|
||||||
|
* model but models created with it are still valid
|
||||||
|
* */
|
||||||
|
WARNING
|
||||||
|
};
|
||||||
|
|
||||||
|
EnumNode<ActionType> type;
|
||||||
|
/** Message used if condition is fulfilled */
|
||||||
|
StringNode message;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** If statements represents one validation check inside rule */
|
||||||
|
struct IfStatementNode : public AstNode {
|
||||||
|
ConditionNode condition;
|
||||||
|
ActionNode action;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* ATTRIBUTE TYPES *
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
/** Represents popup dialog used to modified attribute inside which it is defined
|
||||||
|
* */
|
||||||
|
struct PopupNode : public AstNode {
|
||||||
|
/** Determines type of popup*/
|
||||||
|
enum PopupType {
|
||||||
|
/** Automatic popup is opened when component or connection containing it is defined */
|
||||||
|
AUTOMATIC,
|
||||||
|
/** On demand popups are opened on user request usually from context menus*/
|
||||||
|
ON_DEMAND
|
||||||
|
};
|
||||||
|
|
||||||
|
std::optional<EnumNode<PopupType>> type;
|
||||||
|
/** Title of popup */
|
||||||
|
std::optional<StringNode> title;
|
||||||
|
/** Text of popup */
|
||||||
|
std::optional<StringNode> text;
|
||||||
|
|
||||||
|
/** If popup contains an enumeration*/
|
||||||
|
bool enumerated;
|
||||||
|
std::vector<StringPropertyNode> enumeration;
|
||||||
|
|
||||||
|
/** Validation rules for given popup */
|
||||||
|
std::vector<RuleNode> rules;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Represents component or connection attribute
|
||||||
|
* Attributes are values that can programmatically be changed
|
||||||
|
* if popup is defined
|
||||||
|
* */
|
||||||
|
struct AttributeNode : public AstNode {
|
||||||
|
/** Type of attribute */
|
||||||
|
ValueNode::ValueType type;
|
||||||
|
/** Name of attribute */
|
||||||
|
IdentifierNode name;
|
||||||
|
/** Display name */
|
||||||
|
std::optional<StringNode> displayName;
|
||||||
|
/** Default type of attribute */
|
||||||
|
std::optional<ValueNode> defaultValue;
|
||||||
|
/** Popup used to change attribute value */
|
||||||
|
std::optional<PopupNode> popup;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* DISPLAY TYPES *
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
struct DisplayItemNode;
|
||||||
|
|
||||||
|
/** Represents how a component or bus is rendered
|
||||||
|
* Display is made from an list of display items
|
||||||
|
* */
|
||||||
|
struct DisplayNode : public AstNode {
|
||||||
|
std::vector<DisplayItemNode> items;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** DisplayItem represents one rendered item
|
||||||
|
* in source code items are defined similar to json objects
|
||||||
|
* eg.
|
||||||
|
* @code rect {
|
||||||
|
* x: 100;
|
||||||
|
* y: 100;
|
||||||
|
* w: 100;
|
||||||
|
* h: 100;
|
||||||
|
* fillColor: #123456
|
||||||
|
* }
|
||||||
|
* */
|
||||||
|
struct DisplayItemNode : public AstNode {
|
||||||
|
/** Contains type of display item */
|
||||||
|
IdentifierNode type;
|
||||||
|
/** Contains all property nodes */
|
||||||
|
std::vector<PropertyNode> values;
|
||||||
|
|
||||||
|
/** Returns value of requested property
|
||||||
|
* If requested property doesn't exists default value is returned (eg. asInt is called but PropertyNode contains string)
|
||||||
|
* If value of requested property is different than expected nullopt is retured
|
||||||
|
* */
|
||||||
|
std::optional<long long int> asInt(const std::string &property, long long int _default = 0);
|
||||||
|
std::optional<Color> asColor(const std::string &property, Color _default = Color(0, 0, 0));
|
||||||
|
std::optional<std::string> asString(const std::string &property, std::string _default = "");
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::optional<PropertyNode> getProperty(const std::string &property);
|
||||||
|
};
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* LIBRARY TYPES *
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
/** Represents AddressSpaces
|
||||||
|
* Address spaces are defined with their name and address range
|
||||||
|
* */
|
||||||
|
struct AddressSpaceNode : public AstNode {
|
||||||
|
IdentifierNode name;
|
||||||
|
/** Range represent which addresses are available for components that use memory space [first, second> */
|
||||||
|
NumberPairNode range;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Pins are used to create component-component or component-bus connections */
|
||||||
|
struct PinNode : public AstNode {
|
||||||
|
/** Determines pin type, pin types currently only affect how pins are rendered */
|
||||||
|
enum PinType {
|
||||||
|
IN_OUT,
|
||||||
|
IN,
|
||||||
|
OUT
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Name of pin */
|
||||||
|
IdentifierNode name;
|
||||||
|
/** Type of pin */
|
||||||
|
EnumNode<PinType> type;
|
||||||
|
/** Tooltip content displayed on hover over pin */
|
||||||
|
std::optional<StringNode> tooltip;
|
||||||
|
/** If present this means pin must be connected to another component or bus to create connection
|
||||||
|
* Connection contains error message shown
|
||||||
|
* */
|
||||||
|
std::optional<StringNode> connection;
|
||||||
|
/** Determines how the pin is displayed */
|
||||||
|
std::optional<DisplayNode> display;
|
||||||
|
/** If pin connection is optional it requires list of wires used to populate comdel model */
|
||||||
|
std::optional<std::vector<ValueNode>> wires;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents COMDEL component
|
||||||
|
* */
|
||||||
|
struct ComponentNode : public AstNode {
|
||||||
|
/** Determines type of component */
|
||||||
|
enum ComponentType {
|
||||||
|
/** Generic component */
|
||||||
|
OTHER,
|
||||||
|
/** Represents processor, all processors have implicit attribute _memory if type memory
|
||||||
|
* used when generating COMDEL model to connect memories and processors
|
||||||
|
*/
|
||||||
|
PROCESSOR,
|
||||||
|
/** Represents memory, all components of type memory can be selected in _memory attribute of processor */
|
||||||
|
MEMORY
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Component name */
|
||||||
|
IdentifierNode name;
|
||||||
|
/** Component name */
|
||||||
|
std::optional<StringNode> displayName;
|
||||||
|
/** Tooltip displayed on hover */
|
||||||
|
std::optional<StringNode> tooltip;
|
||||||
|
/** Contains path to COMDEL source containing current component */
|
||||||
|
std::optional<StringNode> source;
|
||||||
|
/** Type of component */
|
||||||
|
EnumNode<ComponentType> type;
|
||||||
|
/** List of component level rules */
|
||||||
|
std::vector<RuleNode> rules;
|
||||||
|
/** Default used to name instances */
|
||||||
|
std::optional<IdentifierNode> instanceName;
|
||||||
|
/** Count determines number of instances allowed in a schema */
|
||||||
|
std::optional<NumberPairNode> count;
|
||||||
|
/** Display determines how component is rendered */
|
||||||
|
std::optional<DisplayNode> display;
|
||||||
|
/** List of all pins */
|
||||||
|
std::vector<PinNode> pins;
|
||||||
|
/** List of all attributes */
|
||||||
|
std::vector<AttributeNode> attributes;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** WireNode represents COMDEL wire
|
||||||
|
* */
|
||||||
|
struct WireNode : public AstNode {
|
||||||
|
/** Determines type of wires */
|
||||||
|
enum WireType {
|
||||||
|
/** Generic wire */
|
||||||
|
WIRE,
|
||||||
|
/** wired_and can have multiple sources, that are ANDed together */
|
||||||
|
WIRED_AND,
|
||||||
|
/** wired_and can have multiple sources, that are ORed together */
|
||||||
|
WIRED_OR,
|
||||||
|
/** r_wire can remain unconnected */
|
||||||
|
R_WIRE
|
||||||
|
};
|
||||||
|
EnumNode<WireType> type;
|
||||||
|
/** Name of wire */
|
||||||
|
IdentifierNode name;
|
||||||
|
/** Number of bits inside of a wire */
|
||||||
|
NumberNode size;
|
||||||
|
|
||||||
|
/** If wire is visible or hidden, this determines how wires are generated in COMDEL */
|
||||||
|
bool hidden = false;
|
||||||
|
|
||||||
|
/** If wire isn't connected to anything it is replaced with terminate with terminateWith value */
|
||||||
|
bool hasTerminateWith = false;
|
||||||
|
ValueNode terminateWith;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Buses dont exist in COMDEL but they are useful
|
||||||
|
* as they allow us to connect multiple COMDEL wires together
|
||||||
|
* */
|
||||||
|
struct BusNode : public AstNode {
|
||||||
|
enum BusType {
|
||||||
|
/** This busses connect two components */
|
||||||
|
AUTOMATIC,
|
||||||
|
/**
|
||||||
|
* This busses allow us to connect multiple component together using one bus
|
||||||
|
* */
|
||||||
|
REGULAR,
|
||||||
|
/** This busses connect two components,
|
||||||
|
* they differ from automatic as they allow us to connect same pins multiple times */
|
||||||
|
SINGLE_AUTOMATIC
|
||||||
|
};
|
||||||
|
|
||||||
|
EnumNode<BusType> type;
|
||||||
|
/** Bus name */
|
||||||
|
IdentifierNode name;
|
||||||
|
/** Display name */
|
||||||
|
std::optional<StringNode> displayName;
|
||||||
|
/** Default used to name instances */
|
||||||
|
std::optional<IdentifierNode> instanceName;
|
||||||
|
/** Tooltip displayed on hover */
|
||||||
|
std::optional<StringNode> tooltip;
|
||||||
|
/** Count determines number of instances allowed in a schema */
|
||||||
|
std::optional<NumberPairNode> count;
|
||||||
|
/** Display determines how component is rendered */
|
||||||
|
std::optional<DisplayNode> display;
|
||||||
|
|
||||||
|
/** List of all COMDEL wires contained in bus */
|
||||||
|
std::vector<WireNode> wires;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Represents ComponentConnection key in Connection node
|
||||||
|
* (eg. componentName.pinName)
|
||||||
|
* */
|
||||||
|
struct ConnectionComponentNode : public AstNode {
|
||||||
|
IdentifierNode component;
|
||||||
|
IdentifierNode pin;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Represents Connection node
|
||||||
|
* Connection can be between component and bus in which second is null,
|
||||||
|
* or between two components
|
||||||
|
* */
|
||||||
|
struct ConnectionNode : public AstNode {
|
||||||
|
ConnectionComponentNode first;
|
||||||
|
std::optional<ConnectionComponentNode> second;
|
||||||
|
|
||||||
|
IdentifierNode bus;
|
||||||
|
std::vector<AttributeNode> attributes;
|
||||||
|
|
||||||
|
/** If connection is of type component-component it contains two pairs of wires */
|
||||||
|
std::vector<ValueNode> firstWires;
|
||||||
|
std::optional<std::vector<ValueNode>> secondWires;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** LibraryNode represent library instance */
|
||||||
|
struct LibraryNode : public AstNode {
|
||||||
|
/** Name of library */
|
||||||
|
std::optional<StringNode> name;
|
||||||
|
/** Library info contains generic information about library */
|
||||||
|
std::optional<StringNode> libraryInfo;
|
||||||
|
/** Contains text that is added to top of COMDEL file */
|
||||||
|
std::optional<StringNode> header;
|
||||||
|
/** Contains path to component directory */
|
||||||
|
std::optional<StringNode> componentDirectory;
|
||||||
|
/** Contains text that is added to top of System component in COMDEL file */
|
||||||
|
std::optional<StringNode> componentHeader;
|
||||||
|
|
||||||
|
std::vector<AddressSpaceNode> addressSpaces;
|
||||||
|
|
||||||
|
std::vector<ComponentNode> components;
|
||||||
|
std::vector<BusNode> buses;
|
||||||
|
std::vector<ConnectionNode> connections;
|
||||||
|
|
||||||
|
/** Contains properties used to translate dialog and error messages */
|
||||||
|
std::vector<PropertyNode> messages;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* LIBRARY TYPES *
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
/** Represents instance of attribute in component or connection instance */
|
||||||
|
struct InstanceAttributeNode : public AstNode {
|
||||||
|
IdentifierNode name;
|
||||||
|
ValueNode value;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Represents instance of a component or a bus */
|
||||||
|
struct InstanceNode : public AstNode {
|
||||||
|
/** Contains instance name */
|
||||||
|
IdentifierNode name;
|
||||||
|
/** Contains component name */
|
||||||
|
IdentifierNode component;
|
||||||
|
|
||||||
|
/** Contains position of component instance */
|
||||||
|
std::optional<NumberPairNode> position;
|
||||||
|
std::vector<InstanceAttributeNode> attributes;
|
||||||
|
|
||||||
|
/** Contains size of bus instances */
|
||||||
|
std::optional<NumberNode> size;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Represents ComponentConnection of a selected instance */
|
||||||
|
struct ConnectionComponentInstanceNode : public AstNode {
|
||||||
|
/** Name of component instance */
|
||||||
|
IdentifierNode instance;
|
||||||
|
/** Name of pin */
|
||||||
|
IdentifierNode pin;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Represents Connection instance */
|
||||||
|
struct ConnectionInstanceNode : public AstNode {
|
||||||
|
ConnectionComponentInstanceNode first;
|
||||||
|
std::optional<ConnectionComponentInstanceNode> second;
|
||||||
|
|
||||||
|
IdentifierNode bus;
|
||||||
|
|
||||||
|
std::vector<InstanceAttributeNode> attributes;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Represent schema instance */
|
||||||
|
struct SchemaNode : public AstNode {
|
||||||
|
/** Contains path to library source */
|
||||||
|
std::optional<StringNode> source;
|
||||||
|
|
||||||
|
/** Contains list of instances */
|
||||||
|
std::vector<InstanceNode> instances;
|
||||||
|
/** Contains list of connection */
|
||||||
|
std::vector<ConnectionInstanceNode> connections;
|
||||||
|
|
||||||
|
/** Contains library */
|
||||||
|
std::optional<LibraryNode> library;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // AST_NODE_H
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,424 +0,0 @@
|
||||||
#ifndef AST_NODE_H
|
|
||||||
#define AST_NODE_H
|
|
||||||
|
|
||||||
#include "token.h"
|
|
||||||
#include <optional>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* AST base class, all AST node classes extend this class. Class contains basic
|
|
||||||
* information about nodes location in file.
|
|
||||||
*/
|
|
||||||
class AstNode {
|
|
||||||
public:
|
|
||||||
|
|
||||||
Span span;
|
|
||||||
|
|
||||||
AstNode() = default;
|
|
||||||
|
|
||||||
virtual ~AstNode(); // 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: public AstNode
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum ValueType {
|
|
||||||
INT,
|
|
||||||
STRING,
|
|
||||||
BOOL,
|
|
||||||
WIRE,
|
|
||||||
IDENTIFIER,
|
|
||||||
NIL,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
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 ofNull() {
|
|
||||||
ValueNode value;
|
|
||||||
value.type = NIL;
|
|
||||||
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: public AstNode {
|
|
||||||
public:
|
|
||||||
enum ActionType {
|
|
||||||
ERROR,
|
|
||||||
WARNING
|
|
||||||
};
|
|
||||||
|
|
||||||
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<PopupType> type;
|
|
||||||
std::optional<StringNode> title;
|
|
||||||
std::optional<StringNode> text;
|
|
||||||
|
|
||||||
bool enumerated;
|
|
||||||
std::vector<EnumerationNode> enumeration;
|
|
||||||
|
|
||||||
std::vector<RuleNode> rules;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PropertyNode: public AstNode
|
|
||||||
{
|
|
||||||
IdentifierNode key;
|
|
||||||
ValueNode value;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct DisplayItemNode: public AstNode
|
|
||||||
{
|
|
||||||
IdentifierNode type;
|
|
||||||
std::vector<PropertyNode> values;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct DisplayNode: public AstNode
|
|
||||||
{
|
|
||||||
std::vector<DisplayItemNode> items;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct PinConnectionNode: public AstNode
|
|
||||||
{
|
|
||||||
enum ConnectionType {
|
|
||||||
CHECK_ONLY,
|
|
||||||
AUTOMATICALLY
|
|
||||||
};
|
|
||||||
|
|
||||||
StringNode message;
|
|
||||||
ConnectionType type;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct PinNode: public AstNode
|
|
||||||
{
|
|
||||||
enum PinType {
|
|
||||||
IN_OUT,
|
|
||||||
IN,
|
|
||||||
OUT
|
|
||||||
};
|
|
||||||
|
|
||||||
IdentifierNode name;
|
|
||||||
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
|
|
||||||
};
|
|
||||||
WireType type;
|
|
||||||
IdentifierNode name;
|
|
||||||
NumberNode size;
|
|
||||||
|
|
||||||
bool hidden;
|
|
||||||
|
|
||||||
bool hasTermination;
|
|
||||||
long long isUnterminated;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
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;
|
|
||||||
ComponentType type;
|
|
||||||
std::vector<RuleNode> rules;
|
|
||||||
std::optional<StringNode> instanceName;
|
|
||||||
std::optional<CountNode> count;
|
|
||||||
std::optional<DisplayNode> display;
|
|
||||||
std::vector<PinNode> pins;
|
|
||||||
std::vector<AttributeNode> attributes;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct BusNode: public AstNode
|
|
||||||
{
|
|
||||||
enum BusType {
|
|
||||||
AUTOMATIC,
|
|
||||||
REGULAR
|
|
||||||
};
|
|
||||||
|
|
||||||
BusType type;
|
|
||||||
IdentifierNode name;
|
|
||||||
std::optional<StringNode> tooltip;
|
|
||||||
std::optional<CountNode> count;
|
|
||||||
std::optional<DisplayNode> display;
|
|
||||||
|
|
||||||
std::vector<WireNode> wires;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct LibraryNode: public AstNode
|
|
||||||
{
|
|
||||||
std::optional<StringNode> name;
|
|
||||||
std::optional<StringNode> libraryInfo;
|
|
||||||
std::optional<StringNode> header;
|
|
||||||
std::optional<StringNode> componentDirectory;
|
|
||||||
|
|
||||||
std::vector<AddressSpaceNode> addressSpaces;
|
|
||||||
|
|
||||||
std::vector<ComponentNode> components;
|
|
||||||
std::vector<BusNode> buses;
|
|
||||||
std::vector<ConnectionNode> connections;
|
|
||||||
|
|
||||||
std::vector<PropertyNode> messages;
|
|
||||||
};
|
|
||||||
|
|
||||||
// SCHEMA models
|
|
||||||
|
|
||||||
|
|
||||||
struct WireInstanceNode: public AstNode
|
|
||||||
{
|
|
||||||
IdentifierNode name;
|
|
||||||
std::optional<CountNode> position;
|
|
||||||
std::optional<DisplayNode> display;
|
|
||||||
};
|
|
||||||
|
|
||||||
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 {
|
|
||||||
IdentifierNode instance;
|
|
||||||
IdentifierNode pin;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ConnectionInstanceNode: public AstNode
|
|
||||||
{
|
|
||||||
ConnectionComponentInstance first;
|
|
||||||
std::optional<ConnectionComponentInstance> second;
|
|
||||||
|
|
||||||
IdentifierNode bus;
|
|
||||||
std::optional<IdentifierNode> wire;
|
|
||||||
|
|
||||||
std::vector<InstanceAttributeNode> attributes;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct SchemaNode: public AstNode
|
|
||||||
{
|
|
||||||
std::optional<StringNode> source;
|
|
||||||
|
|
||||||
std::vector<InstanceNode> instances;
|
|
||||||
std::vector<WireInstanceNode> wires;
|
|
||||||
std::vector<ConnectionInstanceNode> connections;
|
|
||||||
|
|
||||||
std::optional<LibraryNode> library;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // AST_NODE_H
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
//
|
||||||
|
// Created by bbr on 12.06.22..
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef SCHEMEEDITOR_COLOR_H
|
||||||
|
#define SCHEMEEDITOR_COLOR_H
|
||||||
|
|
||||||
|
|
||||||
|
struct Color {
|
||||||
|
unsigned char r = 0;
|
||||||
|
unsigned char g = 0;
|
||||||
|
unsigned char b = 0;
|
||||||
|
unsigned char a = 255;
|
||||||
|
|
||||||
|
Color() = default;
|
||||||
|
|
||||||
|
Color(unsigned char r, unsigned char g, unsigned char b, unsigned char a = 0): r(r), g(g), b(b), a(a) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //SCHEMEEDITOR_COLOR_H
|
|
@ -1,6 +1,6 @@
|
||||||
#include "comdellexer.h"
|
#include "comdel_lexer.h"
|
||||||
#include "token.h"
|
#include "token.h"
|
||||||
#include "tokenstype.h"
|
#include "tokens_type.h"
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
|
@ -42,8 +42,7 @@ ComdelLexer::ComdelLexer(std::string fileName, std::string source,
|
||||||
// TODO Update this
|
// TODO Update this
|
||||||
fileId(this->parseContext->addFile(fileName, this->source)),
|
fileId(this->parseContext->addFile(fileName, this->source)),
|
||||||
position(this->fileId, 1, 1, 0),
|
position(this->fileId, 1, 1, 0),
|
||||||
ch(this->source[0])
|
ch(this->source[0]) {}
|
||||||
{}
|
|
||||||
|
|
||||||
|
|
||||||
LexerResult ComdelLexer::tokenize() {
|
LexerResult ComdelLexer::tokenize() {
|
||||||
|
@ -181,8 +180,7 @@ PResult<TokenType> ComdelLexer::takeString() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PResult<TokenType> ComdelLexer::takeRawString()
|
PResult<TokenType> ComdelLexer::takeRawString() {
|
||||||
{
|
|
||||||
Position lo = position;
|
Position lo = position;
|
||||||
|
|
||||||
if (ch != '`')
|
if (ch != '`')
|
||||||
|
@ -237,20 +235,15 @@ bool ComdelLexer::skipMultilineComment() {
|
||||||
|
|
||||||
|
|
||||||
PResult<TokenType> ComdelLexer::nextTokenType() {
|
PResult<TokenType> ComdelLexer::nextTokenType() {
|
||||||
if (isWhitespace(ch))
|
if (isWhitespace(ch)) {
|
||||||
{
|
|
||||||
skipWhitespace();
|
skipWhitespace();
|
||||||
return TokenType::WHITESPACE;
|
return TokenType::WHITESPACE;
|
||||||
}
|
} else if (identifierStart(ch)) {
|
||||||
else if (identifierStart(ch))
|
|
||||||
{
|
|
||||||
bump();
|
bump();
|
||||||
while (identifierContinue(ch))
|
while (identifierContinue(ch))
|
||||||
bump();
|
bump();
|
||||||
return TokenType::IDENTIFIER;
|
return TokenType::IDENTIFIER;
|
||||||
}
|
} else if (numberStart(ch)) {
|
||||||
else if (numberStart(ch))
|
|
||||||
{
|
|
||||||
if (ch == '-') {
|
if (ch == '-') {
|
||||||
bump();
|
bump();
|
||||||
}
|
}
|
||||||
|
@ -266,27 +259,16 @@ PResult<TokenType> ComdelLexer::nextTokenType() {
|
||||||
"illegal digit or letter found at the end of number"});
|
"illegal digit or letter found at the end of number"});
|
||||||
}
|
}
|
||||||
return TokenType::NUMBER;
|
return TokenType::NUMBER;
|
||||||
}
|
} else if (ch == '!') {
|
||||||
else if (ch == '!')
|
|
||||||
{
|
|
||||||
bump();
|
bump();
|
||||||
return TokenType::NOT;
|
return TokenType::NOT;
|
||||||
}
|
} else if (ch == '<') {
|
||||||
|
|
||||||
else if (ch == '<')
|
|
||||||
{
|
|
||||||
bump();
|
bump();
|
||||||
return TokenType::LT;
|
return TokenType::LT;
|
||||||
}
|
} else if (ch == '>') {
|
||||||
|
|
||||||
else if (ch == '>')
|
|
||||||
{
|
|
||||||
bump();
|
bump();
|
||||||
return TokenType::GT;
|
return TokenType::GT;
|
||||||
}
|
} else if (ch == '#') {
|
||||||
|
|
||||||
else if (ch == '#')
|
|
||||||
{
|
|
||||||
bump();
|
bump();
|
||||||
|
|
||||||
if (digitIsValid(ch, Radix::HEX_NUMBER)) {
|
if (digitIsValid(ch, Radix::HEX_NUMBER)) {
|
||||||
|
@ -304,65 +286,42 @@ PResult<TokenType> ComdelLexer::nextTokenType() {
|
||||||
return PError({Span(tokenBegin, position),
|
return PError({Span(tokenBegin, position),
|
||||||
"unexpected #"});
|
"unexpected #"});
|
||||||
}
|
}
|
||||||
}
|
} else if (ch == '@') {
|
||||||
else if (ch == '@')
|
|
||||||
{
|
|
||||||
bump();
|
bump();
|
||||||
while (identifierContinue(ch))
|
while (identifierContinue(ch))
|
||||||
bump();
|
bump();
|
||||||
return TokenType::KEYWORD;
|
return TokenType::KEYWORD;
|
||||||
}
|
} else if (ch == '"') {
|
||||||
else if (ch == '"')
|
|
||||||
{
|
|
||||||
return takeString();
|
return takeString();
|
||||||
}
|
} else if (ch == '`') {
|
||||||
else if (ch == '`')
|
|
||||||
{
|
|
||||||
return takeRawString();
|
return takeRawString();
|
||||||
}
|
} else if (ch == '(') {
|
||||||
else if (ch == '(')
|
|
||||||
{
|
|
||||||
bump();
|
bump();
|
||||||
return TokenType::LPAREN;
|
return TokenType::LPAREN;
|
||||||
}
|
} else if (ch == ')') {
|
||||||
else if (ch == ')')
|
|
||||||
{
|
|
||||||
bump();
|
bump();
|
||||||
return TokenType::RPAREN;
|
return TokenType::RPAREN;
|
||||||
}
|
} else if (ch == '[') {
|
||||||
else if (ch == '[')
|
|
||||||
{
|
|
||||||
bump();
|
bump();
|
||||||
return TokenType::LBRACKET;
|
return TokenType::LBRACKET;
|
||||||
}
|
} else if (ch == ']') {
|
||||||
else if (ch == ']')
|
|
||||||
{
|
|
||||||
bump();
|
bump();
|
||||||
return TokenType::RBRACKET;
|
return TokenType::RBRACKET;
|
||||||
}
|
} else if (ch == '{') {
|
||||||
else if (ch == '{')
|
|
||||||
{
|
|
||||||
bump();
|
bump();
|
||||||
return TokenType::LBRACE;
|
return TokenType::LBRACE;
|
||||||
}
|
} else if (ch == '}') {
|
||||||
else if (ch == '}')
|
|
||||||
{
|
|
||||||
bump();
|
bump();
|
||||||
return TokenType::RBRACE;
|
return TokenType::RBRACE;
|
||||||
}
|
} else if (ch == '/') {
|
||||||
else if (ch == '/')
|
|
||||||
{
|
|
||||||
bump();
|
bump();
|
||||||
if (ch == '/')
|
if (ch == '/') {
|
||||||
{
|
|
||||||
bump();
|
bump();
|
||||||
skipComment();
|
skipComment();
|
||||||
return TokenType::COMMENT;
|
return TokenType::COMMENT;
|
||||||
} else if (ch == '*')
|
} else if (ch == '*') {
|
||||||
{
|
|
||||||
bump();
|
bump();
|
||||||
if (!skipMultilineComment())
|
if (!skipMultilineComment()) {
|
||||||
{
|
|
||||||
return PError({Span(tokenBegin, position),
|
return PError({Span(tokenBegin, position),
|
||||||
"unterminated multiline comment"});
|
"unterminated multiline comment"});
|
||||||
}
|
}
|
||||||
|
@ -370,34 +329,22 @@ PResult<TokenType> ComdelLexer::nextTokenType() {
|
||||||
}
|
}
|
||||||
return PError({Span(tokenBegin, position),
|
return PError({Span(tokenBegin, position),
|
||||||
"unexpected /"});
|
"unexpected /"});
|
||||||
}
|
} else if (ch == '.') {
|
||||||
else if (ch == '.')
|
|
||||||
{
|
|
||||||
bump();
|
bump();
|
||||||
return TokenType::DOT;
|
return TokenType::DOT;
|
||||||
}
|
} else if (ch == ':') {
|
||||||
else if (ch == ':')
|
|
||||||
{
|
|
||||||
bump();
|
bump();
|
||||||
return TokenType::COLON;
|
return TokenType::COLON;
|
||||||
}
|
} else if (ch == ';') {
|
||||||
else if (ch == ';')
|
|
||||||
{
|
|
||||||
bump();
|
bump();
|
||||||
return TokenType::SEMICOLON;
|
return TokenType::SEMICOLON;
|
||||||
}
|
} else if (ch == ',') {
|
||||||
else if (ch == ',')
|
|
||||||
{
|
|
||||||
bump();
|
bump();
|
||||||
return TokenType::COMMA;
|
return TokenType::COMMA;
|
||||||
}
|
} else if (ch == '=') {
|
||||||
else if (ch == '=')
|
|
||||||
{
|
|
||||||
bump();
|
bump();
|
||||||
return TokenType::EQUALS;
|
return TokenType::EQUALS;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
std::stringstream message;
|
std::stringstream message;
|
||||||
message << "unexpected character `" << ch << "`";
|
message << "unexpected character `" << ch << "`";
|
||||||
bump();
|
bump();
|
|
@ -1,9 +1,9 @@
|
||||||
#ifndef COMDEL_LEXER_H
|
#ifndef COMDEL_LEXER_H
|
||||||
#define COMDEL_LEXER_H
|
#define COMDEL_LEXER_H
|
||||||
|
|
||||||
#include "parsecontext.h"
|
#include "parse_context.h"
|
||||||
#include "presult.h"
|
#include "presult.h"
|
||||||
#include "sourceerror.h"
|
#include "source_error.h"
|
||||||
#include "token.h"
|
#include "token.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,13 +11,15 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
/** Contains results of tokenizing,
|
||||||
|
* if errors isn't empty tokenizing has failed */
|
||||||
struct LexerResult {
|
struct LexerResult {
|
||||||
std::vector<Token> tokens;
|
std::vector<Token> tokens;
|
||||||
std::vector<SourceError> errors;
|
std::vector<SourceError> errors;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ComdelLexer
|
/** Used to tokenize input string */
|
||||||
{
|
class ComdelLexer {
|
||||||
|
|
||||||
enum Radix {
|
enum Radix {
|
||||||
BIN_NUMBER = 2,
|
BIN_NUMBER = 2,
|
||||||
|
@ -25,38 +27,46 @@ class ComdelLexer
|
||||||
HEX_NUMBER = 16
|
HEX_NUMBER = 16
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Source file */
|
||||||
std::string source;
|
std::string source;
|
||||||
std::vector<Token> tokens;
|
std::vector<Token> tokens;
|
||||||
std::vector<SourceError> errors;
|
std::vector<SourceError> errors;
|
||||||
|
/** Source file */
|
||||||
ParseContext *parseContext;
|
ParseContext *parseContext;
|
||||||
unsigned fileId;
|
unsigned fileId;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ComdelLexer(std::string fileName, std::string source, ParseContext *parseContext);
|
ComdelLexer(std::string fileName, std::string source, ParseContext *parseContext);
|
||||||
|
|
||||||
LexerResult tokenize();
|
LexerResult tokenize();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void skipWhitespace();
|
/** Current parsing info */
|
||||||
|
|
||||||
unsigned takeNumberInRadix(Radix radix);
|
|
||||||
unsigned takeHexColor();
|
|
||||||
bool digitIsValid(char ch, Radix radix);
|
|
||||||
Radix takeRadix();
|
|
||||||
|
|
||||||
PResult<TokenType> nextTokenType();
|
|
||||||
|
|
||||||
Position tokenBegin;
|
Position tokenBegin;
|
||||||
Position position;
|
Position position;
|
||||||
char ch;
|
char ch;
|
||||||
|
|
||||||
|
/** Methods used to skip unused content */
|
||||||
|
void skipWhitespace();
|
||||||
void skipComment();
|
void skipComment();
|
||||||
bool skipMultilineComment();
|
bool skipMultilineComment();
|
||||||
|
void bump(unsigned count = 1);
|
||||||
|
|
||||||
|
/** Metods used for number parsing */
|
||||||
|
unsigned takeNumberInRadix(Radix radix);
|
||||||
|
bool digitIsValid(char ch, Radix radix);
|
||||||
|
Radix takeRadix();
|
||||||
|
|
||||||
|
unsigned takeHexColor();
|
||||||
|
|
||||||
|
PResult<TokenType> nextTokenType();
|
||||||
|
|
||||||
PResult<TokenType> takeString();
|
PResult<TokenType> takeString();
|
||||||
PResult<TokenType> takeRawString();
|
PResult<TokenType> takeRawString();
|
||||||
|
|
||||||
void bump(unsigned count = 1);
|
|
||||||
char peek();
|
char peek();
|
||||||
|
|
||||||
|
/** Checks if we reached end of file */
|
||||||
bool eof();
|
bool eof();
|
||||||
};
|
};
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,10 +1,10 @@
|
||||||
#ifndef COMDEL_PARSER_H
|
#ifndef COMDEL_PARSER_H
|
||||||
#define COMDEL_PARSER_H
|
#define COMDEL_PARSER_H
|
||||||
|
|
||||||
#include "sourceerror.h"
|
#include "source_error.h"
|
||||||
#include "presult.h"
|
#include "presult.h"
|
||||||
#include "token.h"
|
#include "token.h"
|
||||||
#include "astnode.h"
|
#include "ast_nodes.h"
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
@ -16,24 +16,23 @@
|
||||||
/// Spanner's call operator MOVES from the node so it should
|
/// Spanner's call operator MOVES from the node so it should
|
||||||
/// be always used last.
|
/// be always used last.
|
||||||
class Spanner {
|
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
|
// REFERENCE to the parser's prevSpan. After parsing a node this will
|
||||||
// "point" to the span of the last token contained in the node.
|
// "point" to the span of the last token contained in the node.
|
||||||
const Span &prevSpan;
|
const Span &prevSpan;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
const Span lo; // the low end of the span, beginning of the node
|
||||||
|
|
||||||
Spanner(Span lo, Span &prevSpan) : lo(lo), prevSpan(prevSpan) {}
|
Spanner(Span lo, Span &prevSpan) : lo(lo), prevSpan(prevSpan) {}
|
||||||
|
|
||||||
template<typename T, typename = std::enable_if<std::is_base_of<AstNode, T>::value>>
|
template<typename T, typename = std::enable_if<std::is_base_of<AstNode, T>::value>>
|
||||||
typename std::remove_reference_t<T> operator()(T &&astNode) const {
|
typename std::remove_reference_t<T> operator()(T &&astNode) const {
|
||||||
astNode.span = lo.to(prevSpan);
|
astNode.span = lo.to(prevSpan);
|
||||||
return std::move(astNode);
|
return std::forward<T>(astNode);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ComdelParser
|
class ComdelParser {
|
||||||
{
|
|
||||||
private:
|
private:
|
||||||
std::vector<Token> tokens;
|
std::vector<Token> tokens;
|
||||||
std::set<TokenType> expectedTokens;
|
std::set<TokenType> expectedTokens;
|
||||||
|
@ -43,13 +42,20 @@ private:
|
||||||
|
|
||||||
Span &getPreviousSpan();
|
Span &getPreviousSpan();
|
||||||
|
|
||||||
|
/** Skips current token */
|
||||||
void bump();
|
void bump();
|
||||||
|
/** Checks if next token is of given type and if it is consumes it */
|
||||||
bool consume(TokenType tokenType);
|
bool consume(TokenType tokenType);
|
||||||
|
/** Checks if next token is of given type */
|
||||||
bool check(TokenType tokenType);
|
bool check(TokenType tokenType);
|
||||||
|
/** Skips until next keyword on same level
|
||||||
|
* Used to continue parsing on error
|
||||||
|
* */
|
||||||
|
void skipUntilNextKeyword();
|
||||||
|
/** Retuns current token */
|
||||||
Token ¤t();
|
Token ¤t();
|
||||||
|
|
||||||
|
/** Throws error of unexpected types */
|
||||||
[[nodiscard]] PError unexpected();
|
[[nodiscard]] PError unexpected();
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
@ -61,41 +67,45 @@ private:
|
||||||
|
|
||||||
Spanner getSpanner();
|
Spanner getSpanner();
|
||||||
|
|
||||||
|
/** Base types */
|
||||||
PResult<StringNode> parseString();
|
PResult<StringNode> parseString();
|
||||||
|
PResult<ColorNode> parseColor();
|
||||||
PResult<IdentifierNode> parseIdentifier();
|
PResult<IdentifierNode> parseIdentifier();
|
||||||
PResult<NumberNode> parseNumber();
|
PResult<NumberNode> parseNumber();
|
||||||
PResult<CountNode> parseCount();
|
PResult<NumberPairNode> parseNumberPair();
|
||||||
PResult<PropertyNode> parseProperty(std::optional<TokenType> valueType);
|
PResult<PropertyNode> parseProperty(std::optional<TokenType> valueType);
|
||||||
PResult<EnumerationNode> parseEnumeration();
|
PResult<StringPropertyNode> parseStringProperty();
|
||||||
|
PResult<ValueNode> parseValue();
|
||||||
|
|
||||||
|
/** Library types */
|
||||||
PResult<ValueNode> parseConnectionWire();
|
PResult<ValueNode> parseConnectionWire();
|
||||||
PResult<ComponentNode> parseComponent();
|
PResult<ComponentNode> parseComponent();
|
||||||
|
PResult<EnumNode<ComponentNode::ComponentType>> parseComponentType();
|
||||||
PResult<AddressSpaceNode> parseAddress();
|
PResult<AddressSpaceNode> parseAddress();
|
||||||
PResult<PinNode> parsePin();
|
PResult<PinNode> parsePin();
|
||||||
PResult<DisplayNode> parseDisplay();
|
PResult<DisplayNode> parseDisplay();
|
||||||
PResult<PinConnectionNode> parsePinConnection();
|
|
||||||
PResult<AttributeNode> parseAttribute();
|
PResult<AttributeNode> parseAttribute();
|
||||||
PResult<PopupNode> parsePopup();
|
PResult<PopupNode> parsePopup();
|
||||||
PResult<RuleNode> parseRule();
|
PResult<RuleNode> parseRule();
|
||||||
PResult<BusNode> parseBus();
|
PResult<BusNode> parseBus();
|
||||||
PResult<WireNode> parseWire();
|
PResult<WireNode> parseWire();
|
||||||
PResult<ConnectionNode> parseConnection();
|
PResult<ConnectionNode> parseConnection();
|
||||||
|
PResult<ConnectionComponentNode> parseConnectionComponent();
|
||||||
PResult<DisplayItemNode> parseDisplayItem();
|
PResult<DisplayItemNode> parseDisplayItem();
|
||||||
PResult<IfStatementNode> parseIfStatement();
|
PResult<IfStatementNode> parseIfStatement();
|
||||||
PResult<ValueNode> parseValue();
|
PResult<EnumNode<BusNode::BusType>> parseBusType();
|
||||||
|
|
||||||
|
/** Schema types */
|
||||||
PResult<WireInstanceNode> parseWireInstance();
|
|
||||||
PResult<CountNode> parsePosition();
|
|
||||||
PResult<InstanceNode> parseInstance();
|
PResult<InstanceNode> parseInstance();
|
||||||
PResult<InstanceAttributeNode> parseInstanceAttribute();
|
PResult<InstanceAttributeNode> parseInstanceAttribute();
|
||||||
PResult<ConnectionInstanceNode> parseConnectionInstance();
|
PResult<ConnectionInstanceNode> parseConnectionInstance();
|
||||||
|
PResult<ConnectionComponentInstanceNode> parseConnectionComponentInstance();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ComdelParser(std::vector<Token> tokens);
|
explicit ComdelParser(std::vector<Token> tokens);
|
||||||
|
|
||||||
std::optional<SchemaNode> parseSchema();
|
std::optional<SchemaNode> parseSchema();
|
||||||
std::optional<LibraryNode> parse();
|
std::optional<LibraryNode> parseLibrary();
|
||||||
const std::vector<SourceError> &getErrors();
|
const std::vector<SourceError> &getErrors();
|
||||||
};
|
};
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -128,27 +128,33 @@ namespace tl {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace tl {
|
namespace tl {
|
||||||
template <class T, class E> class expected;
|
template<class T, class E>
|
||||||
|
class expected;
|
||||||
|
|
||||||
#ifndef TL_MONOSTATE_INPLACE_MUTEX
|
#ifndef TL_MONOSTATE_INPLACE_MUTEX
|
||||||
#define TL_MONOSTATE_INPLACE_MUTEX
|
#define TL_MONOSTATE_INPLACE_MUTEX
|
||||||
|
|
||||||
/// \brief Used to represent an expected with no data
|
/// \brief Used to represent an expected with no data
|
||||||
class monostate {};
|
class monostate {
|
||||||
|
};
|
||||||
|
|
||||||
/// \brief A tag type to tell expected to construct its value in-place
|
/// \brief A tag type to tell expected to construct its value in-place
|
||||||
struct in_place_t {
|
struct in_place_t {
|
||||||
explicit in_place_t() = default;
|
explicit in_place_t() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief A tag to tell expected to construct its value in-place
|
/// \brief A tag to tell expected to construct its value in-place
|
||||||
static constexpr in_place_t in_place{};
|
static constexpr in_place_t in_place{};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// Used as a wrapper to store the unexpected value
|
/// Used as a wrapper to store the unexpected value
|
||||||
template <class E> class unexpected {
|
template<class E>
|
||||||
|
class unexpected {
|
||||||
public:
|
public:
|
||||||
static_assert(!std::is_same<E, void>::value, "E must not be void");
|
static_assert(!std::is_same<E, void>::value, "E must not be void");
|
||||||
|
|
||||||
unexpected() = delete;
|
unexpected() = delete;
|
||||||
|
|
||||||
constexpr unexpected(const E &e) : m_val(e) {}
|
constexpr unexpected(const E &e) : m_val(e) {}
|
||||||
|
|
||||||
constexpr unexpected(E &&e) : m_val(std::move(e)) {}
|
constexpr unexpected(E &&e) : m_val(std::move(e)) {}
|
||||||
|
@ -160,6 +166,7 @@ public:
|
||||||
TL_EXPECTED_11_CONSTEXPR E &value() &{ return m_val; }
|
TL_EXPECTED_11_CONSTEXPR E &value() &{ return m_val; }
|
||||||
/// \group unexpected_value
|
/// \group unexpected_value
|
||||||
TL_EXPECTED_11_CONSTEXPR E &&value() &&{ return std::move(m_val); }
|
TL_EXPECTED_11_CONSTEXPR E &&value() &&{ return std::move(m_val); }
|
||||||
|
|
||||||
/// \exclude
|
/// \exclude
|
||||||
constexpr const E &&value() const &&{ return std::move(m_val); }
|
constexpr const E &&value() const &&{ return std::move(m_val); }
|
||||||
|
|
||||||
|
@ -174,26 +181,31 @@ template <class E>
|
||||||
constexpr bool operator==(const unexpected<E> &lhs, const unexpected<E> &rhs) {
|
constexpr bool operator==(const unexpected<E> &lhs, const unexpected<E> &rhs) {
|
||||||
return lhs.value() == rhs.value();
|
return lhs.value() == rhs.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \group unexpected_relop
|
/// \group unexpected_relop
|
||||||
template<class E>
|
template<class E>
|
||||||
constexpr bool operator!=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
|
constexpr bool operator!=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
|
||||||
return lhs.value() != rhs.value();
|
return lhs.value() != rhs.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \group unexpected_relop
|
/// \group unexpected_relop
|
||||||
template<class E>
|
template<class E>
|
||||||
constexpr bool operator<(const unexpected<E> &lhs, const unexpected<E> &rhs) {
|
constexpr bool operator<(const unexpected<E> &lhs, const unexpected<E> &rhs) {
|
||||||
return lhs.value() < rhs.value();
|
return lhs.value() < rhs.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \group unexpected_relop
|
/// \group unexpected_relop
|
||||||
template<class E>
|
template<class E>
|
||||||
constexpr bool operator<=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
|
constexpr bool operator<=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
|
||||||
return lhs.value() <= rhs.value();
|
return lhs.value() <= rhs.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \group unexpected_relop
|
/// \group unexpected_relop
|
||||||
template<class E>
|
template<class E>
|
||||||
constexpr bool operator>(const unexpected<E> &lhs, const unexpected<E> &rhs) {
|
constexpr bool operator>(const unexpected<E> &lhs, const unexpected<E> &rhs) {
|
||||||
return lhs.value() > rhs.value();
|
return lhs.value() > rhs.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \group unexpected_relop
|
/// \group unexpected_relop
|
||||||
template<class E>
|
template<class E>
|
||||||
constexpr bool operator>=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
|
constexpr bool operator>=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
|
||||||
|
@ -214,6 +226,7 @@ unexpected<typename std::decay<E>::type> make_unexpected(E &&e) {
|
||||||
struct unexpect_t {
|
struct unexpect_t {
|
||||||
unexpect_t() = default;
|
unexpect_t() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief A tag to tell expected to construct the unexpected value
|
/// \brief A tag to tell expected to construct the unexpected value
|
||||||
static constexpr unexpect_t unexpect{};
|
static constexpr unexpect_t unexpect{};
|
||||||
|
|
||||||
|
@ -246,11 +259,16 @@ template <bool B, class T, class F>
|
||||||
using conditional_t = typename std::conditional<B, T, F>::type;
|
using conditional_t = typename std::conditional<B, T, F>::type;
|
||||||
|
|
||||||
// std::conjunction from C++17
|
// std::conjunction from C++17
|
||||||
template <class...> struct conjunction : std::true_type {};
|
template<class...>
|
||||||
template <class B> struct conjunction<B> : B {};
|
struct conjunction : std::true_type {
|
||||||
|
};
|
||||||
|
template<class B>
|
||||||
|
struct conjunction<B> : B {
|
||||||
|
};
|
||||||
template<class B, class... Bs>
|
template<class B, class... Bs>
|
||||||
struct conjunction<B, Bs...>
|
struct conjunction<B, Bs...>
|
||||||
: std::conditional<bool(B::value), conjunction<Bs...>, B>::type {};
|
: std::conditional<bool(B::value), conjunction<Bs...>, B>::type {
|
||||||
|
};
|
||||||
|
|
||||||
// std::invoke from C++17
|
// std::invoke from C++17
|
||||||
// https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround
|
// https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround
|
||||||
|
@ -272,7 +290,8 @@ constexpr auto invoke(Fn &&f, Args &&... args) noexcept(
|
||||||
}
|
}
|
||||||
|
|
||||||
// std::invoke_result from C++17
|
// std::invoke_result from C++17
|
||||||
template <class F, class, class... Us> struct invoke_result_impl;
|
template<class F, class, class... Us>
|
||||||
|
struct invoke_result_impl;
|
||||||
|
|
||||||
template<class F, class... Us>
|
template<class F, class... Us>
|
||||||
struct invoke_result_impl<
|
struct invoke_result_impl<
|
||||||
|
@ -289,9 +308,12 @@ using invoke_result_t = typename invoke_result<F, Us...>::type;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Trait for checking if a type is a tl::expected
|
// Trait for checking if a type is a tl::expected
|
||||||
template <class T> struct is_expected_impl : std::false_type {};
|
template<class T>
|
||||||
|
struct is_expected_impl : std::false_type {
|
||||||
|
};
|
||||||
template<class T, class E>
|
template<class T, class E>
|
||||||
struct is_expected_impl<expected<T, E>> : std::true_type {};
|
struct is_expected_impl<expected<T, E>> : std::true_type {
|
||||||
|
};
|
||||||
template<class T> using is_expected = is_expected_impl<decay_t<T>>;
|
template<class T> using is_expected = is_expected_impl<decay_t<T>>;
|
||||||
|
|
||||||
template<class T, class E, class U>
|
template<class T, class E, class U>
|
||||||
|
@ -339,7 +361,8 @@ using is_move_assignable_or_void =
|
||||||
|
|
||||||
/// \exclude
|
/// \exclude
|
||||||
namespace detail {
|
namespace detail {
|
||||||
struct no_init_t {};
|
struct no_init_t {
|
||||||
|
};
|
||||||
static constexpr no_init_t no_init{};
|
static constexpr no_init_t no_init{};
|
||||||
|
|
||||||
// Implements the storage of the values, and ensures that the destructor is
|
// Implements the storage of the values, and ensures that the destructor is
|
||||||
|
@ -352,6 +375,7 @@ template <class T, class E, bool = std::is_trivially_destructible<T>::value,
|
||||||
bool = std::is_trivially_destructible<E>::value>
|
bool = std::is_trivially_destructible<E>::value>
|
||||||
struct expected_storage_base {
|
struct expected_storage_base {
|
||||||
constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
|
constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
|
||||||
|
|
||||||
constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {}
|
constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {}
|
||||||
|
|
||||||
template<class... Args,
|
template<class... Args,
|
||||||
|
@ -366,6 +390,7 @@ struct expected_storage_base {
|
||||||
constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
|
constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
|
||||||
Args &&... args)
|
Args &&... args)
|
||||||
: m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
|
: m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
|
||||||
|
|
||||||
template<class... Args,
|
template<class... Args,
|
||||||
detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
|
detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
|
||||||
nullptr>
|
nullptr>
|
||||||
|
@ -387,6 +412,7 @@ struct expected_storage_base {
|
||||||
m_unexpect.~unexpected<E>();
|
m_unexpect.~unexpected<E>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
union {
|
union {
|
||||||
T m_val;
|
T m_val;
|
||||||
unexpected<E> m_unexpect;
|
unexpected<E> m_unexpect;
|
||||||
|
@ -397,8 +423,10 @@ struct expected_storage_base {
|
||||||
|
|
||||||
// This specialization is for when both `T` and `E` are trivially-destructible,
|
// This specialization is for when both `T` and `E` are trivially-destructible,
|
||||||
// so the destructor of the `expected` can be trivial.
|
// so the destructor of the `expected` can be trivial.
|
||||||
template <class T, class E> struct expected_storage_base<T, E, true, true> {
|
template<class T, class E>
|
||||||
|
struct expected_storage_base<T, E, true, true> {
|
||||||
constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
|
constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
|
||||||
|
|
||||||
constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {}
|
constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {}
|
||||||
|
|
||||||
template<class... Args,
|
template<class... Args,
|
||||||
|
@ -413,6 +441,7 @@ template <class T, class E> struct expected_storage_base<T, E, true, true> {
|
||||||
constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
|
constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
|
||||||
Args &&... args)
|
Args &&... args)
|
||||||
: m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
|
: m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
|
||||||
|
|
||||||
template<class... Args,
|
template<class... Args,
|
||||||
detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
|
detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
|
||||||
nullptr>
|
nullptr>
|
||||||
|
@ -428,6 +457,7 @@ template <class T, class E> struct expected_storage_base<T, E, true, true> {
|
||||||
: m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
|
: m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
|
||||||
|
|
||||||
~expected_storage_base() = default;
|
~expected_storage_base() = default;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
T m_val;
|
T m_val;
|
||||||
unexpected<E> m_unexpect;
|
unexpected<E> m_unexpect;
|
||||||
|
@ -437,8 +467,10 @@ template <class T, class E> struct expected_storage_base<T, E, true, true> {
|
||||||
};
|
};
|
||||||
|
|
||||||
// T is trivial, E is not.
|
// T is trivial, E is not.
|
||||||
template <class T, class E> struct expected_storage_base<T, E, true, false> {
|
template<class T, class E>
|
||||||
|
struct expected_storage_base<T, E, true, false> {
|
||||||
constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
|
constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
|
||||||
|
|
||||||
TL_EXPECTED_MSVC2015_CONSTEXPR expected_storage_base(no_init_t)
|
TL_EXPECTED_MSVC2015_CONSTEXPR expected_storage_base(no_init_t)
|
||||||
: m_no_init(), m_has_val(false) {}
|
: m_no_init(), m_has_val(false) {}
|
||||||
|
|
||||||
|
@ -454,6 +486,7 @@ template <class T, class E> struct expected_storage_base<T, E, true, false> {
|
||||||
constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
|
constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
|
||||||
Args &&... args)
|
Args &&... args)
|
||||||
: m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
|
: m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
|
||||||
|
|
||||||
template<class... Args,
|
template<class... Args,
|
||||||
detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
|
detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
|
||||||
nullptr>
|
nullptr>
|
||||||
|
@ -483,8 +516,10 @@ template <class T, class E> struct expected_storage_base<T, E, true, false> {
|
||||||
};
|
};
|
||||||
|
|
||||||
// E is trivial, T is not.
|
// E is trivial, T is not.
|
||||||
template <class T, class E> struct expected_storage_base<T, E, false, true> {
|
template<class T, class E>
|
||||||
|
struct expected_storage_base<T, E, false, true> {
|
||||||
constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
|
constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
|
||||||
|
|
||||||
constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {}
|
constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {}
|
||||||
|
|
||||||
template<class... Args,
|
template<class... Args,
|
||||||
|
@ -499,6 +534,7 @@ template <class T, class E> struct expected_storage_base<T, E, false, true> {
|
||||||
constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
|
constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
|
||||||
Args &&... args)
|
Args &&... args)
|
||||||
: m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
|
: m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
|
||||||
|
|
||||||
template<class... Args,
|
template<class... Args,
|
||||||
detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
|
detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
|
||||||
nullptr>
|
nullptr>
|
||||||
|
@ -518,6 +554,7 @@ template <class T, class E> struct expected_storage_base<T, E, false, true> {
|
||||||
m_val.~T();
|
m_val.~T();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
union {
|
union {
|
||||||
T m_val;
|
T m_val;
|
||||||
unexpected<E> m_unexpect;
|
unexpected<E> m_unexpect;
|
||||||
|
@ -527,8 +564,10 @@ template <class T, class E> struct expected_storage_base<T, E, false, true> {
|
||||||
};
|
};
|
||||||
|
|
||||||
// `T` is `void`, `E` is trivially-destructible
|
// `T` is `void`, `E` is trivially-destructible
|
||||||
template <class E> struct expected_storage_base<void, E, false, true> {
|
template<class E>
|
||||||
|
struct expected_storage_base<void, E, false, true> {
|
||||||
TL_EXPECTED_MSVC2015_CONSTEXPR expected_storage_base() : m_has_val(true) {}
|
TL_EXPECTED_MSVC2015_CONSTEXPR expected_storage_base() : m_has_val(true) {}
|
||||||
|
|
||||||
constexpr expected_storage_base(no_init_t) : m_val(), m_has_val(false) {}
|
constexpr expected_storage_base(no_init_t) : m_val(), m_has_val(false) {}
|
||||||
|
|
||||||
constexpr expected_storage_base(in_place_t) : m_has_val(true) {}
|
constexpr expected_storage_base(in_place_t) : m_has_val(true) {}
|
||||||
|
@ -548,7 +587,9 @@ template <class E> struct expected_storage_base<void, E, false, true> {
|
||||||
: m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
|
: m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
|
||||||
|
|
||||||
~expected_storage_base() = default;
|
~expected_storage_base() = default;
|
||||||
struct dummy {};
|
|
||||||
|
struct dummy {
|
||||||
|
};
|
||||||
union {
|
union {
|
||||||
unexpected<E> m_unexpect;
|
unexpected<E> m_unexpect;
|
||||||
dummy m_val;
|
dummy m_val;
|
||||||
|
@ -557,8 +598,10 @@ template <class E> struct expected_storage_base<void, E, false, true> {
|
||||||
};
|
};
|
||||||
|
|
||||||
// `T` is `void`, `E` is not trivially-destructible
|
// `T` is `void`, `E` is not trivially-destructible
|
||||||
template <class E> struct expected_storage_base<void, E, false, false> {
|
template<class E>
|
||||||
|
struct expected_storage_base<void, E, false, false> {
|
||||||
constexpr expected_storage_base() : m_dummy(), m_has_val(true) {}
|
constexpr expected_storage_base() : m_dummy(), m_has_val(true) {}
|
||||||
|
|
||||||
constexpr expected_storage_base(no_init_t) : m_dummy(), m_has_val(false) {}
|
constexpr expected_storage_base(no_init_t) : m_dummy(), m_has_val(false) {}
|
||||||
|
|
||||||
constexpr expected_storage_base(in_place_t) : m_dummy(), m_has_val(true) {}
|
constexpr expected_storage_base(in_place_t) : m_dummy(), m_has_val(true) {}
|
||||||
|
@ -596,17 +639,20 @@ template <class T, class E>
|
||||||
struct expected_operations_base : expected_storage_base<T, E> {
|
struct expected_operations_base : expected_storage_base<T, E> {
|
||||||
using expected_storage_base<T, E>::expected_storage_base;
|
using expected_storage_base<T, E>::expected_storage_base;
|
||||||
|
|
||||||
template <class... Args> void construct(Args &&... args) noexcept {
|
template<class... Args>
|
||||||
|
void construct(Args &&... args) noexcept {
|
||||||
new(std::addressof(this->m_val)) T(std::forward<Args>(args)...);
|
new(std::addressof(this->m_val)) T(std::forward<Args>(args)...);
|
||||||
this->m_has_val = true;
|
this->m_has_val = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Rhs> void construct_with(Rhs &&rhs) noexcept {
|
template<class Rhs>
|
||||||
|
void construct_with(Rhs &&rhs) noexcept {
|
||||||
new(std::addressof(this->m_val)) T(std::forward<Rhs>(rhs).get());
|
new(std::addressof(this->m_val)) T(std::forward<Rhs>(rhs).get());
|
||||||
this->m_has_val = true;
|
this->m_has_val = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class... Args> void construct_error(Args &&... args) noexcept {
|
template<class... Args>
|
||||||
|
void construct_error(Args &&... args) noexcept {
|
||||||
new(std::addressof(this->m_unexpect))
|
new(std::addressof(this->m_unexpect))
|
||||||
unexpected<E>(std::forward<Args>(args)...);
|
unexpected<E>(std::forward<Args>(args)...);
|
||||||
this->m_has_val = false;
|
this->m_has_val = false;
|
||||||
|
@ -728,7 +774,8 @@ struct expected_operations_base : expected_storage_base<T, E> {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// The common part of move/copy assigning
|
// The common part of move/copy assigning
|
||||||
template <class Rhs> void assign_common(Rhs &&rhs) {
|
template<class Rhs>
|
||||||
|
void assign_common(Rhs &&rhs) {
|
||||||
if (this->m_has_val) {
|
if (this->m_has_val) {
|
||||||
if (rhs.m_has_val) {
|
if (rhs.m_has_val) {
|
||||||
get() = std::forward<Rhs>(rhs).get();
|
get() = std::forward<Rhs>(rhs).get();
|
||||||
|
@ -746,23 +793,33 @@ struct expected_operations_base : expected_storage_base<T, E> {
|
||||||
bool has_value() const { return this->m_has_val; }
|
bool has_value() const { return this->m_has_val; }
|
||||||
|
|
||||||
TL_EXPECTED_11_CONSTEXPR T &get() &{ return this->m_val; }
|
TL_EXPECTED_11_CONSTEXPR T &get() &{ return this->m_val; }
|
||||||
|
|
||||||
constexpr const T &get() const &{ return this->m_val; }
|
constexpr const T &get() const &{ return this->m_val; }
|
||||||
|
|
||||||
TL_EXPECTED_11_CONSTEXPR T &&get() &&{ return std::move(this->m_val); }
|
TL_EXPECTED_11_CONSTEXPR T &&get() &&{ return std::move(this->m_val); }
|
||||||
|
|
||||||
#ifndef TL_EXPECTED_NO_CONSTRR
|
#ifndef TL_EXPECTED_NO_CONSTRR
|
||||||
|
|
||||||
constexpr const T &&get() const &&{ return std::move(this->m_val); }
|
constexpr const T &&get() const &&{ return std::move(this->m_val); }
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
TL_EXPECTED_11_CONSTEXPR unexpected<E> &geterr() &{
|
TL_EXPECTED_11_CONSTEXPR unexpected<E> &geterr() &{
|
||||||
return this->m_unexpect;
|
return this->m_unexpect;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr const unexpected<E> &geterr() const &{ return this->m_unexpect; }
|
constexpr const unexpected<E> &geterr() const &{ return this->m_unexpect; }
|
||||||
|
|
||||||
TL_EXPECTED_11_CONSTEXPR unexpected<E> &&geterr() &&{
|
TL_EXPECTED_11_CONSTEXPR unexpected<E> &&geterr() &&{
|
||||||
return std::move(this->m_unexpect);
|
return std::move(this->m_unexpect);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef TL_EXPECTED_NO_CONSTRR
|
#ifndef TL_EXPECTED_NO_CONSTRR
|
||||||
|
|
||||||
constexpr const unexpected<E> &&geterr() const &&{
|
constexpr const unexpected<E> &&geterr() const &&{
|
||||||
return std::move(this->m_unexpect);
|
return std::move(this->m_unexpect);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
TL_EXPECTED_11_CONSTEXPR void destroy_val() {
|
TL_EXPECTED_11_CONSTEXPR void destroy_val() {
|
||||||
|
@ -776,21 +833,25 @@ template <class E>
|
||||||
struct expected_operations_base<void, E> : expected_storage_base<void, E> {
|
struct expected_operations_base<void, E> : expected_storage_base<void, E> {
|
||||||
using expected_storage_base<void, E>::expected_storage_base;
|
using expected_storage_base<void, E>::expected_storage_base;
|
||||||
|
|
||||||
template <class... Args> void construct() noexcept { this->m_has_val = true; }
|
template<class... Args>
|
||||||
|
void construct() noexcept { this->m_has_val = true; }
|
||||||
|
|
||||||
// This function doesn't use its argument, but needs it so that code in
|
// This function doesn't use its argument, but needs it so that code in
|
||||||
// levels above this can work independently of whether T is void
|
// levels above this can work independently of whether T is void
|
||||||
template <class Rhs> void construct_with(Rhs &&) noexcept {
|
template<class Rhs>
|
||||||
|
void construct_with(Rhs &&) noexcept {
|
||||||
this->m_has_val = true;
|
this->m_has_val = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class... Args> void construct_error(Args &&... args) noexcept {
|
template<class... Args>
|
||||||
|
void construct_error(Args &&... args) noexcept {
|
||||||
new(std::addressof(this->m_unexpect))
|
new(std::addressof(this->m_unexpect))
|
||||||
unexpected<E>(std::forward<Args>(args)...);
|
unexpected<E>(std::forward<Args>(args)...);
|
||||||
this->m_has_val = false;
|
this->m_has_val = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Rhs> void assign(Rhs &&rhs) noexcept {
|
template<class Rhs>
|
||||||
|
void assign(Rhs &&rhs) noexcept {
|
||||||
if (!this->m_has_val) {
|
if (!this->m_has_val) {
|
||||||
if (rhs.m_has_val) {
|
if (rhs.m_has_val) {
|
||||||
geterr().~unexpected<E>();
|
geterr().~unexpected<E>();
|
||||||
|
@ -810,14 +871,19 @@ struct expected_operations_base<void, E> : expected_storage_base<void, E> {
|
||||||
TL_EXPECTED_11_CONSTEXPR unexpected<E> &geterr() &{
|
TL_EXPECTED_11_CONSTEXPR unexpected<E> &geterr() &{
|
||||||
return this->m_unexpect;
|
return this->m_unexpect;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr const unexpected<E> &geterr() const &{ return this->m_unexpect; }
|
constexpr const unexpected<E> &geterr() const &{ return this->m_unexpect; }
|
||||||
|
|
||||||
TL_EXPECTED_11_CONSTEXPR unexpected<E> &&geterr() &&{
|
TL_EXPECTED_11_CONSTEXPR unexpected<E> &&geterr() &&{
|
||||||
return std::move(this->m_unexpect);
|
return std::move(this->m_unexpect);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef TL_EXPECTED_NO_CONSTRR
|
#ifndef TL_EXPECTED_NO_CONSTRR
|
||||||
|
|
||||||
constexpr const unexpected<E> &&geterr() const &&{
|
constexpr const unexpected<E> &&geterr() const &&{
|
||||||
return std::move(this->m_unexpect);
|
return std::move(this->m_unexpect);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
TL_EXPECTED_11_CONSTEXPR void destroy_val() {
|
TL_EXPECTED_11_CONSTEXPR void destroy_val() {
|
||||||
|
@ -840,6 +906,7 @@ struct expected_copy_base<T, E, false> : expected_operations_base<T, E> {
|
||||||
using expected_operations_base<T, E>::expected_operations_base;
|
using expected_operations_base<T, E>::expected_operations_base;
|
||||||
|
|
||||||
expected_copy_base() = default;
|
expected_copy_base() = default;
|
||||||
|
|
||||||
expected_copy_base(const expected_copy_base &rhs)
|
expected_copy_base(const expected_copy_base &rhs)
|
||||||
: expected_operations_base<T, E>(no_init) {
|
: expected_operations_base<T, E>(no_init) {
|
||||||
if (rhs.has_value()) {
|
if (rhs.has_value()) {
|
||||||
|
@ -850,7 +917,9 @@ struct expected_copy_base<T, E, false> : expected_operations_base<T, E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
expected_copy_base(expected_copy_base &&rhs) = default;
|
expected_copy_base(expected_copy_base &&rhs) = default;
|
||||||
|
|
||||||
expected_copy_base &operator=(const expected_copy_base &rhs) = default;
|
expected_copy_base &operator=(const expected_copy_base &rhs) = default;
|
||||||
|
|
||||||
expected_copy_base &operator=(expected_copy_base &&rhs) = default;
|
expected_copy_base &operator=(expected_copy_base &&rhs) = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -869,11 +938,13 @@ struct expected_move_base : expected_copy_base<T, E> {
|
||||||
#else
|
#else
|
||||||
template <class T, class E, bool = false> struct expected_move_base;
|
template <class T, class E, bool = false> struct expected_move_base;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template<class T, class E>
|
template<class T, class E>
|
||||||
struct expected_move_base<T, E, false> : expected_copy_base<T, E> {
|
struct expected_move_base<T, E, false> : expected_copy_base<T, E> {
|
||||||
using expected_copy_base<T, E>::expected_copy_base;
|
using expected_copy_base<T, E>::expected_copy_base;
|
||||||
|
|
||||||
expected_move_base() = default;
|
expected_move_base() = default;
|
||||||
|
|
||||||
expected_move_base(const expected_move_base &rhs) = default;
|
expected_move_base(const expected_move_base &rhs) = default;
|
||||||
|
|
||||||
expected_move_base(expected_move_base &&rhs) noexcept(
|
expected_move_base(expected_move_base &&rhs) noexcept(
|
||||||
|
@ -885,7 +956,9 @@ struct expected_move_base<T, E, false> : expected_copy_base<T, E> {
|
||||||
this->construct_error(std::move(rhs.geterr()));
|
this->construct_error(std::move(rhs.geterr()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
expected_move_base &operator=(const expected_move_base &rhs) = default;
|
expected_move_base &operator=(const expected_move_base &rhs) = default;
|
||||||
|
|
||||||
expected_move_base &operator=(expected_move_base &&rhs) = default;
|
expected_move_base &operator=(expected_move_base &&rhs) = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -907,13 +980,16 @@ struct expected_copy_assign_base<T, E, false> : expected_move_base<T, E> {
|
||||||
using expected_move_base<T, E>::expected_move_base;
|
using expected_move_base<T, E>::expected_move_base;
|
||||||
|
|
||||||
expected_copy_assign_base() = default;
|
expected_copy_assign_base() = default;
|
||||||
|
|
||||||
expected_copy_assign_base(const expected_copy_assign_base &rhs) = default;
|
expected_copy_assign_base(const expected_copy_assign_base &rhs) = default;
|
||||||
|
|
||||||
expected_copy_assign_base(expected_copy_assign_base &&rhs) = default;
|
expected_copy_assign_base(expected_copy_assign_base &&rhs) = default;
|
||||||
|
|
||||||
expected_copy_assign_base &operator=(const expected_copy_assign_base &rhs) {
|
expected_copy_assign_base &operator=(const expected_copy_assign_base &rhs) {
|
||||||
this->assign(rhs);
|
this->assign(rhs);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
expected_copy_assign_base &
|
expected_copy_assign_base &
|
||||||
operator=(expected_copy_assign_base &&rhs) = default;
|
operator=(expected_copy_assign_base &&rhs) = default;
|
||||||
};
|
};
|
||||||
|
@ -945,6 +1021,7 @@ struct expected_move_assign_base<T, E, false>
|
||||||
using expected_copy_assign_base<T, E>::expected_copy_assign_base;
|
using expected_copy_assign_base<T, E>::expected_copy_assign_base;
|
||||||
|
|
||||||
expected_move_assign_base() = default;
|
expected_move_assign_base() = default;
|
||||||
|
|
||||||
expected_move_assign_base(const expected_move_assign_base &rhs) = default;
|
expected_move_assign_base(const expected_move_assign_base &rhs) = default;
|
||||||
|
|
||||||
expected_move_assign_base(expected_move_assign_base &&rhs) = default;
|
expected_move_assign_base(expected_move_assign_base &&rhs) = default;
|
||||||
|
@ -970,10 +1047,14 @@ template <class T, class E,
|
||||||
std::is_move_constructible<E>::value)>
|
std::is_move_constructible<E>::value)>
|
||||||
struct expected_delete_ctor_base {
|
struct expected_delete_ctor_base {
|
||||||
expected_delete_ctor_base() = default;
|
expected_delete_ctor_base() = default;
|
||||||
|
|
||||||
expected_delete_ctor_base(const expected_delete_ctor_base &) = default;
|
expected_delete_ctor_base(const expected_delete_ctor_base &) = default;
|
||||||
|
|
||||||
expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = default;
|
expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = default;
|
||||||
|
|
||||||
expected_delete_ctor_base &
|
expected_delete_ctor_base &
|
||||||
operator=(const expected_delete_ctor_base &) = default;
|
operator=(const expected_delete_ctor_base &) = default;
|
||||||
|
|
||||||
expected_delete_ctor_base &
|
expected_delete_ctor_base &
|
||||||
operator=(expected_delete_ctor_base &&) noexcept = default;
|
operator=(expected_delete_ctor_base &&) noexcept = default;
|
||||||
};
|
};
|
||||||
|
@ -981,10 +1062,14 @@ struct expected_delete_ctor_base {
|
||||||
template<class T, class E>
|
template<class T, class E>
|
||||||
struct expected_delete_ctor_base<T, E, true, false> {
|
struct expected_delete_ctor_base<T, E, true, false> {
|
||||||
expected_delete_ctor_base() = default;
|
expected_delete_ctor_base() = default;
|
||||||
|
|
||||||
expected_delete_ctor_base(const expected_delete_ctor_base &) = default;
|
expected_delete_ctor_base(const expected_delete_ctor_base &) = default;
|
||||||
|
|
||||||
expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = delete;
|
expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = delete;
|
||||||
|
|
||||||
expected_delete_ctor_base &
|
expected_delete_ctor_base &
|
||||||
operator=(const expected_delete_ctor_base &) = default;
|
operator=(const expected_delete_ctor_base &) = default;
|
||||||
|
|
||||||
expected_delete_ctor_base &
|
expected_delete_ctor_base &
|
||||||
operator=(expected_delete_ctor_base &&) noexcept = default;
|
operator=(expected_delete_ctor_base &&) noexcept = default;
|
||||||
};
|
};
|
||||||
|
@ -992,10 +1077,14 @@ struct expected_delete_ctor_base<T, E, true, false> {
|
||||||
template<class T, class E>
|
template<class T, class E>
|
||||||
struct expected_delete_ctor_base<T, E, false, true> {
|
struct expected_delete_ctor_base<T, E, false, true> {
|
||||||
expected_delete_ctor_base() = default;
|
expected_delete_ctor_base() = default;
|
||||||
|
|
||||||
expected_delete_ctor_base(const expected_delete_ctor_base &) = delete;
|
expected_delete_ctor_base(const expected_delete_ctor_base &) = delete;
|
||||||
|
|
||||||
expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = default;
|
expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = default;
|
||||||
|
|
||||||
expected_delete_ctor_base &
|
expected_delete_ctor_base &
|
||||||
operator=(const expected_delete_ctor_base &) = default;
|
operator=(const expected_delete_ctor_base &) = default;
|
||||||
|
|
||||||
expected_delete_ctor_base &
|
expected_delete_ctor_base &
|
||||||
operator=(expected_delete_ctor_base &&) noexcept = default;
|
operator=(expected_delete_ctor_base &&) noexcept = default;
|
||||||
};
|
};
|
||||||
|
@ -1003,10 +1092,14 @@ struct expected_delete_ctor_base<T, E, false, true> {
|
||||||
template<class T, class E>
|
template<class T, class E>
|
||||||
struct expected_delete_ctor_base<T, E, false, false> {
|
struct expected_delete_ctor_base<T, E, false, false> {
|
||||||
expected_delete_ctor_base() = default;
|
expected_delete_ctor_base() = default;
|
||||||
|
|
||||||
expected_delete_ctor_base(const expected_delete_ctor_base &) = delete;
|
expected_delete_ctor_base(const expected_delete_ctor_base &) = delete;
|
||||||
|
|
||||||
expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = delete;
|
expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = delete;
|
||||||
|
|
||||||
expected_delete_ctor_base &
|
expected_delete_ctor_base &
|
||||||
operator=(const expected_delete_ctor_base &) = default;
|
operator=(const expected_delete_ctor_base &) = default;
|
||||||
|
|
||||||
expected_delete_ctor_base &
|
expected_delete_ctor_base &
|
||||||
operator=(expected_delete_ctor_base &&) noexcept = default;
|
operator=(expected_delete_ctor_base &&) noexcept = default;
|
||||||
};
|
};
|
||||||
|
@ -1025,11 +1118,15 @@ template <class T, class E,
|
||||||
std::is_move_assignable<E>::value)>
|
std::is_move_assignable<E>::value)>
|
||||||
struct expected_delete_assign_base {
|
struct expected_delete_assign_base {
|
||||||
expected_delete_assign_base() = default;
|
expected_delete_assign_base() = default;
|
||||||
|
|
||||||
expected_delete_assign_base(const expected_delete_assign_base &) = default;
|
expected_delete_assign_base(const expected_delete_assign_base &) = default;
|
||||||
|
|
||||||
expected_delete_assign_base(expected_delete_assign_base &&) noexcept =
|
expected_delete_assign_base(expected_delete_assign_base &&) noexcept =
|
||||||
default;
|
default;
|
||||||
|
|
||||||
expected_delete_assign_base &
|
expected_delete_assign_base &
|
||||||
operator=(const expected_delete_assign_base &) = default;
|
operator=(const expected_delete_assign_base &) = default;
|
||||||
|
|
||||||
expected_delete_assign_base &
|
expected_delete_assign_base &
|
||||||
operator=(expected_delete_assign_base &&) noexcept = default;
|
operator=(expected_delete_assign_base &&) noexcept = default;
|
||||||
};
|
};
|
||||||
|
@ -1037,11 +1134,15 @@ struct expected_delete_assign_base {
|
||||||
template<class T, class E>
|
template<class T, class E>
|
||||||
struct expected_delete_assign_base<T, E, true, false> {
|
struct expected_delete_assign_base<T, E, true, false> {
|
||||||
expected_delete_assign_base() = default;
|
expected_delete_assign_base() = default;
|
||||||
|
|
||||||
expected_delete_assign_base(const expected_delete_assign_base &) = default;
|
expected_delete_assign_base(const expected_delete_assign_base &) = default;
|
||||||
|
|
||||||
expected_delete_assign_base(expected_delete_assign_base &&) noexcept =
|
expected_delete_assign_base(expected_delete_assign_base &&) noexcept =
|
||||||
default;
|
default;
|
||||||
|
|
||||||
expected_delete_assign_base &
|
expected_delete_assign_base &
|
||||||
operator=(const expected_delete_assign_base &) = default;
|
operator=(const expected_delete_assign_base &) = default;
|
||||||
|
|
||||||
expected_delete_assign_base &
|
expected_delete_assign_base &
|
||||||
operator=(expected_delete_assign_base &&) noexcept = delete;
|
operator=(expected_delete_assign_base &&) noexcept = delete;
|
||||||
};
|
};
|
||||||
|
@ -1049,11 +1150,15 @@ struct expected_delete_assign_base<T, E, true, false> {
|
||||||
template<class T, class E>
|
template<class T, class E>
|
||||||
struct expected_delete_assign_base<T, E, false, true> {
|
struct expected_delete_assign_base<T, E, false, true> {
|
||||||
expected_delete_assign_base() = default;
|
expected_delete_assign_base() = default;
|
||||||
|
|
||||||
expected_delete_assign_base(const expected_delete_assign_base &) = default;
|
expected_delete_assign_base(const expected_delete_assign_base &) = default;
|
||||||
|
|
||||||
expected_delete_assign_base(expected_delete_assign_base &&) noexcept =
|
expected_delete_assign_base(expected_delete_assign_base &&) noexcept =
|
||||||
default;
|
default;
|
||||||
|
|
||||||
expected_delete_assign_base &
|
expected_delete_assign_base &
|
||||||
operator=(const expected_delete_assign_base &) = delete;
|
operator=(const expected_delete_assign_base &) = delete;
|
||||||
|
|
||||||
expected_delete_assign_base &
|
expected_delete_assign_base &
|
||||||
operator=(expected_delete_assign_base &&) noexcept = default;
|
operator=(expected_delete_assign_base &&) noexcept = default;
|
||||||
};
|
};
|
||||||
|
@ -1061,11 +1166,15 @@ struct expected_delete_assign_base<T, E, false, true> {
|
||||||
template<class T, class E>
|
template<class T, class E>
|
||||||
struct expected_delete_assign_base<T, E, false, false> {
|
struct expected_delete_assign_base<T, E, false, false> {
|
||||||
expected_delete_assign_base() = default;
|
expected_delete_assign_base() = default;
|
||||||
|
|
||||||
expected_delete_assign_base(const expected_delete_assign_base &) = default;
|
expected_delete_assign_base(const expected_delete_assign_base &) = default;
|
||||||
|
|
||||||
expected_delete_assign_base(expected_delete_assign_base &&) noexcept =
|
expected_delete_assign_base(expected_delete_assign_base &&) noexcept =
|
||||||
default;
|
default;
|
||||||
|
|
||||||
expected_delete_assign_base &
|
expected_delete_assign_base &
|
||||||
operator=(const expected_delete_assign_base &) = delete;
|
operator=(const expected_delete_assign_base &) = delete;
|
||||||
|
|
||||||
expected_delete_assign_base &
|
expected_delete_assign_base &
|
||||||
operator=(expected_delete_assign_base &&) noexcept = delete;
|
operator=(expected_delete_assign_base &&) noexcept = delete;
|
||||||
};
|
};
|
||||||
|
@ -1084,12 +1193,16 @@ template <class T, class E,
|
||||||
std::is_default_constructible<T>::value || std::is_void<T>::value>
|
std::is_default_constructible<T>::value || std::is_void<T>::value>
|
||||||
struct expected_default_ctor_base {
|
struct expected_default_ctor_base {
|
||||||
constexpr expected_default_ctor_base() noexcept = default;
|
constexpr expected_default_ctor_base() noexcept = default;
|
||||||
|
|
||||||
constexpr expected_default_ctor_base(
|
constexpr expected_default_ctor_base(
|
||||||
expected_default_ctor_base const &) noexcept = default;
|
expected_default_ctor_base const &) noexcept = default;
|
||||||
|
|
||||||
constexpr expected_default_ctor_base(expected_default_ctor_base &&) noexcept =
|
constexpr expected_default_ctor_base(expected_default_ctor_base &&) noexcept =
|
||||||
default;
|
default;
|
||||||
|
|
||||||
expected_default_ctor_base &
|
expected_default_ctor_base &
|
||||||
operator=(expected_default_ctor_base const &) noexcept = default;
|
operator=(expected_default_ctor_base const &) noexcept = default;
|
||||||
|
|
||||||
expected_default_ctor_base &
|
expected_default_ctor_base &
|
||||||
operator=(expected_default_ctor_base &&) noexcept = default;
|
operator=(expected_default_ctor_base &&) noexcept = default;
|
||||||
|
|
||||||
|
@ -1097,14 +1210,19 @@ struct expected_default_ctor_base {
|
||||||
};
|
};
|
||||||
|
|
||||||
// This specialization is for when T is not default constructible
|
// This specialization is for when T is not default constructible
|
||||||
template <class T, class E> struct expected_default_ctor_base<T, E, false> {
|
template<class T, class E>
|
||||||
|
struct expected_default_ctor_base<T, E, false> {
|
||||||
constexpr expected_default_ctor_base() noexcept = delete;
|
constexpr expected_default_ctor_base() noexcept = delete;
|
||||||
|
|
||||||
constexpr expected_default_ctor_base(
|
constexpr expected_default_ctor_base(
|
||||||
expected_default_ctor_base const &) noexcept = default;
|
expected_default_ctor_base const &) noexcept = default;
|
||||||
|
|
||||||
constexpr expected_default_ctor_base(expected_default_ctor_base &&) noexcept =
|
constexpr expected_default_ctor_base(expected_default_ctor_base &&) noexcept =
|
||||||
default;
|
default;
|
||||||
|
|
||||||
expected_default_ctor_base &
|
expected_default_ctor_base &
|
||||||
operator=(expected_default_ctor_base const &) noexcept = default;
|
operator=(expected_default_ctor_base const &) noexcept = default;
|
||||||
|
|
||||||
expected_default_ctor_base &
|
expected_default_ctor_base &
|
||||||
operator=(expected_default_ctor_base &&) noexcept = default;
|
operator=(expected_default_ctor_base &&) noexcept = default;
|
||||||
|
|
||||||
|
@ -1112,7 +1230,8 @@ template <class T, class E> struct expected_default_ctor_base<T, E, false> {
|
||||||
};
|
};
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
template <class E> class bad_expected_access : public std::exception {
|
template<class E>
|
||||||
|
class bad_expected_access : public std::exception {
|
||||||
public:
|
public:
|
||||||
explicit bad_expected_access(E e) : m_val(std::move(e)) {}
|
explicit bad_expected_access(E e) : m_val(std::move(e)) {}
|
||||||
|
|
||||||
|
@ -1121,8 +1240,11 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
const E &error() const &{ return m_val; }
|
const E &error() const &{ return m_val; }
|
||||||
|
|
||||||
E &error() &{ return m_val; }
|
E &error() &{ return m_val; }
|
||||||
|
|
||||||
const E &&error() const &&{ return std::move(m_val); }
|
const E &&error() const &&{ return std::move(m_val); }
|
||||||
|
|
||||||
E &&error() &&{ return std::move(m_val); }
|
E &&error() &&{ return std::move(m_val); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -1151,8 +1273,11 @@ class expected : private detail::expected_move_assign_base<T, E>,
|
||||||
static_assert(!std::is_reference<E>::value, "E must not be a reference");
|
static_assert(!std::is_reference<E>::value, "E must not be a reference");
|
||||||
|
|
||||||
T *valptr() { return std::addressof(this->m_val); }
|
T *valptr() { return std::addressof(this->m_val); }
|
||||||
|
|
||||||
const T *valptr() const { return std::addressof(this->m_val); }
|
const T *valptr() const { return std::addressof(this->m_val); }
|
||||||
|
|
||||||
unexpected<E> *errptr() { return std::addressof(this->m_unexpect); }
|
unexpected<E> *errptr() { return std::addressof(this->m_unexpect); }
|
||||||
|
|
||||||
const unexpected<E> *errptr() const { return std::addressof(this->m_unexpect); }
|
const unexpected<E> *errptr() const { return std::addressof(this->m_unexpect); }
|
||||||
|
|
||||||
template<class U = T,
|
template<class U = T,
|
||||||
|
@ -1160,6 +1285,7 @@ class expected : private detail::expected_move_assign_base<T, E>,
|
||||||
U &val() {
|
U &val() {
|
||||||
return this->m_val;
|
return this->m_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
unexpected<E> &err() { return this->m_unexpect; }
|
unexpected<E> &err() { return this->m_unexpect; }
|
||||||
|
|
||||||
template<class U = T,
|
template<class U = T,
|
||||||
|
@ -1167,6 +1293,7 @@ class expected : private detail::expected_move_assign_base<T, E>,
|
||||||
const U &val() const {
|
const U &val() const {
|
||||||
return this->m_val;
|
return this->m_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
const unexpected<E> &err() const { return this->m_unexpect; }
|
const unexpected<E> &err() const { return this->m_unexpect; }
|
||||||
|
|
||||||
using impl_base = detail::expected_move_assign_base<T, E>;
|
using impl_base = detail::expected_move_assign_base<T, E>;
|
||||||
|
@ -1179,6 +1306,7 @@ public:
|
||||||
|
|
||||||
#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
|
#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
|
||||||
!defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
|
!defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
|
||||||
|
|
||||||
/// \group and_then
|
/// \group and_then
|
||||||
/// Carries out some operation which returns an expected on the stored object
|
/// Carries out some operation which returns an expected on the stored object
|
||||||
/// if there is one. \requires `std::invoke(std::forward<F>(f), value())`
|
/// if there is one. \requires `std::invoke(std::forward<F>(f), value())`
|
||||||
|
@ -1188,28 +1316,34 @@ public:
|
||||||
/// otherwise the return value of `std::invoke(std::forward<F>(f), value())`
|
/// otherwise the return value of `std::invoke(std::forward<F>(f), value())`
|
||||||
/// is returned.
|
/// is returned.
|
||||||
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &;
|
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &;
|
||||||
template <class F> TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) & {
|
template<class F>
|
||||||
|
TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) &{
|
||||||
return and_then_impl(*this, std::forward<F>(f));
|
return and_then_impl(*this, std::forward<F>(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \group and_then
|
/// \group and_then
|
||||||
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &&;
|
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &&;
|
||||||
template <class F> TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) && {
|
template<class F>
|
||||||
|
TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) &&{
|
||||||
return and_then_impl(std::move(*this), std::forward<F>(f));
|
return and_then_impl(std::move(*this), std::forward<F>(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \group and_then
|
/// \group and_then
|
||||||
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &;
|
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &;
|
||||||
template <class F> constexpr auto and_then(F &&f) const & {
|
template<class F>
|
||||||
|
constexpr auto and_then(F &&f) const &{
|
||||||
return and_then_impl(*this, std::forward<F>(f));
|
return and_then_impl(*this, std::forward<F>(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef TL_EXPECTED_NO_CONSTRR
|
#ifndef TL_EXPECTED_NO_CONSTRR
|
||||||
|
|
||||||
/// \group and_then
|
/// \group and_then
|
||||||
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &&;
|
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &&;
|
||||||
template <class F> constexpr auto and_then(F &&f) const && {
|
template<class F>
|
||||||
|
constexpr auto and_then(F &&f) const &&{
|
||||||
return and_then_impl(std::move(*this), std::forward<F>(f));
|
return and_then_impl(std::move(*this), std::forward<F>(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
@ -1257,6 +1391,7 @@ public:
|
||||||
|
|
||||||
#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
|
#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
|
||||||
!defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
|
!defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
|
||||||
|
|
||||||
/// \brief Carries out some operation on the stored object if there is one.
|
/// \brief Carries out some operation on the stored object if there is one.
|
||||||
/// \returns Let `U` be the result of `std::invoke(std::forward<F>(f),
|
/// \returns Let `U` be the result of `std::invoke(std::forward<F>(f),
|
||||||
/// value())`. If `U` is `void`, returns an `expected<monostate,E>, otherwise
|
/// value())`. If `U` is `void`, returns an `expected<monostate,E>, otherwise
|
||||||
|
@ -1267,27 +1402,32 @@ public:
|
||||||
///
|
///
|
||||||
/// \group map
|
/// \group map
|
||||||
/// \synopsis template <class F> constexpr auto map(F &&f) &;
|
/// \synopsis template <class F> constexpr auto map(F &&f) &;
|
||||||
template <class F> TL_EXPECTED_11_CONSTEXPR auto map(F &&f) & {
|
template<class F>
|
||||||
|
TL_EXPECTED_11_CONSTEXPR auto map(F &&f) &{
|
||||||
return expected_map_impl(*this, std::forward<F>(f));
|
return expected_map_impl(*this, std::forward<F>(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \group map
|
/// \group map
|
||||||
/// \synopsis template <class F> constexpr auto map(F &&f) &&;
|
/// \synopsis template <class F> constexpr auto map(F &&f) &&;
|
||||||
template <class F> TL_EXPECTED_11_CONSTEXPR auto map(F &&f) && {
|
template<class F>
|
||||||
|
TL_EXPECTED_11_CONSTEXPR auto map(F &&f) &&{
|
||||||
return expected_map_impl(std::move(*this), std::forward<F>(f));
|
return expected_map_impl(std::move(*this), std::forward<F>(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \group map
|
/// \group map
|
||||||
/// \synopsis template <class F> constexpr auto map(F &&f) const &;
|
/// \synopsis template <class F> constexpr auto map(F &&f) const &;
|
||||||
template <class F> constexpr auto map(F &&f) const & {
|
template<class F>
|
||||||
|
constexpr auto map(F &&f) const &{
|
||||||
return expected_map_impl(*this, std::forward<F>(f));
|
return expected_map_impl(*this, std::forward<F>(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \group map
|
/// \group map
|
||||||
/// \synopsis template <class F> constexpr auto map(F &&f) const &&;
|
/// \synopsis template <class F> constexpr auto map(F &&f) const &&;
|
||||||
template <class F> constexpr auto map(F &&f) const && {
|
template<class F>
|
||||||
|
constexpr auto map(F &&f) const &&{
|
||||||
return expected_map_impl(std::move(*this), std::forward<F>(f));
|
return expected_map_impl(std::move(*this), std::forward<F>(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
/// \brief Carries out some operation on the stored object if there is one.
|
/// \brief Carries out some operation on the stored object if there is one.
|
||||||
/// \returns Let `U` be the result of `std::invoke(std::forward<F>(f),
|
/// \returns Let `U` be the result of `std::invoke(std::forward<F>(f),
|
||||||
|
@ -1338,6 +1478,7 @@ public:
|
||||||
|
|
||||||
#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
|
#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
|
||||||
!defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
|
!defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
|
||||||
|
|
||||||
/// \brief Carries out some operation on the stored unexpected object if there
|
/// \brief Carries out some operation on the stored unexpected object if there
|
||||||
/// is one.
|
/// is one.
|
||||||
/// \returns Let `U` be the result of `std::invoke(std::forward<F>(f),
|
/// \returns Let `U` be the result of `std::invoke(std::forward<F>(f),
|
||||||
|
@ -1349,27 +1490,32 @@ public:
|
||||||
///
|
///
|
||||||
/// \group map_error
|
/// \group map_error
|
||||||
/// \synopsis template <class F> constexpr auto map_error(F &&f) &;
|
/// \synopsis template <class F> constexpr auto map_error(F &&f) &;
|
||||||
template <class F> TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) & {
|
template<class F>
|
||||||
|
TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) &{
|
||||||
return map_error_impl(*this, std::forward<F>(f));
|
return map_error_impl(*this, std::forward<F>(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \group map_error
|
/// \group map_error
|
||||||
/// \synopsis template <class F> constexpr auto map_error(F &&f) &&;
|
/// \synopsis template <class F> constexpr auto map_error(F &&f) &&;
|
||||||
template <class F> TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) && {
|
template<class F>
|
||||||
|
TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) &&{
|
||||||
return map_error_impl(std::move(*this), std::forward<F>(f));
|
return map_error_impl(std::move(*this), std::forward<F>(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \group map_error
|
/// \group map_error
|
||||||
/// \synopsis template <class F> constexpr auto map_error(F &&f) const &;
|
/// \synopsis template <class F> constexpr auto map_error(F &&f) const &;
|
||||||
template <class F> constexpr auto map_error(F &&f) const & {
|
template<class F>
|
||||||
|
constexpr auto map_error(F &&f) const &{
|
||||||
return map_error_impl(*this, std::forward<F>(f));
|
return map_error_impl(*this, std::forward<F>(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \group map_error
|
/// \group map_error
|
||||||
/// \synopsis template <class F> constexpr auto map_error(F &&f) const &&;
|
/// \synopsis template <class F> constexpr auto map_error(F &&f) const &&;
|
||||||
template <class F> constexpr auto map_error(F &&f) const && {
|
template<class F>
|
||||||
|
constexpr auto map_error(F &&f) const &&{
|
||||||
return map_error_impl(std::move(*this), std::forward<F>(f));
|
return map_error_impl(std::move(*this), std::forward<F>(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
/// \brief Carries out some operation on the stored unexpected object if there
|
/// \brief Carries out some operation on the stored unexpected object if there
|
||||||
/// is one.
|
/// is one.
|
||||||
|
@ -1426,27 +1572,38 @@ public:
|
||||||
/// `std::nullopt`. Otherwise, returns `std::forward<F>(f)(E)`.
|
/// `std::nullopt`. Otherwise, returns `std::forward<F>(f)(E)`.
|
||||||
///
|
///
|
||||||
/// \group or_else
|
/// \group or_else
|
||||||
template <class F> expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) & {
|
template<class F>
|
||||||
|
expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) &{
|
||||||
return or_else_impl(*this, std::forward<F>(f));
|
return or_else_impl(*this, std::forward<F>(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class F> expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) && {
|
template<class F>
|
||||||
|
expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) &&{
|
||||||
return or_else_impl(std::move(*this), std::forward<F>(f));
|
return or_else_impl(std::move(*this), std::forward<F>(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class F> expected constexpr or_else(F &&f) const & {
|
template<class F>
|
||||||
|
expected constexpr or_else(F &&f) const &{
|
||||||
return or_else_impl(*this, std::forward<F>(f));
|
return or_else_impl(*this, std::forward<F>(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef TL_EXPECTED_NO_CONSTRR
|
#ifndef TL_EXPECTED_NO_CONSTRR
|
||||||
template <class F> expected constexpr or_else(F &&f) const && {
|
|
||||||
|
template<class F>
|
||||||
|
expected constexpr or_else(F &&f) const &&{
|
||||||
return or_else_impl(std::move(*this), std::forward<F>(f));
|
return or_else_impl(std::move(*this), std::forward<F>(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
constexpr expected() = default;
|
constexpr expected() = default;
|
||||||
|
|
||||||
constexpr expected(const expected &rhs) = default;
|
constexpr expected(const expected &rhs) = default;
|
||||||
|
|
||||||
constexpr expected(expected &&rhs) = default;
|
constexpr expected(expected &&rhs) = default;
|
||||||
|
|
||||||
expected &operator=(const expected &rhs) = default;
|
expected &operator=(const expected &rhs) = default;
|
||||||
|
|
||||||
expected &operator=(expected &&rhs) = default;
|
expected &operator=(expected &&rhs) = default;
|
||||||
|
|
||||||
template<class... Args,
|
template<class... Args,
|
||||||
|
@ -1805,18 +1962,21 @@ public:
|
||||||
constexpr const U &operator*() const &{
|
constexpr const U &operator*() const &{
|
||||||
return val();
|
return val();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \group deref
|
/// \group deref
|
||||||
template<class U = T,
|
template<class U = T,
|
||||||
detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
|
detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
|
||||||
TL_EXPECTED_11_CONSTEXPR U &operator*() &{
|
TL_EXPECTED_11_CONSTEXPR U &operator*() &{
|
||||||
return val();
|
return val();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \group deref
|
/// \group deref
|
||||||
template<class U = T,
|
template<class U = T,
|
||||||
detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
|
detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
|
||||||
constexpr const U &&operator*() const &&{
|
constexpr const U &&operator*() const &&{
|
||||||
return std::move(val());
|
return std::move(val());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \group deref
|
/// \group deref
|
||||||
template<class U = T,
|
template<class U = T,
|
||||||
detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
|
detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
|
||||||
|
@ -1827,6 +1987,7 @@ public:
|
||||||
/// \returns whether or not the optional has a value
|
/// \returns whether or not the optional has a value
|
||||||
/// \group has_value
|
/// \group has_value
|
||||||
constexpr bool has_value() const noexcept { return this->m_has_val; }
|
constexpr bool has_value() const noexcept { return this->m_has_val; }
|
||||||
|
|
||||||
/// \group has_value
|
/// \group has_value
|
||||||
constexpr explicit operator bool() const noexcept { return this->m_has_val; }
|
constexpr explicit operator bool() const noexcept { return this->m_has_val; }
|
||||||
|
|
||||||
|
@ -1841,6 +2002,7 @@ public:
|
||||||
detail::throw_exception(bad_expected_access<E>(err().value()));
|
detail::throw_exception(bad_expected_access<E>(err().value()));
|
||||||
return val();
|
return val();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \group value
|
/// \group value
|
||||||
template<class U = T,
|
template<class U = T,
|
||||||
detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
|
detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
|
||||||
|
@ -1849,6 +2011,7 @@ public:
|
||||||
detail::throw_exception(bad_expected_access<E>(err().value()));
|
detail::throw_exception(bad_expected_access<E>(err().value()));
|
||||||
return val();
|
return val();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \group value
|
/// \group value
|
||||||
template<class U = T,
|
template<class U = T,
|
||||||
detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
|
detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
|
||||||
|
@ -1857,6 +2020,7 @@ public:
|
||||||
detail::throw_exception(bad_expected_access<E>(err().value()));
|
detail::throw_exception(bad_expected_access<E>(err().value()));
|
||||||
return std::move(val());
|
return std::move(val());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \group value
|
/// \group value
|
||||||
template<class U = T,
|
template<class U = T,
|
||||||
detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
|
detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
|
||||||
|
@ -1872,6 +2036,7 @@ public:
|
||||||
constexpr const E &error() const &{ return err().value(); }
|
constexpr const E &error() const &{ return err().value(); }
|
||||||
/// \group error
|
/// \group error
|
||||||
TL_EXPECTED_11_CONSTEXPR E &error() &{ return err().value(); }
|
TL_EXPECTED_11_CONSTEXPR E &error() &{ return err().value(); }
|
||||||
|
|
||||||
/// \group error
|
/// \group error
|
||||||
constexpr const E &&error() const &&{ return std::move(err().value()); }
|
constexpr const E &&error() const &&{ return std::move(err().value()); }
|
||||||
/// \group error
|
/// \group error
|
||||||
|
@ -1879,14 +2044,17 @@ public:
|
||||||
|
|
||||||
/// \returns the stored value if there is one, otherwise returns `u`
|
/// \returns the stored value if there is one, otherwise returns `u`
|
||||||
/// \group value_or
|
/// \group value_or
|
||||||
template <class U> constexpr T value_or(U &&v) const & {
|
template<class U>
|
||||||
|
constexpr T value_or(U &&v) const &{
|
||||||
static_assert(std::is_copy_constructible<T>::value &&
|
static_assert(std::is_copy_constructible<T>::value &&
|
||||||
std::is_convertible<U &&, T>::value,
|
std::is_convertible<U &&, T>::value,
|
||||||
"T must be copy-constructible and convertible to from U&&");
|
"T must be copy-constructible and convertible to from U&&");
|
||||||
return bool(*this) ? **this : static_cast<T>(std::forward<U>(v));
|
return bool(*this) ? **this : static_cast<T>(std::forward<U>(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \group value_or
|
/// \group value_or
|
||||||
template <class U> TL_EXPECTED_11_CONSTEXPR T value_or(U &&v) && {
|
template<class U>
|
||||||
|
TL_EXPECTED_11_CONSTEXPR T value_or(U &&v) &&{
|
||||||
static_assert(std::is_move_constructible<T>::value &&
|
static_assert(std::is_move_constructible<T>::value &&
|
||||||
std::is_convertible<U &&, T>::value,
|
std::is_convertible<U &&, T>::value,
|
||||||
"T must be move-constructible and convertible to from U&&");
|
"T must be move-constructible and convertible to from U&&");
|
||||||
|
@ -1901,6 +2069,7 @@ template <class Exp> using err_t = typename detail::decay_t<Exp>::error_type;
|
||||||
template<class Exp, class Ret> using ret_t = expected<Ret, err_t<Exp>>;
|
template<class Exp, class Ret> using ret_t = expected<Ret, err_t<Exp>>;
|
||||||
|
|
||||||
#ifdef TL_EXPECTED_CXX14
|
#ifdef TL_EXPECTED_CXX14
|
||||||
|
|
||||||
template<class Exp, class F,
|
template<class Exp, class F,
|
||||||
detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
|
detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
|
||||||
class Ret = decltype(detail::invoke(std::declval<F>(),
|
class Ret = decltype(detail::invoke(std::declval<F>(),
|
||||||
|
@ -1922,6 +2091,7 @@ constexpr auto and_then_impl(Exp &&exp, F &&f) {
|
||||||
return exp.has_value() ? detail::invoke(std::forward<F>(f))
|
return exp.has_value() ? detail::invoke(std::forward<F>(f))
|
||||||
: Ret(unexpect, std::forward<Exp>(exp).error());
|
: Ret(unexpect, std::forward<Exp>(exp).error());
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
template <class> struct TC;
|
template <class> struct TC;
|
||||||
template <class Exp, class F,
|
template <class Exp, class F,
|
||||||
|
@ -1948,6 +2118,7 @@ constexpr auto and_then_impl(Exp &&exp, F &&f) -> Ret {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef TL_EXPECTED_CXX14
|
#ifdef TL_EXPECTED_CXX14
|
||||||
|
|
||||||
template<class Exp, class F,
|
template<class Exp, class F,
|
||||||
detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
|
detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
|
||||||
class Ret = decltype(detail::invoke(std::declval<F>(),
|
class Ret = decltype(detail::invoke(std::declval<F>(),
|
||||||
|
@ -1998,6 +2169,7 @@ auto expected_map_impl(Exp &&exp, F &&f) {
|
||||||
|
|
||||||
return result(unexpect, std::forward<Exp>(exp).error());
|
return result(unexpect, std::forward<Exp>(exp).error());
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
template <class Exp, class F,
|
template <class Exp, class F,
|
||||||
detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
|
detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
|
||||||
|
@ -2059,6 +2231,7 @@ auto expected_map_impl(Exp &&exp, F &&f) -> expected<void, err_t<Exp>> {
|
||||||
|
|
||||||
#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
|
#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
|
||||||
!defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
|
!defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
|
||||||
|
|
||||||
template<class Exp, class F,
|
template<class Exp, class F,
|
||||||
detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
|
detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
|
||||||
class Ret = decltype(detail::invoke(std::declval<F>(),
|
class Ret = decltype(detail::invoke(std::declval<F>(),
|
||||||
|
@ -2071,6 +2244,7 @@ constexpr auto map_error_impl(Exp &&exp, F &&f) {
|
||||||
: result(unexpect, detail::invoke(std::forward<F>(f),
|
: result(unexpect, detail::invoke(std::forward<F>(f),
|
||||||
std::forward<Exp>(exp).error()));
|
std::forward<Exp>(exp).error()));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Exp, class F,
|
template<class Exp, class F,
|
||||||
detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
|
detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
|
||||||
class Ret = decltype(detail::invoke(std::declval<F>(),
|
class Ret = decltype(detail::invoke(std::declval<F>(),
|
||||||
|
@ -2085,6 +2259,7 @@ auto map_error_impl(Exp &&exp, F &&f) {
|
||||||
detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
|
detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
|
||||||
return result(unexpect, monostate{});
|
return result(unexpect, monostate{});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Exp, class F,
|
template<class Exp, class F,
|
||||||
detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
|
detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
|
||||||
class Ret = decltype(detail::invoke(std::declval<F>(),
|
class Ret = decltype(detail::invoke(std::declval<F>(),
|
||||||
|
@ -2097,6 +2272,7 @@ constexpr auto map_error_impl(Exp &&exp, F &&f) {
|
||||||
: result(unexpect, detail::invoke(std::forward<F>(f),
|
: result(unexpect, detail::invoke(std::forward<F>(f),
|
||||||
std::forward<Exp>(exp).error()));
|
std::forward<Exp>(exp).error()));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Exp, class F,
|
template<class Exp, class F,
|
||||||
detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
|
detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
|
||||||
class Ret = decltype(detail::invoke(std::declval<F>(),
|
class Ret = decltype(detail::invoke(std::declval<F>(),
|
||||||
|
@ -2111,6 +2287,7 @@ auto map_error_impl(Exp &&exp, F &&f) {
|
||||||
detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
|
detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
|
||||||
return result(unexpect, monostate{});
|
return result(unexpect, monostate{});
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
template <class Exp, class F,
|
template <class Exp, class F,
|
||||||
detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
|
detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
|
||||||
|
@ -2174,6 +2351,7 @@ auto map_error_impl(Exp &&exp, F &&f) -> expected<exp_t<Exp>, monostate> {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef TL_EXPECTED_CXX14
|
#ifdef TL_EXPECTED_CXX14
|
||||||
|
|
||||||
template<class Exp, class F,
|
template<class Exp, class F,
|
||||||
class Ret = decltype(detail::invoke(std::declval<F>(),
|
class Ret = decltype(detail::invoke(std::declval<F>(),
|
||||||
std::declval<Exp>().error())),
|
std::declval<Exp>().error())),
|
||||||
|
@ -2195,6 +2373,7 @@ detail::decay_t<Exp> or_else_impl(Exp &&exp, F &&f) {
|
||||||
: (detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error()),
|
: (detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error()),
|
||||||
std::forward<Exp>(exp));
|
std::forward<Exp>(exp));
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
template <class Exp, class F,
|
template <class Exp, class F,
|
||||||
class Ret = decltype(detail::invoke(std::declval<F>(),
|
class Ret = decltype(detail::invoke(std::declval<F>(),
|
||||||
|
@ -2227,6 +2406,7 @@ constexpr bool operator==(const expected<T, E> &lhs,
|
||||||
? false
|
? false
|
||||||
: (!lhs.has_value() ? lhs.error() == rhs.error() : *lhs == *rhs);
|
: (!lhs.has_value() ? lhs.error() == rhs.error() : *lhs == *rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T, class E, class U, class F>
|
template<class T, class E, class U, class F>
|
||||||
constexpr bool operator!=(const expected<T, E> &lhs,
|
constexpr bool operator!=(const expected<T, E> &lhs,
|
||||||
const expected<U, F> &rhs) {
|
const expected<U, F> &rhs) {
|
||||||
|
@ -2239,14 +2419,17 @@ template <class T, class E, class U>
|
||||||
constexpr bool operator==(const expected<T, E> &x, const U &v) {
|
constexpr bool operator==(const expected<T, E> &x, const U &v) {
|
||||||
return x.has_value() ? *x == v : false;
|
return x.has_value() ? *x == v : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T, class E, class U>
|
template<class T, class E, class U>
|
||||||
constexpr bool operator==(const U &v, const expected<T, E> &x) {
|
constexpr bool operator==(const U &v, const expected<T, E> &x) {
|
||||||
return x.has_value() ? *x == v : false;
|
return x.has_value() ? *x == v : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T, class E, class U>
|
template<class T, class E, class U>
|
||||||
constexpr bool operator!=(const expected<T, E> &x, const U &v) {
|
constexpr bool operator!=(const expected<T, E> &x, const U &v) {
|
||||||
return x.has_value() ? *x != v : true;
|
return x.has_value() ? *x != v : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T, class E, class U>
|
template<class T, class E, class U>
|
||||||
constexpr bool operator!=(const U &v, const expected<T, E> &x) {
|
constexpr bool operator!=(const U &v, const expected<T, E> &x) {
|
||||||
return x.has_value() ? *x != v : true;
|
return x.has_value() ? *x != v : true;
|
||||||
|
@ -2256,14 +2439,17 @@ template <class T, class E>
|
||||||
constexpr bool operator==(const expected<T, E> &x, const unexpected<E> &e) {
|
constexpr bool operator==(const expected<T, E> &x, const unexpected<E> &e) {
|
||||||
return x.has_value() ? false : x.error() == e.value();
|
return x.has_value() ? false : x.error() == e.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T, class E>
|
template<class T, class E>
|
||||||
constexpr bool operator==(const unexpected<E> &e, const expected<T, E> &x) {
|
constexpr bool operator==(const unexpected<E> &e, const expected<T, E> &x) {
|
||||||
return x.has_value() ? false : x.error() == e.value();
|
return x.has_value() ? false : x.error() == e.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T, class E>
|
template<class T, class E>
|
||||||
constexpr bool operator!=(const expected<T, E> &x, const unexpected<E> &e) {
|
constexpr bool operator!=(const expected<T, E> &x, const unexpected<E> &e) {
|
||||||
return x.has_value() ? true : x.error() != e.value();
|
return x.has_value() ? true : x.error() != e.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T, class E>
|
template<class T, class E>
|
||||||
constexpr bool operator!=(const unexpected<E> &e, const expected<T, E> &x) {
|
constexpr bool operator!=(const unexpected<E> &e, const expected<T, E> &x) {
|
||||||
return x.has_value() ? true : x.error() != e.value();
|
return x.has_value() ? true : x.error() != e.value();
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#include "parsecontext.h"
|
#include "parse_context.h"
|
||||||
#include "assert.h"
|
#include "assert.h"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
@ -6,26 +6,24 @@
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
|
|
||||||
ParseContext::ParseContext()
|
ParseContext::ParseContext() {
|
||||||
{
|
|
||||||
applicationDir = std::string();
|
applicationDir = std::string();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned ParseContext::addFile(const std::string &fileName,
|
unsigned ParseContext::addFile(const std::string &fileName,
|
||||||
const std::string& source)
|
const std::string &source) {
|
||||||
{
|
fileMap.emplace_back(fileName, source);
|
||||||
fileMap.push_back(SourceFile(fileName, source));
|
|
||||||
return fileMap.size();
|
return fileMap.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
SourceFile& ParseContext::getFile(unsigned fileId)
|
SourceFile &ParseContext::getFile(unsigned fileId) {
|
||||||
{
|
|
||||||
return fileMap[fileId - 1];
|
return fileMap[fileId - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct pad {
|
struct pad {
|
||||||
char ch; int count;
|
char ch;
|
||||||
|
int count;
|
||||||
|
|
||||||
pad(char ch, int count) : ch(ch), count(count) {}
|
pad(char ch, int count) : ch(ch), count(count) {}
|
||||||
};
|
};
|
||||||
|
@ -42,14 +40,11 @@ std::ostream& operator<<(std::ostream& stream, const pad& p) {
|
||||||
|
|
||||||
void ParseContext::formatError(const SourceError &sourceError,
|
void ParseContext::formatError(const SourceError &sourceError,
|
||||||
std::ostream &stream,
|
std::ostream &stream,
|
||||||
const std::string& ErrorOrWarning)
|
const std::string &errorOrWarning) {
|
||||||
{
|
|
||||||
ATLAS_ASSERT(sourceError.span.lo.col != 0
|
ATLAS_ASSERT(sourceError.span.lo.col != 0
|
||||||
&& sourceError.span.hi.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;
|
Span span = sourceError.span;
|
||||||
|
|
||||||
|
@ -100,20 +95,16 @@ void ParseContext::formatError(const SourceError& sourceError,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
SourceFile::SourceFile(std::string fileName, std::string source)
|
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);
|
lineOffsets.push_back(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string& SourceFile::getFileName() const
|
const std::string &SourceFile::getFileName() const {
|
||||||
{
|
|
||||||
return fileName;
|
return fileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string SourceFile::getLine(unsigned line) const
|
std::string SourceFile::getLine(unsigned line) const {
|
||||||
{
|
|
||||||
auto lineOffset = lineOffsets[line - 1];
|
auto lineOffset = lineOffsets[line - 1];
|
||||||
auto nextLF = source.find('\n', lineOffset);
|
auto nextLF = source.find('\n', lineOffset);
|
||||||
auto nextCR = source.find('\r', lineOffset);
|
auto nextCR = source.find('\r', lineOffset);
|
||||||
|
@ -122,7 +113,6 @@ const std::string SourceFile::getLine(unsigned line) const
|
||||||
return source.substr(lineOffset, nl - lineOffset);
|
return source.substr(lineOffset, nl - lineOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SourceFile::addLineOffset(unsigned offset)
|
void SourceFile::addLineOffset(unsigned offset) {
|
||||||
{
|
|
||||||
lineOffsets.push_back(offset);
|
lineOffsets.push_back(offset);
|
||||||
}
|
}
|
|
@ -2,30 +2,29 @@
|
||||||
#define PARSE_CONTEXT_H
|
#define PARSE_CONTEXT_H
|
||||||
|
|
||||||
|
|
||||||
#include "sourceerror.h"
|
#include "source_error.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
/*** Represent source file */
|
||||||
class SourceFile {
|
class SourceFile {
|
||||||
std::string fileName;
|
std::string fileName;
|
||||||
std::string source;
|
std::string source;
|
||||||
std::vector<unsigned> lineOffsets;
|
std::vector<unsigned> lineOffsets;
|
||||||
|
|
||||||
public:
|
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);
|
SourceFile(std::string fileName, std::string source);
|
||||||
|
|
||||||
const std::string &getFileName() const;
|
const std::string &getFileName() const;
|
||||||
const std::string getLine(unsigned line) const;
|
|
||||||
|
std::string getLine(unsigned line) const;
|
||||||
|
|
||||||
void addLineOffset(unsigned offset);
|
void addLineOffset(unsigned offset);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*** Represent parsing context */
|
||||||
class ParseContext
|
class ParseContext {
|
||||||
{
|
|
||||||
std::string applicationDir;
|
std::string applicationDir;
|
||||||
std::vector<SourceFile> fileMap;
|
std::vector<SourceFile> fileMap;
|
||||||
|
|
||||||
|
@ -33,9 +32,10 @@ public:
|
||||||
ParseContext();
|
ParseContext();
|
||||||
|
|
||||||
unsigned addFile(const std::string &fileName, const std::string &source);
|
unsigned addFile(const std::string &fileName, const std::string &source);
|
||||||
|
|
||||||
SourceFile &getFile(unsigned file);
|
SourceFile &getFile(unsigned file);
|
||||||
|
|
||||||
void formatError(const SourceError &sourceError, std::ostream &stream, const std::string& ErrorOrWarning);
|
void formatError(const SourceError &sourceError, std::ostream &stream, const std::string &errorOrWarning);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue