moved date and time stuff to separate header
also: - merged all the separate integer parsing functions - renamed the member functions of parse_error for clarity - added the beginnings of a doxygen pipeline
This commit is contained in:
parent
537eb30080
commit
ab5ffa5a3c
@ -3,9 +3,13 @@ version: 2.1
|
||||
jobs:
|
||||
linux_build:
|
||||
docker:
|
||||
- image: "debian:bullseye"
|
||||
- image: debian:bullseye
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Pulling Catch2
|
||||
command: |
|
||||
git submodule update --init --recursive extern/Catch2
|
||||
- run:
|
||||
name: Installing python
|
||||
command: |
|
||||
@ -19,10 +23,6 @@ jobs:
|
||||
command: |
|
||||
apt-get -qq update && apt-get install -y git clang-9 g++-9 python3-pip ninja-build
|
||||
pip3 install meson
|
||||
- run:
|
||||
name: Pulling submodules
|
||||
command: |
|
||||
git submodule update --init --recursive
|
||||
- run:
|
||||
name: Building with clang
|
||||
command: |
|
||||
@ -38,8 +38,70 @@ jobs:
|
||||
command: |
|
||||
cd build-clang && ninja test && cd ../build-gcc && ninja test
|
||||
|
||||
generate_dox:
|
||||
docker:
|
||||
- image: debian:bullseye
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Installing dependencies
|
||||
command: |
|
||||
git submodule update --init extern/m.css
|
||||
apt-get -qq update && apt-get install -y python3 doxygen python3-pip cmake clang-9 flex bison
|
||||
pip3 install beautifulsoup4 jinja2 pygments html5lib
|
||||
- run:
|
||||
name: Building and installing Doxygen 1.8.17
|
||||
command: |
|
||||
wget http://doxygen.nl/files/doxygen-1.8.17.src.tar.gz
|
||||
tar xvzf doxygen-1.8.17.src.tar.gz
|
||||
rm doxygen-1.8.17.src.tar.gz
|
||||
cd doxygen-1.8.17
|
||||
CC=clang-9 CXX=clang++-9 cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr -Wno-dev -Wno-deprecated
|
||||
make install
|
||||
- run:
|
||||
name: Generating documentation
|
||||
command: |
|
||||
cd python && python3 generate_documentation.py
|
||||
- persist_to_workspace:
|
||||
root: docs
|
||||
paths: html
|
||||
|
||||
deploy_dox:
|
||||
docker:
|
||||
- image: node:8.10.0
|
||||
steps:
|
||||
- checkout
|
||||
- attach_workspace:
|
||||
at: docs
|
||||
- run:
|
||||
name: Disable jekyll builds
|
||||
command: |
|
||||
touch docs/html/.nojekyll
|
||||
- run:
|
||||
name: Installing dependencies
|
||||
command: |
|
||||
npm install -g --silent gh-pages
|
||||
git config user.email "ci-build@tomlplusplus.com"
|
||||
git config user.name "ci-build"
|
||||
- add_ssh_keys:
|
||||
fingerprints:
|
||||
- "a6:63:c0:a5:89:cf:2d:03:e7:c9:88:5d:c0:8c:39:e0"
|
||||
- run:
|
||||
name: Deploy docs to gh-pages branch
|
||||
command: gh-pages --dotfiles --message "[skip ci] Updates" --dist docs/html
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
build:
|
||||
jobs:
|
||||
- linux_build
|
||||
- generate_dox:
|
||||
requires:
|
||||
- linux_build
|
||||
filters:
|
||||
branches:
|
||||
only: master
|
||||
- deploy_dox:
|
||||
requires:
|
||||
- generate_dox
|
||||
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -7,6 +7,8 @@ meson-private/
|
||||
build.ninja
|
||||
compile_commands.json
|
||||
[Bb]uild*/
|
||||
[Dd]ocs/xml
|
||||
[Dd]ocs/html
|
||||
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
|
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -1,3 +1,6 @@
|
||||
[submodule "extern/Catch2"]
|
||||
path = extern/Catch2
|
||||
url = https://github.com/catchorg/Catch2.git
|
||||
[submodule "extern/m.css"]
|
||||
path = extern/m.css
|
||||
url = https://github.com/mosra/m.css.git
|
||||
|
384
docs/Doxyfile
Normal file
384
docs/Doxyfile
Normal file
@ -0,0 +1,384 @@
|
||||
# Doxyfile 1.8.16
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Project related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
DOXYFILE_ENCODING = UTF-8
|
||||
PROJECT_NAME = toml++
|
||||
PROJECT_NUMBER =
|
||||
PROJECT_BRIEF =
|
||||
PROJECT_LOGO =
|
||||
OUTPUT_DIRECTORY = ./
|
||||
CREATE_SUBDIRS = NO
|
||||
ALLOW_UNICODE_NAMES = NO
|
||||
OUTPUT_LANGUAGE = English
|
||||
OUTPUT_TEXT_DIRECTION = None
|
||||
BRIEF_MEMBER_DESC = YES
|
||||
REPEAT_BRIEF = YES
|
||||
ABBREVIATE_BRIEF = "The $name class" \
|
||||
"The $name widget" \
|
||||
"The $name file" \
|
||||
is \
|
||||
provides \
|
||||
specifies \
|
||||
contains \
|
||||
represents \
|
||||
a \
|
||||
an \
|
||||
the
|
||||
ALWAYS_DETAILED_SEC = NO
|
||||
INLINE_INHERITED_MEMB = YES
|
||||
FULL_PATH_NAMES = YES
|
||||
STRIP_FROM_PATH = ../
|
||||
STRIP_FROM_INC_PATH =
|
||||
SHORT_NAMES = NO
|
||||
JAVADOC_AUTOBRIEF = NO
|
||||
JAVADOC_BANNER = NO
|
||||
QT_AUTOBRIEF = NO
|
||||
MULTILINE_CPP_IS_BRIEF = NO
|
||||
INHERIT_DOCS = YES
|
||||
SEPARATE_MEMBER_PAGES = NO
|
||||
TAB_SIZE = 4
|
||||
ALIASES = "cpp=@code{.cpp}" \
|
||||
"ecpp=@endcode" \
|
||||
"epp=@endcode" \
|
||||
"detail=@details"
|
||||
TCL_SUBST =
|
||||
OPTIMIZE_OUTPUT_FOR_C = NO
|
||||
OPTIMIZE_OUTPUT_JAVA = NO
|
||||
OPTIMIZE_FOR_FORTRAN = NO
|
||||
OPTIMIZE_OUTPUT_VHDL = NO
|
||||
OPTIMIZE_OUTPUT_SLICE = NO
|
||||
EXTENSION_MAPPING =
|
||||
MARKDOWN_SUPPORT = YES
|
||||
TOC_INCLUDE_HEADINGS = 0
|
||||
AUTOLINK_SUPPORT = YES
|
||||
BUILTIN_STL_SUPPORT = YES
|
||||
CPP_CLI_SUPPORT = NO
|
||||
SIP_SUPPORT = NO
|
||||
IDL_PROPERTY_SUPPORT = NO
|
||||
DISTRIBUTE_GROUP_DOC = NO
|
||||
GROUP_NESTED_COMPOUNDS = NO
|
||||
SUBGROUPING = YES
|
||||
INLINE_GROUPED_CLASSES = NO
|
||||
INLINE_SIMPLE_STRUCTS = NO
|
||||
TYPEDEF_HIDES_STRUCT = NO
|
||||
LOOKUP_CACHE_SIZE = 1
|
||||
#---------------------------------------------------------------------------
|
||||
# Build related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
EXTRACT_ALL = NO
|
||||
EXTRACT_PRIVATE = NO
|
||||
EXTRACT_PRIV_VIRTUAL = NO
|
||||
EXTRACT_PACKAGE = NO
|
||||
EXTRACT_STATIC = NO
|
||||
EXTRACT_LOCAL_CLASSES = NO
|
||||
EXTRACT_LOCAL_METHODS = NO
|
||||
EXTRACT_ANON_NSPACES = NO
|
||||
HIDE_UNDOC_MEMBERS = YES
|
||||
HIDE_UNDOC_CLASSES = YES
|
||||
HIDE_FRIEND_COMPOUNDS = NO
|
||||
HIDE_IN_BODY_DOCS = NO
|
||||
INTERNAL_DOCS = NO
|
||||
CASE_SENSE_NAMES = NO
|
||||
HIDE_SCOPE_NAMES = NO
|
||||
HIDE_COMPOUND_REFERENCE= NO
|
||||
SHOW_INCLUDE_FILES = YES
|
||||
SHOW_GROUPED_MEMB_INC = NO
|
||||
FORCE_LOCAL_INCLUDES = NO
|
||||
INLINE_INFO = YES
|
||||
SORT_MEMBER_DOCS = YES
|
||||
SORT_BRIEF_DOCS = YES
|
||||
SORT_MEMBERS_CTORS_1ST = YES
|
||||
SORT_GROUP_NAMES = NO
|
||||
SORT_BY_SCOPE_NAME = NO
|
||||
STRICT_PROTO_MATCHING = NO
|
||||
GENERATE_TODOLIST = NO
|
||||
GENERATE_TESTLIST = NO
|
||||
GENERATE_BUGLIST = NO
|
||||
GENERATE_DEPRECATEDLIST= NO
|
||||
ENABLED_SECTIONS =
|
||||
MAX_INITIALIZER_LINES = 30
|
||||
SHOW_USED_FILES = YES
|
||||
SHOW_FILES = YES
|
||||
SHOW_NAMESPACES = YES
|
||||
FILE_VERSION_FILTER =
|
||||
LAYOUT_FILE =
|
||||
CITE_BIB_FILES =
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to warning and progress messages
|
||||
#---------------------------------------------------------------------------
|
||||
QUIET = NO
|
||||
WARNINGS = YES
|
||||
WARN_IF_UNDOCUMENTED = YES
|
||||
WARN_IF_DOC_ERROR = YES
|
||||
WARN_NO_PARAMDOC = NO
|
||||
WARN_AS_ERROR = YES
|
||||
WARN_FORMAT = "$file:$line: $text"
|
||||
WARN_LOGFILE = ./doc/doxygen_warnings.log
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the input files
|
||||
#---------------------------------------------------------------------------
|
||||
INPUT = ../include
|
||||
INPUT_ENCODING = UTF-8
|
||||
FILE_PATTERNS = *.c \
|
||||
*.cc \
|
||||
*.cxx \
|
||||
*.cpp \
|
||||
*.c++ \
|
||||
*.java \
|
||||
*.ii \
|
||||
*.ixx \
|
||||
*.ipp \
|
||||
*.i++ \
|
||||
*.inl \
|
||||
*.idl \
|
||||
*.ddl \
|
||||
*.odl \
|
||||
*.h \
|
||||
*.hh \
|
||||
*.hxx \
|
||||
*.hpp \
|
||||
*.h++ \
|
||||
*.cs \
|
||||
*.d \
|
||||
*.php \
|
||||
*.php4 \
|
||||
*.php5 \
|
||||
*.phtml \
|
||||
*.inc \
|
||||
*.m \
|
||||
*.markdown \
|
||||
*.md \
|
||||
*.mm \
|
||||
*.dox \
|
||||
*.py \
|
||||
*.pyw \
|
||||
*.f90 \
|
||||
*.f95 \
|
||||
*.f03 \
|
||||
*.f08 \
|
||||
*.f \
|
||||
*.for \
|
||||
*.tcl \
|
||||
*.vhd \
|
||||
*.vhdl \
|
||||
*.ucf \
|
||||
*.qsf
|
||||
RECURSIVE = YES
|
||||
EXCLUDE =
|
||||
EXCLUDE_SYMLINKS = NO
|
||||
EXCLUDE_PATTERNS =
|
||||
EXCLUDE_SYMBOLS =
|
||||
EXAMPLE_PATH =
|
||||
EXAMPLE_PATTERNS = *
|
||||
EXAMPLE_RECURSIVE = NO
|
||||
IMAGE_PATH = ./
|
||||
INPUT_FILTER =
|
||||
FILTER_PATTERNS =
|
||||
FILTER_SOURCE_FILES = NO
|
||||
FILTER_SOURCE_PATTERNS =
|
||||
USE_MDFILE_AS_MAINPAGE =
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to source browsing
|
||||
#---------------------------------------------------------------------------
|
||||
SOURCE_BROWSER = NO
|
||||
INLINE_SOURCES = NO
|
||||
STRIP_CODE_COMMENTS = YES
|
||||
REFERENCED_BY_RELATION = NO
|
||||
REFERENCES_RELATION = NO
|
||||
REFERENCES_LINK_SOURCE = NO
|
||||
SOURCE_TOOLTIPS = YES
|
||||
USE_HTAGS = NO
|
||||
VERBATIM_HEADERS = NO
|
||||
CLANG_ASSISTED_PARSING = NO
|
||||
CLANG_OPTIONS =
|
||||
CLANG_DATABASE_PATH =
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the alphabetical class index
|
||||
#---------------------------------------------------------------------------
|
||||
ALPHABETICAL_INDEX = YES
|
||||
COLS_IN_ALPHA_INDEX = 5
|
||||
IGNORE_PREFIX =
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the HTML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_HTML = YES
|
||||
HTML_OUTPUT = html
|
||||
HTML_FILE_EXTENSION = .html
|
||||
HTML_HEADER =
|
||||
HTML_FOOTER =
|
||||
HTML_STYLESHEET =
|
||||
HTML_EXTRA_STYLESHEET =
|
||||
HTML_EXTRA_FILES =
|
||||
HTML_COLORSTYLE_HUE = 224
|
||||
HTML_COLORSTYLE_SAT = 50
|
||||
HTML_COLORSTYLE_GAMMA = 67
|
||||
HTML_TIMESTAMP = NO
|
||||
HTML_DYNAMIC_MENUS = YES
|
||||
HTML_DYNAMIC_SECTIONS = NO
|
||||
HTML_INDEX_NUM_ENTRIES = 100
|
||||
GENERATE_DOCSET = NO
|
||||
DOCSET_FEEDNAME = "Doxygen generated docs"
|
||||
DOCSET_BUNDLE_ID = org.doxygen.Project
|
||||
DOCSET_PUBLISHER_ID = org.doxygen.Publisher
|
||||
DOCSET_PUBLISHER_NAME = Publisher
|
||||
GENERATE_HTMLHELP = NO
|
||||
CHM_FILE =
|
||||
HHC_LOCATION =
|
||||
GENERATE_CHI = NO
|
||||
CHM_INDEX_ENCODING =
|
||||
BINARY_TOC = NO
|
||||
TOC_EXPAND = NO
|
||||
GENERATE_QHP = NO
|
||||
QCH_FILE =
|
||||
QHP_NAMESPACE = org.doxygen.Project
|
||||
QHP_VIRTUAL_FOLDER = doc
|
||||
QHP_CUST_FILTER_NAME =
|
||||
QHP_CUST_FILTER_ATTRS =
|
||||
QHP_SECT_FILTER_ATTRS =
|
||||
QHG_LOCATION =
|
||||
GENERATE_ECLIPSEHELP = NO
|
||||
ECLIPSE_DOC_ID = org.doxygen.Project
|
||||
DISABLE_INDEX = NO
|
||||
GENERATE_TREEVIEW = YES
|
||||
ENUM_VALUES_PER_LINE = 4
|
||||
TREEVIEW_WIDTH = 250
|
||||
EXT_LINKS_IN_WINDOW = NO
|
||||
FORMULA_FONTSIZE = 10
|
||||
FORMULA_TRANSPARENT = YES
|
||||
USE_MATHJAX = NO
|
||||
MATHJAX_FORMAT = HTML-CSS
|
||||
MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
|
||||
MATHJAX_EXTENSIONS =
|
||||
MATHJAX_CODEFILE =
|
||||
SEARCHENGINE = NO
|
||||
SERVER_BASED_SEARCH = NO
|
||||
EXTERNAL_SEARCH = NO
|
||||
SEARCHENGINE_URL =
|
||||
SEARCHDATA_FILE = searchdata.xml
|
||||
EXTERNAL_SEARCH_ID =
|
||||
EXTRA_SEARCH_MAPPINGS =
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the LaTeX output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_LATEX = NO
|
||||
LATEX_OUTPUT = latex
|
||||
LATEX_CMD_NAME = latex
|
||||
MAKEINDEX_CMD_NAME = makeindex
|
||||
LATEX_MAKEINDEX_CMD = makeindex
|
||||
COMPACT_LATEX = NO
|
||||
PAPER_TYPE = a4
|
||||
EXTRA_PACKAGES =
|
||||
LATEX_HEADER =
|
||||
LATEX_FOOTER =
|
||||
LATEX_EXTRA_STYLESHEET =
|
||||
LATEX_EXTRA_FILES =
|
||||
PDF_HYPERLINKS = YES
|
||||
USE_PDFLATEX = YES
|
||||
LATEX_BATCHMODE = NO
|
||||
LATEX_HIDE_INDICES = NO
|
||||
LATEX_SOURCE_CODE = NO
|
||||
LATEX_BIB_STYLE = plain
|
||||
LATEX_TIMESTAMP = NO
|
||||
LATEX_EMOJI_DIRECTORY =
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the RTF output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_RTF = NO
|
||||
RTF_OUTPUT = rtf
|
||||
COMPACT_RTF = NO
|
||||
RTF_HYPERLINKS = NO
|
||||
RTF_STYLESHEET_FILE =
|
||||
RTF_EXTENSIONS_FILE =
|
||||
RTF_SOURCE_CODE = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the man page output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_MAN = NO
|
||||
MAN_OUTPUT = man
|
||||
MAN_EXTENSION = .3
|
||||
MAN_SUBDIR =
|
||||
MAN_LINKS = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the XML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_XML = NO
|
||||
XML_OUTPUT = xml
|
||||
XML_PROGRAMLISTING = YES
|
||||
XML_NS_MEMB_FILE_SCOPE = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the DOCBOOK output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_DOCBOOK = NO
|
||||
DOCBOOK_OUTPUT = docbook
|
||||
DOCBOOK_PROGRAMLISTING = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options for the AutoGen Definitions output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_AUTOGEN_DEF = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the Perl module output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_PERLMOD = NO
|
||||
PERLMOD_LATEX = NO
|
||||
PERLMOD_PRETTY = YES
|
||||
PERLMOD_MAKEVAR_PREFIX =
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the preprocessor
|
||||
#---------------------------------------------------------------------------
|
||||
ENABLE_PREPROCESSING = YES
|
||||
MACRO_EXPANSION = YES
|
||||
EXPAND_ONLY_PREDEF = NO
|
||||
SEARCH_INCLUDES = YES
|
||||
INCLUDE_PATH =
|
||||
INCLUDE_FILE_PATTERNS =
|
||||
PREDEFINED = __cplusplus=201703L
|
||||
EXPAND_AS_DEFINED =
|
||||
SKIP_FUNCTION_MACROS = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to external references
|
||||
#---------------------------------------------------------------------------
|
||||
TAGFILES =
|
||||
GENERATE_TAGFILE =
|
||||
ALLEXTERNALS = NO
|
||||
EXTERNAL_GROUPS = YES
|
||||
EXTERNAL_PAGES = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the dot tool
|
||||
#---------------------------------------------------------------------------
|
||||
CLASS_DIAGRAMS = NO
|
||||
DIA_PATH =
|
||||
HIDE_UNDOC_RELATIONS = YES
|
||||
HAVE_DOT = NO
|
||||
DOT_NUM_THREADS = 0
|
||||
DOT_FONTNAME = Helvetica
|
||||
DOT_FONTSIZE = 10
|
||||
DOT_FONTPATH =
|
||||
CLASS_GRAPH = YES
|
||||
COLLABORATION_GRAPH = YES
|
||||
GROUP_GRAPHS = YES
|
||||
UML_LOOK = NO
|
||||
UML_LIMIT_NUM_FIELDS = 10
|
||||
TEMPLATE_RELATIONS = NO
|
||||
INCLUDE_GRAPH = YES
|
||||
INCLUDED_BY_GRAPH = YES
|
||||
CALL_GRAPH = YES
|
||||
CALLER_GRAPH = YES
|
||||
GRAPHICAL_HIERARCHY = YES
|
||||
DIRECTORY_GRAPH = YES
|
||||
DOT_IMAGE_FORMAT = png
|
||||
INTERACTIVE_SVG = NO
|
||||
DOT_PATH =
|
||||
DOTFILE_DIRS =
|
||||
MSCFILE_DIRS =
|
||||
DIAFILE_DIRS =
|
||||
PLANTUML_JAR_PATH =
|
||||
PLANTUML_CFG_FILE =
|
||||
PLANTUML_INCLUDE_PATH =
|
||||
DOT_GRAPH_MAX_NODES = 50
|
||||
MAX_DOT_GRAPH_DEPTH = 0
|
||||
DOT_TRANSPARENT = NO
|
||||
DOT_MULTI_TARGETS = NO
|
||||
GENERATE_LEGEND = YES
|
||||
DOT_CLEANUP = YES
|
21
docs/Doxyfile-mcss
Normal file
21
docs/Doxyfile-mcss
Normal file
@ -0,0 +1,21 @@
|
||||
@INCLUDE = ./Doxyfile
|
||||
GENERATE_HTML = NO
|
||||
GENERATE_XML = YES
|
||||
XML_PROGRAMLISTING = NO
|
||||
HTML_EXTRA_STYLESHEET = https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,600,600i%7CSource+Code+Pro:400,400i,600 \
|
||||
../css/m-dark+documentation.compiled.css \
|
||||
tomlplusplus.css
|
||||
WARN_AS_ERROR = NO
|
||||
TAB_SIZE = 4
|
||||
HTML_EXTRA_FILES = tomlplusplus.js
|
||||
##! M_THEME_COLOR = #2d2d30
|
||||
##! M_LINKS_NAVBAR1 = namespaces
|
||||
##! M_LINKS_NAVBAR2 = annotated
|
||||
##! M_SEARCH_DOWNLOAD_BINARY = NO
|
||||
##! M_CLASS_TREE_EXPAND_LEVELS = 1
|
||||
##! M_FILE_TREE_EXPAND_LEVELS = 3
|
||||
##! M_PAGE_FINE_PRINT = \
|
||||
##! <a target="_blank" href="https://github.com/marzer/tomlplusplus/">Github</a> • \
|
||||
##! <a target="_blank" href="https://github.com/marzer/tomlplusplus/issues">Report an issue</a> \
|
||||
##! <br><br><div id="tpp-custom-footer"></div>
|
||||
##! M_HTML_HEADER = <script src="tomlplusplus.js"></script>
|
218
docs/tomlplusplus.css
Normal file
218
docs/tomlplusplus.css
Normal file
@ -0,0 +1,218 @@
|
||||
table.m-table th
|
||||
{
|
||||
color: #ffe698;
|
||||
}
|
||||
article section > h2
|
||||
{
|
||||
padding-top: 0.5rem;
|
||||
padding-bottom: 0.1rem;
|
||||
background-color: #282e36;
|
||||
padding-left: 1rem;
|
||||
margin-left: -1rem;
|
||||
margin-right: -1rem;
|
||||
margin-top: 2rem;
|
||||
border-color: #282e36;
|
||||
border-style: solid;
|
||||
border-width: 0.0625rem;
|
||||
border-left-width: 0.25rem;
|
||||
border-radius: 0.2rem;
|
||||
}
|
||||
article section:target
|
||||
{
|
||||
border-radius: 0.2rem;
|
||||
}
|
||||
article section:target > h2
|
||||
{
|
||||
border-color: #a5c9ea;
|
||||
}
|
||||
|
||||
table.m-table thead th
|
||||
{
|
||||
border-bottom-width: 0.0rem;
|
||||
}
|
||||
table.m-table tbody td
|
||||
{
|
||||
border: 0px;
|
||||
}
|
||||
table.m-table thead tr:first-child th
|
||||
{
|
||||
border-top-width: 0.1rem;
|
||||
}
|
||||
code.m-code, aside code
|
||||
{
|
||||
margin-left: 0.1em;
|
||||
padding-left: 0.2em;
|
||||
padding-right: 0.1em;
|
||||
}
|
||||
dl.m-doc dd
|
||||
{
|
||||
margin-bottom: 0.8rem;
|
||||
}
|
||||
|
||||
a.tpp-external
|
||||
{
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.m-doc-template a, dl.m-doc dd a, ul.m-doc li > span.m-doc a
|
||||
{
|
||||
color: #858585;
|
||||
}
|
||||
|
||||
.m-doc-template a.tpp-external:hover,
|
||||
dl.m-doc dd a.tpp-external:hover,
|
||||
ul.m-doc li > span.m-doc a.tpp-external:hover
|
||||
{
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
|
||||
.tpp-swatch, .tpp-enable-if > *
|
||||
{
|
||||
display: inline-block;
|
||||
border-radius: 0.2rem;
|
||||
}
|
||||
|
||||
.tpp-enable-if
|
||||
{
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.tpp-enable-if > *
|
||||
{
|
||||
background-clip: padding-box !important;
|
||||
padding: 0px 2px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.tpp-enable-if > a
|
||||
{
|
||||
white-space: nowrap;
|
||||
font-size: 0.8rem;
|
||||
font-weight: bold;
|
||||
background-color: #858585;
|
||||
color: #050505;
|
||||
padding-bottom: 0px;
|
||||
margin: 0px 1px;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.tpp-enable-if > a:hover
|
||||
{
|
||||
background-color: #747474;
|
||||
color: initial;
|
||||
}
|
||||
|
||||
.tpp-enable-if > span
|
||||
{
|
||||
display: none;
|
||||
padding-left: 2em;
|
||||
|
||||
}
|
||||
|
||||
.tpp-swatch
|
||||
{
|
||||
min-width: 3em;
|
||||
min-height: 1em;
|
||||
}
|
||||
|
||||
body > header > nav
|
||||
{
|
||||
background-color: #1e1e1e;
|
||||
}
|
||||
|
||||
html
|
||||
{
|
||||
background-color: #2d2d30;
|
||||
}
|
||||
|
||||
pre, code, .m-label/*.m-flat.m-success*/, .tpp-enable-if > a
|
||||
{
|
||||
font-family: 'Consolas', monospace;
|
||||
}
|
||||
|
||||
pre, .m-doc-search-content /*, .tpp-enable-if > full*/
|
||||
{
|
||||
background-color: #1e1e1e;
|
||||
}
|
||||
|
||||
pre.m-code, code
|
||||
{
|
||||
background-color: #1e1e1e88;
|
||||
}
|
||||
|
||||
.m-code .c1 /* comments */
|
||||
{
|
||||
color: rgb(87,166,74);
|
||||
}
|
||||
|
||||
.m-code .mi, .m-code .mf /* literals */
|
||||
{
|
||||
color: rgb(181,206,168);
|
||||
}
|
||||
|
||||
.m-code .k /* keywords */
|
||||
{
|
||||
color: rgb(86,156,214);
|
||||
}
|
||||
|
||||
.m-code .n /* names */
|
||||
{
|
||||
color: rgb(220,220,220);
|
||||
}
|
||||
|
||||
.m-code .p /* punctuation */
|
||||
{
|
||||
color: rgb(120,120,120);
|
||||
}
|
||||
|
||||
article section.m-doc-details > div > h3:first-child, article section > h2, body > footer > nav
|
||||
{
|
||||
background-color: #252526;
|
||||
}
|
||||
|
||||
.tpp-external-navbar
|
||||
{
|
||||
background-color: #007acc11;
|
||||
}
|
||||
|
||||
.m-label:not(.m-flat)
|
||||
{
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
header
|
||||
{
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
body
|
||||
{
|
||||
margin-top: 3rem;
|
||||
}
|
||||
|
||||
div.m-doc-include
|
||||
{
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.m-doc-include span.cp
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.m-doc-include a.cpf
|
||||
{
|
||||
color: #9999AA;
|
||||
}
|
||||
|
||||
article, article > header, article section
|
||||
{
|
||||
margin-bottom: 3em;
|
||||
background-color: red;
|
||||
background-color: inherit;
|
||||
}
|
18
docs/tomlplusplus.js
Normal file
18
docs/tomlplusplus.js
Normal file
@ -0,0 +1,18 @@
|
||||
function ToggleEnableIf(anchor)
|
||||
{
|
||||
if (!anchor.hasOwnProperty('enableIfHidden'))
|
||||
anchor['enableIfHidden'] = true;
|
||||
anchor.enableIfHidden = !anchor.enableIfHidden;
|
||||
|
||||
content = anchor.parentNode.getElementsByTagName('span')[0]
|
||||
if (anchor.enableIfHidden)
|
||||
{
|
||||
anchor.style.display = "";
|
||||
content.style.display = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
anchor.style.display = "none";
|
||||
content.style.display = "block";
|
||||
}
|
||||
}
|
@ -31,13 +31,12 @@ int main(int argc, char** argv)
|
||||
catch (const toml::parse_error& err)
|
||||
{
|
||||
std::cerr
|
||||
<< "Error parsing file '"sv << *err.where().path
|
||||
<< "':\n"sv << err.what()
|
||||
<< "\n ("sv << err.where().begin << ")"sv
|
||||
<< "Error parsing file '"sv << *err.source().path
|
||||
<< "':\n"sv << err.description()
|
||||
<< "\n ("sv << err.source().begin << ")"sv
|
||||
<< std::endl;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -32,9 +32,9 @@ int main(int argc, char** argv)
|
||||
catch (const toml::parse_error & err)
|
||||
{
|
||||
std::cerr
|
||||
<< "Error parsing file '"sv << *err.where().path
|
||||
<< "':\n"sv << err.what()
|
||||
<< "\n ("sv << err.where().begin << ")"sv
|
||||
<< "Error parsing file '"sv << *err.source().path
|
||||
<< "':\n"sv << err.description()
|
||||
<< "\n ("sv << err.source().begin << ")"sv
|
||||
<< std::endl;
|
||||
|
||||
return 1;
|
||||
@ -52,8 +52,8 @@ int main(int argc, char** argv)
|
||||
catch (const toml::parse_error& err)
|
||||
{
|
||||
std::cerr
|
||||
<< "Error parsing stdin:\n"sv << err.what()
|
||||
<< "\n ("sv << err.where().begin << ")"sv
|
||||
<< "Error parsing stdin:\n"sv << err.description()
|
||||
<< "\n ("sv << err.source().begin << ")"sv
|
||||
<< std::endl;
|
||||
|
||||
return 1;
|
||||
|
@ -5,14 +5,15 @@
|
||||
//# is used as the source for generate_single_header.py.
|
||||
|
||||
#include "toml_common.h"
|
||||
#include "toml_print_to_stream.h"
|
||||
#include "toml_date_time.h"
|
||||
#include "toml_node.h"
|
||||
#include "toml_table.h"
|
||||
#include "toml_array.h"
|
||||
#include "toml_value.h"
|
||||
#include "toml_utf8.h"
|
||||
#include "toml_node_view.h"
|
||||
#include "toml_utf8.h"
|
||||
#include "toml_parser.h"
|
||||
#include "toml_print_to_stream.h"
|
||||
#include "toml_formatter.h"
|
||||
#include "toml_default_formatter.h"
|
||||
#include "toml_json_formatter.h"
|
||||
|
@ -27,10 +27,10 @@ namespace toml::impl
|
||||
|
||||
public:
|
||||
|
||||
array_iterator() noexcept = default;
|
||||
|
||||
using reference = std::conditional_t<is_const, const node&, node&>;
|
||||
|
||||
array_iterator() noexcept = default;
|
||||
|
||||
array_iterator& operator++() noexcept // ++pre
|
||||
{
|
||||
++raw_;
|
||||
|
@ -114,6 +114,8 @@
|
||||
#define TOML_USE_STREAMS_FOR_FLOATS 1
|
||||
#endif
|
||||
|
||||
#elif defined (DOXYGEN)
|
||||
#define TOML_EXCEPTIONS 0
|
||||
#endif
|
||||
|
||||
#ifndef TOML_CPP_VERSION
|
||||
@ -268,19 +270,23 @@ TOML_POP_WARNINGS
|
||||
////////// FORWARD DECLARATIONS & TYPEDEFS
|
||||
// clang-format on
|
||||
|
||||
/// \brief The root namespace for all toml++ functions and types.
|
||||
namespace toml
|
||||
{
|
||||
/// \brief User-defined literals.
|
||||
inline namespace literals
|
||||
{
|
||||
using namespace std::string_literals;
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
/// \brief Specifies a uint8_t literal.
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE
|
||||
TOML_CONSTEVAL uint8_t operator"" _u8(unsigned long long n) noexcept
|
||||
{
|
||||
return static_cast<uint8_t>(n);
|
||||
}
|
||||
|
||||
/// \brief Specifies a size_t literal.
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE
|
||||
TOML_CONSTEVAL size_t operator"" _sz(unsigned long long n) noexcept
|
||||
{
|
||||
@ -296,14 +302,24 @@ namespace toml
|
||||
|
||||
#else
|
||||
|
||||
/// \brief The base character type for toml++ keys and string values.
|
||||
/// \remarks This will be `char8_t` if `TOML_CHAR_8_STRINGS = 1`, otherwise it will be `char`.
|
||||
using string_char = char;
|
||||
|
||||
/// \brief The string type for toml++ keys and string values.
|
||||
/// \remarks This will be `std::u8string` if `TOML_CHAR_8_STRINGS = 1`, otherwise it will be `std::string`.
|
||||
using string = std::string;
|
||||
|
||||
/// \brief The string type for toml++ keys and string values.
|
||||
/// \remarks This will be `std::u8string_view` if `TOML_CHAR_8_STRINGS = 1`, otherwise it will be `std::string_view`.
|
||||
using string_view = std::string_view;
|
||||
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
using string_map = std::map<string, T, std::less<>>; //heterogeneous lookup
|
||||
struct date;
|
||||
struct time;
|
||||
struct time_offset;
|
||||
struct date_time;
|
||||
|
||||
class node;
|
||||
template <typename T> class node_view;
|
||||
@ -311,6 +327,7 @@ namespace toml
|
||||
class array;
|
||||
class table;
|
||||
|
||||
/// \brief TOML node type identifiers.
|
||||
enum class node_type : uint8_t
|
||||
{
|
||||
table,
|
||||
@ -330,21 +347,31 @@ namespace toml
|
||||
|
||||
#else
|
||||
|
||||
/// \brief The integer type used to tally line numbers and columns.
|
||||
/// \remarks This will be `uint32_t` if `TOML_LARGE_FILES = 1`, otherwise it will be `uint16_t`.
|
||||
using source_index = uint16_t;
|
||||
|
||||
#endif
|
||||
|
||||
/// \brief A source document line-and-column pair.
|
||||
struct source_position final
|
||||
{
|
||||
source_index line; //begins at 1
|
||||
source_index column; //begins at 1
|
||||
/// \brief The line number.
|
||||
/// \remarks Valid line numbers start at 1.
|
||||
source_index line;
|
||||
|
||||
/// \brief The column number.
|
||||
/// \remarks Valid column numbers start at 1.
|
||||
source_index column;
|
||||
|
||||
/// \brief Returns true if both line and column numbers are non-zero.
|
||||
[[nodiscard]]
|
||||
explicit constexpr operator bool () const noexcept
|
||||
{
|
||||
return line > source_index{} && column > source_index{};
|
||||
}
|
||||
|
||||
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator == (const source_position& lhs, const source_position& rhs) noexcept
|
||||
{
|
||||
@ -381,12 +408,21 @@ namespace toml
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief A pointer to a shared string resource containing a source path.
|
||||
using source_path_ptr = std::shared_ptr<const std::string>;
|
||||
|
||||
/// \brief A source document region.
|
||||
struct source_region final
|
||||
{
|
||||
/// \brief The beginning of the region (inclusive).
|
||||
source_position begin;
|
||||
|
||||
/// \brief The end of the region (exclusive).
|
||||
source_position end;
|
||||
|
||||
/// \brief The path to the corresponding source document.
|
||||
///
|
||||
/// \remarks This will be `nullptr` if no path was provided to toml::parse().
|
||||
source_path_ptr path;
|
||||
};
|
||||
|
||||
@ -404,23 +440,29 @@ namespace toml
|
||||
public:
|
||||
|
||||
TOML_NODISCARD_CTOR TOML_GCC_ATTR(nonnull)
|
||||
parse_error(const char* description, source_region&& source) noexcept
|
||||
: std::runtime_error{ description },
|
||||
source_{ std::move(source) }
|
||||
parse_error(const char* desc, source_region&& src) noexcept
|
||||
: std::runtime_error{ desc },
|
||||
source_{ std::move(src) }
|
||||
{}
|
||||
|
||||
TOML_NODISCARD_CTOR TOML_GCC_ATTR(nonnull)
|
||||
parse_error(const char* description, const source_region& source) noexcept
|
||||
: parse_error{ description, source_region{ source } }
|
||||
parse_error(const char* desc, const source_region& src) noexcept
|
||||
: parse_error{ desc, source_region{ src } }
|
||||
{}
|
||||
|
||||
TOML_NODISCARD_CTOR TOML_GCC_ATTR(nonnull)
|
||||
parse_error(const char* description, const source_position& position, const source_path_ptr& path = {}) noexcept
|
||||
: parse_error{ description, source_region{ position, position, path } }
|
||||
parse_error(const char* desc, const source_position& position, const source_path_ptr& path = {}) noexcept
|
||||
: parse_error{ desc, source_region{ position, position, path } }
|
||||
{}
|
||||
|
||||
[[nodiscard]]
|
||||
const source_region& where() const noexcept
|
||||
std::string_view description() const noexcept
|
||||
{
|
||||
return std::string_view{ what() };
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
const source_region& source() const noexcept
|
||||
{
|
||||
return source_;
|
||||
}
|
||||
@ -428,6 +470,10 @@ namespace toml
|
||||
|
||||
#else
|
||||
|
||||
/// \brief An error thrown/returned when parsing fails.
|
||||
///
|
||||
/// \remarks This will inherit from `std::runtime_exception` when `TOML_EXCEPTIONS = 1`.
|
||||
/// The public interface will be exactly the same either way.
|
||||
class parse_error final
|
||||
{
|
||||
private:
|
||||
@ -437,29 +483,32 @@ namespace toml
|
||||
public:
|
||||
|
||||
TOML_NODISCARD_CTOR
|
||||
parse_error(std::string&& description, source_region&& source) noexcept
|
||||
: description_{ std::move(description) },
|
||||
source_{ std::move(source) }
|
||||
parse_error(std::string&& desc, source_region&& src) noexcept
|
||||
: description_{ std::move(desc) },
|
||||
source_{ std::move(src) }
|
||||
{}
|
||||
|
||||
TOML_NODISCARD_CTOR
|
||||
parse_error(std::string&& description, const source_region& source) noexcept
|
||||
: parse_error{ std::move(description), source_region{ source } }
|
||||
parse_error(std::string&& desc, const source_region& src) noexcept
|
||||
: parse_error{ std::move(desc), source_region{ src } }
|
||||
{}
|
||||
|
||||
TOML_NODISCARD_CTOR
|
||||
parse_error(std::string&& description, const source_position& position, const source_path_ptr& path = {}) noexcept
|
||||
: parse_error{ std::move(description), source_region{ position, position, path } }
|
||||
parse_error(std::string&& desc, const source_position& position, const source_path_ptr& path = {}) noexcept
|
||||
: parse_error{ std::move(desc), source_region{ position, position, path } }
|
||||
{}
|
||||
|
||||
|
||||
/// \brief Returns a textual description of the error.
|
||||
[[nodiscard]]
|
||||
std::string_view what() const noexcept
|
||||
std::string_view description() const noexcept
|
||||
{
|
||||
return description_;
|
||||
}
|
||||
|
||||
/// \brief Returns the region of the source document responsible for the error.
|
||||
[[nodiscard]]
|
||||
const source_region& where() const noexcept
|
||||
const source_region& source() const noexcept
|
||||
{
|
||||
return source_;
|
||||
}
|
||||
@ -468,103 +517,14 @@ namespace toml
|
||||
#endif
|
||||
|
||||
TOML_POP_WARNINGS
|
||||
|
||||
struct date final
|
||||
{
|
||||
uint16_t year;
|
||||
uint8_t month;
|
||||
uint8_t day;
|
||||
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator == (date lhs, date rhs) noexcept
|
||||
{
|
||||
return lhs.year == rhs.year
|
||||
&& lhs.month == rhs.month
|
||||
&& lhs.day == rhs.day;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator != (date lhs, date rhs) noexcept
|
||||
{
|
||||
return lhs.year != rhs.year
|
||||
|| lhs.month != rhs.month
|
||||
|| lhs.day != rhs.day;
|
||||
}
|
||||
};
|
||||
|
||||
struct time final
|
||||
{
|
||||
uint8_t hour;
|
||||
uint8_t minute;
|
||||
uint8_t second;
|
||||
uint32_t nanosecond;
|
||||
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator == (const time& lhs, const time& rhs) noexcept
|
||||
{
|
||||
return lhs.hour == rhs.hour
|
||||
&& lhs.minute == rhs.minute
|
||||
&& lhs.second == rhs.second
|
||||
&& lhs.nanosecond == rhs.nanosecond;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator != (const time& lhs, const time& rhs) noexcept
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
};
|
||||
|
||||
struct time_offset final
|
||||
{
|
||||
int16_t minutes;
|
||||
|
||||
[[nodiscard]]
|
||||
static constexpr time_offset from_hh_mm(int8_t hours, int8_t minutes) noexcept
|
||||
{
|
||||
return time_offset{ static_cast<int16_t>(hours * 60 + minutes) };
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator == (time_offset lhs, time_offset rhs) noexcept
|
||||
{
|
||||
return lhs.minutes == rhs.minutes;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator != (time_offset lhs, time_offset rhs) noexcept
|
||||
{
|
||||
return lhs.minutes != rhs.minutes;
|
||||
}
|
||||
};
|
||||
|
||||
struct date_time final
|
||||
{
|
||||
toml::date date;
|
||||
toml::time time;
|
||||
std::optional<toml::time_offset> time_offset;
|
||||
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator == (const date_time& lhs, const date_time& rhs) noexcept
|
||||
{
|
||||
return lhs.date == rhs.date
|
||||
&& lhs.time == rhs.time
|
||||
&& lhs.time_offset == rhs.time_offset;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator != (const date_time& lhs, const date_time& rhs) noexcept
|
||||
{
|
||||
return lhs.date != rhs.date
|
||||
|| lhs.time != rhs.time
|
||||
|| lhs.time_offset != rhs.time_offset;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
/// \brief Internal implementation details. No user-serviceable parts within.
|
||||
namespace toml::impl
|
||||
{
|
||||
template <typename T>
|
||||
using string_map = std::map<string, T, std::less<>>; //heterogeneous lookup
|
||||
|
||||
#if defined(__cpp_lib_remove_cvref) || (defined(_MSC_VER) && defined(_HAS_CXX20))
|
||||
|
||||
template <typename T>
|
||||
@ -656,6 +616,7 @@ namespace toml::impl
|
||||
template <> struct value_promoter<uint16_t> { using type = int64_t; };
|
||||
template <> struct value_promoter<uint8_t> { using type = int64_t; };
|
||||
template <> struct value_promoter<float> { using type = double; };
|
||||
template <typename T> using promoted = typename impl::value_promoter<T>::type;
|
||||
|
||||
inline constexpr toml::string_view low_character_escape_table[] =
|
||||
{
|
||||
@ -705,6 +666,28 @@ namespace toml::impl
|
||||
"time"sv,
|
||||
"date-time"sv
|
||||
};
|
||||
|
||||
|
||||
#define TOML_P2S_DECL(linkage, type) \
|
||||
template <typename CHAR> \
|
||||
linkage void print_to_stream(type, std::basic_ostream<CHAR>&) TOML_MAY_THROW
|
||||
|
||||
TOML_P2S_DECL(TOML_ALWAYS_INLINE, int8_t);
|
||||
TOML_P2S_DECL(TOML_ALWAYS_INLINE, int16_t);
|
||||
TOML_P2S_DECL(TOML_ALWAYS_INLINE, int32_t);
|
||||
TOML_P2S_DECL(TOML_ALWAYS_INLINE, int64_t);
|
||||
TOML_P2S_DECL(TOML_ALWAYS_INLINE, uint8_t);
|
||||
TOML_P2S_DECL(TOML_ALWAYS_INLINE, uint16_t);
|
||||
TOML_P2S_DECL(TOML_ALWAYS_INLINE, uint32_t);
|
||||
TOML_P2S_DECL(TOML_ALWAYS_INLINE, uint64_t);
|
||||
TOML_P2S_DECL(TOML_ALWAYS_INLINE, float);
|
||||
TOML_P2S_DECL(TOML_ALWAYS_INLINE, double);
|
||||
TOML_P2S_DECL(inline, const date&);
|
||||
TOML_P2S_DECL(inline, const time&);
|
||||
TOML_P2S_DECL(inline, time_offset);
|
||||
TOML_P2S_DECL(inline, const date_time&);
|
||||
|
||||
#undef TOML_P2S_DECL
|
||||
}
|
||||
|
||||
namespace toml
|
||||
@ -715,9 +698,6 @@ namespace toml
|
||||
template <typename T>
|
||||
using value_of = typename impl::node_unwrapper<T>::type;
|
||||
|
||||
template <typename T>
|
||||
using promoted = typename impl::value_promoter<T>::type;
|
||||
|
||||
template <typename CHAR>
|
||||
inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, node_type rhs) TOML_MAY_THROW
|
||||
{
|
||||
|
135
include/toml++/toml_date_time.h
Normal file
135
include/toml++/toml_date_time.h
Normal file
@ -0,0 +1,135 @@
|
||||
#pragma once
|
||||
#include "toml_common.h"
|
||||
|
||||
namespace toml
|
||||
{
|
||||
struct date final
|
||||
{
|
||||
uint16_t year;
|
||||
uint8_t month;
|
||||
uint8_t day;
|
||||
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator == (date lhs, date rhs) noexcept
|
||||
{
|
||||
return lhs.year == rhs.year
|
||||
&& lhs.month == rhs.month
|
||||
&& lhs.day == rhs.day;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator != (date lhs, date rhs) noexcept
|
||||
{
|
||||
return lhs.year != rhs.year
|
||||
|| lhs.month != rhs.month
|
||||
|| lhs.day != rhs.day;
|
||||
}
|
||||
|
||||
template <typename CHAR>
|
||||
friend inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const date& rhs)
|
||||
TOML_MAY_THROW
|
||||
{
|
||||
impl::print_to_stream(rhs, lhs);
|
||||
return lhs;
|
||||
}
|
||||
};
|
||||
|
||||
struct time final
|
||||
{
|
||||
uint8_t hour;
|
||||
uint8_t minute;
|
||||
uint8_t second;
|
||||
uint32_t nanosecond;
|
||||
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator == (const time& lhs, const time& rhs) noexcept
|
||||
{
|
||||
return lhs.hour == rhs.hour
|
||||
&& lhs.minute == rhs.minute
|
||||
&& lhs.second == rhs.second
|
||||
&& lhs.nanosecond == rhs.nanosecond;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator != (const time& lhs, const time& rhs) noexcept
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
template <typename CHAR>
|
||||
friend inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const time& rhs)
|
||||
TOML_MAY_THROW
|
||||
{
|
||||
impl::print_to_stream(rhs, lhs);
|
||||
return lhs;
|
||||
}
|
||||
};
|
||||
|
||||
struct time_offset final
|
||||
{
|
||||
int16_t minutes;
|
||||
|
||||
[[nodiscard]]
|
||||
static constexpr time_offset from_hh_mm(int8_t hours, int8_t minutes) noexcept
|
||||
{
|
||||
return time_offset{ static_cast<int16_t>(hours * 60 + minutes) };
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator == (time_offset lhs, time_offset rhs) noexcept
|
||||
{
|
||||
return lhs.minutes == rhs.minutes;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator != (time_offset lhs, time_offset rhs) noexcept
|
||||
{
|
||||
return lhs.minutes != rhs.minutes;
|
||||
}
|
||||
|
||||
template <typename CHAR>
|
||||
friend inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const time_offset& rhs)
|
||||
TOML_MAY_THROW
|
||||
{
|
||||
impl::print_to_stream(rhs, lhs);
|
||||
return lhs;
|
||||
}
|
||||
};
|
||||
|
||||
struct date_time final
|
||||
{
|
||||
toml::date date;
|
||||
toml::time time;
|
||||
std::optional<toml::time_offset> time_offset;
|
||||
|
||||
[[nodiscard]]
|
||||
constexpr bool is_local() const noexcept
|
||||
{
|
||||
return !time_offset.has_value();
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator == (const date_time& lhs, const date_time& rhs) noexcept
|
||||
{
|
||||
return lhs.date == rhs.date
|
||||
&& lhs.time == rhs.time
|
||||
&& lhs.time_offset == rhs.time_offset;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator != (const date_time& lhs, const date_time& rhs) noexcept
|
||||
{
|
||||
return lhs.date != rhs.date
|
||||
|| lhs.time != rhs.time
|
||||
|| lhs.time_offset != rhs.time_offset;
|
||||
}
|
||||
|
||||
template <typename CHAR>
|
||||
friend inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const date_time& rhs)
|
||||
TOML_MAY_THROW
|
||||
{
|
||||
impl::print_to_stream(rhs, lhs);
|
||||
return lhs;
|
||||
}
|
||||
};
|
||||
}
|
@ -6,6 +6,7 @@
|
||||
|
||||
namespace toml::impl
|
||||
{
|
||||
[[nodiscard]]
|
||||
inline toml::string default_formatter_make_key_segment(const toml::string& str) noexcept
|
||||
{
|
||||
if (str.empty())
|
||||
@ -40,6 +41,7 @@ namespace toml::impl
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
inline size_t default_formatter_inline_columns(const node& node) noexcept
|
||||
{
|
||||
return node.visit([](const auto& n) noexcept
|
||||
@ -110,6 +112,7 @@ namespace toml::impl
|
||||
});
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
inline bool default_formatter_forces_multiline(const node& node, size_t starting_column_bias = 0) noexcept
|
||||
{
|
||||
return (default_formatter_inline_columns(node) + starting_column_bias) > 120_sz;
|
||||
|
@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
#include "toml_value.h"
|
||||
#include "toml_print_to_stream.h"
|
||||
|
||||
namespace toml::impl
|
||||
{
|
||||
@ -8,6 +8,7 @@ namespace toml::impl
|
||||
// TINAE - char can have signed _or_ unsigned semantics and I can't
|
||||
// be arsed handling this differently
|
||||
|
||||
[[nodiscard]]
|
||||
inline toml::string_view escape_string_character(const toml::string_char& c) noexcept
|
||||
{
|
||||
if (c >= TOML_STRING_PREFIX('\x00') && c <= TOML_STRING_PREFIX('\x1F')) TOML_UNLIKELY
|
||||
@ -40,17 +41,16 @@ namespace toml::impl
|
||||
size_t indent_columns_;
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
[[nodiscard]] const toml::table& source() const noexcept { return source_; }
|
||||
[[nodiscard]] const formatter_options& options() const noexcept { return options_; }
|
||||
[[nodiscard]] std::basic_ostream<CHAR>& stream() const noexcept { return *stream_; }
|
||||
|
||||
[[nodiscard]] int indent() const noexcept { return indent_; }
|
||||
[[nodiscard]] size_t indent_columns() const noexcept { return indent_columns_; }
|
||||
void indent(int level) noexcept { indent_ = level; }
|
||||
void increase_indent() noexcept { indent_++; }
|
||||
void decrease_indent() noexcept { indent_--; }
|
||||
size_t indent_columns() const noexcept { return indent_columns_; }
|
||||
|
||||
void clear_naked_newline() noexcept { naked_newline_ = false; }
|
||||
|
||||
|
@ -35,11 +35,12 @@ namespace toml
|
||||
return reinterpret_cast<const node_of<T>*>(this);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
node() noexcept = default;
|
||||
node(const node&) = delete;
|
||||
node& operator= (const node&) = delete;
|
||||
|
||||
public:
|
||||
|
||||
virtual ~node() noexcept = default;
|
||||
|
||||
[[nodiscard]] virtual node_type type() const noexcept = 0;
|
||||
|
@ -199,7 +199,7 @@ namespace toml
|
||||
template <typename U>
|
||||
[[nodiscard]] static bool value_equality(const node_view& lhs, const U& rhs) noexcept
|
||||
{
|
||||
const auto val = lhs.as<promoted<U>>();
|
||||
const auto val = lhs.as<impl::promoted<U>>();
|
||||
return val && val->get() == rhs;
|
||||
}
|
||||
|
||||
@ -222,7 +222,7 @@ namespace toml
|
||||
size_t i{};
|
||||
for (auto& list_elem : rhs)
|
||||
{
|
||||
const auto elem = arr->get_as<promoted<elem_t>>(i++);
|
||||
const auto elem = arr->get_as<impl::promoted<elem_t>>(i++);
|
||||
if (!elem || elem->get() != list_elem)
|
||||
return false;
|
||||
}
|
||||
@ -282,10 +282,6 @@ namespace toml
|
||||
return { this, key };
|
||||
}
|
||||
|
||||
// inline constexpr auto kek1 = sizeof(node_view<table>);
|
||||
// inline constexpr auto kek2 = sizeof(decltype(std::declval<node_view<table>>()[0]));
|
||||
// inline constexpr auto kek3 = sizeof(decltype(std::declval<node_view<table>>()["kek"sv]));
|
||||
|
||||
inline node_view<const table> table::operator[] (string_view key) const noexcept
|
||||
{
|
||||
return { this, key };
|
||||
|
@ -1,8 +1,8 @@
|
||||
#pragma once
|
||||
#include "toml_utf8.h"
|
||||
#include "toml_value.h"
|
||||
#include "toml_array.h"
|
||||
#include "toml_table.h"
|
||||
#include "toml_array.h"
|
||||
#include "toml_value.h"
|
||||
|
||||
namespace toml
|
||||
{
|
||||
@ -146,6 +146,48 @@ namespace toml::impl
|
||||
#define TOML_ERROR err.emplace
|
||||
#endif
|
||||
|
||||
#if !TOML_EXCEPTIONS || defined(__INTELLISENSE__)
|
||||
#define TOML_NORETURN
|
||||
#else
|
||||
#define TOML_NORETURN [[noreturn]]
|
||||
#endif
|
||||
|
||||
template <int> struct parse_integer_traits;
|
||||
template <> struct parse_integer_traits<2> final
|
||||
{
|
||||
static constexpr auto qualifier = "binary"sv;
|
||||
static constexpr auto is_digit = is_binary_digit;
|
||||
static constexpr auto is_signed = false;
|
||||
static constexpr auto buffer_length = 63;
|
||||
static constexpr char32_t prefix_codepoint = U'b';
|
||||
static constexpr char prefix = 'b';
|
||||
};
|
||||
template <> struct parse_integer_traits<8> final
|
||||
{
|
||||
static constexpr auto qualifier = "octal"sv;
|
||||
static constexpr auto is_digit = is_octal_digit;
|
||||
static constexpr auto is_signed = false;
|
||||
static constexpr auto buffer_length = 21; // strlen("777777777777777777777")
|
||||
static constexpr char32_t prefix_codepoint = U'o';
|
||||
static constexpr char prefix = 'o';
|
||||
};
|
||||
template <> struct parse_integer_traits<10> final
|
||||
{
|
||||
static constexpr auto qualifier = "decimal"sv;
|
||||
static constexpr auto is_digit = is_decimal_digit;
|
||||
static constexpr auto is_signed = true;
|
||||
static constexpr auto buffer_length = 19; //strlen("9223372036854775807")
|
||||
};
|
||||
template <> struct parse_integer_traits<16> final
|
||||
{
|
||||
static constexpr auto qualifier = "hexadecimal"sv;
|
||||
static constexpr auto is_digit = is_hexadecimal_digit;
|
||||
static constexpr auto is_signed = false;
|
||||
static constexpr auto buffer_length = 16; //strlen("7FFFFFFFFFFFFFFF")
|
||||
static constexpr char32_t prefix_codepoint = U'x';
|
||||
static constexpr char prefix = 'x';
|
||||
};
|
||||
|
||||
class parser final
|
||||
{
|
||||
private:
|
||||
@ -171,9 +213,7 @@ namespace toml::impl
|
||||
}
|
||||
|
||||
template <typename... T>
|
||||
#if TOML_EXCEPTIONS
|
||||
[[noreturn]]
|
||||
#endif
|
||||
TOML_NORETURN
|
||||
void abort_with_error(T &&... args) const TOML_MAY_THROW
|
||||
{
|
||||
TOML_ERROR_CHECK();
|
||||
@ -541,7 +581,7 @@ namespace toml::impl
|
||||
{
|
||||
eof_check();
|
||||
|
||||
if (!is_hex_digit(*cp))
|
||||
if (!is_hexadecimal_digit(*cp))
|
||||
abort_with_error(
|
||||
"Encountered unexpected character while parsing "sv,
|
||||
(MULTI_LINE ? "multi-line "sv : ""sv),
|
||||
@ -1159,7 +1199,7 @@ namespace toml::impl
|
||||
|
||||
if (*cp == U'_')
|
||||
{
|
||||
if (!prev || !is_hex_digit(*prev))
|
||||
if (!prev || !is_hexadecimal_digit(*prev))
|
||||
abort_with_error(
|
||||
"Encountered unexpected character while parsing hexadecimal "sv,
|
||||
node_type::floating_point, "; underscores may only follow digits"sv
|
||||
@ -1214,7 +1254,7 @@ namespace toml::impl
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!seen_exponent && !is_hex_digit(*cp))
|
||||
if (!seen_exponent && !is_hexadecimal_digit(*cp))
|
||||
abort_with_error("Encountered unexpected character while parsing hexadecimal "sv,
|
||||
node_type::floating_point, "; expected hexadecimal digit, saw '"sv, *cp, '\''
|
||||
);
|
||||
@ -1287,41 +1327,73 @@ namespace toml::impl
|
||||
|
||||
#endif //!TOML_USE_STREAMS_FOR_FLOATS && TOML_LANG_HIGHER_THAN(0, 5, 0)
|
||||
|
||||
template <int base>
|
||||
[[nodiscard]]
|
||||
int64_t parse_binary_integer() TOML_MAY_THROW
|
||||
int64_t parse_integer() TOML_MAY_THROW
|
||||
{
|
||||
TOML_ERROR_CHECK({});
|
||||
TOML_ASSERT(cp && *cp == U'0');
|
||||
TOML_ASSERT(cp);
|
||||
using traits = parse_integer_traits<base>;
|
||||
|
||||
const auto eof_check = [this]() TOML_MAY_THROW
|
||||
{
|
||||
TOML_ERROR_CHECK();
|
||||
if (!cp)
|
||||
abort_with_error("Encountered EOF while parsing binary "sv, node_type::integer);
|
||||
abort_with_error(
|
||||
"Encountered EOF while parsing "sv, traits::qualifier, ' ', node_type::integer
|
||||
);
|
||||
};
|
||||
|
||||
// '0'
|
||||
if (*cp != U'0')
|
||||
abort_with_error(
|
||||
"Encountered unexpected character while parsing binary "sv,
|
||||
node_type::integer, "; expected '0', saw '"sv, *cp, '\''
|
||||
);
|
||||
advance();
|
||||
eof_check();
|
||||
[[maybe_unused]] int64_t sign = 1;
|
||||
if constexpr (traits::is_signed)
|
||||
{
|
||||
if (*cp == U'-')
|
||||
{
|
||||
sign = -1;
|
||||
advance();
|
||||
}
|
||||
else if(*cp == U'+')
|
||||
advance();
|
||||
eof_check();
|
||||
|
||||
// 'b' or 'B'
|
||||
if (*cp != U'b' && *cp != U'B')
|
||||
abort_with_error(
|
||||
"Encountered unexpected character while parsing binary "sv,
|
||||
node_type::integer, "; expected 'b' or 'B', saw '"sv, *cp, '\''
|
||||
);
|
||||
advance();
|
||||
eof_check();
|
||||
TOML_ERROR_CHECK({});
|
||||
}
|
||||
|
||||
if constexpr (base == 10)
|
||||
{
|
||||
if (!traits::is_digit(*cp))
|
||||
abort_with_error(
|
||||
"Encountered unexpected character while parsing "sv, traits::qualifier, ' ',
|
||||
node_type::integer, "; expected expected "sv, traits::qualifier,
|
||||
" digit or sign, saw '"sv, *cp, '\''
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
// '0'
|
||||
if (*cp != U'0')
|
||||
abort_with_error(
|
||||
"Encountered unexpected character while parsing "sv, traits::qualifier,
|
||||
' ', node_type::integer, "; expected '0', saw '"sv, *cp, '\''
|
||||
);
|
||||
advance();
|
||||
eof_check();
|
||||
|
||||
// 'b', 'o', 'x'
|
||||
if (*cp != traits::prefix_codepoint)
|
||||
abort_with_error(
|
||||
"Encountered unexpected character while parsing "sv, traits::qualifier,
|
||||
' ', node_type::integer, "; expected '"sv, traits::prefix,
|
||||
"', saw '"sv, *cp, '\''
|
||||
);
|
||||
advance();
|
||||
eof_check();
|
||||
}
|
||||
|
||||
TOML_ERROR_CHECK({});
|
||||
|
||||
// consume value chars
|
||||
TOML_GCC_ATTR(uninitialized) char chars[64];
|
||||
TOML_GCC_ATTR(uninitialized) char chars[traits::buffer_length];
|
||||
size_t length = {};
|
||||
const utf8_codepoint* prev = {};
|
||||
while (true)
|
||||
@ -1331,22 +1403,23 @@ namespace toml::impl
|
||||
|
||||
if (*cp == U'_')
|
||||
{
|
||||
if (!prev || !is_binary_digit(*prev))
|
||||
if (!prev || !traits::is_digit(*prev))
|
||||
abort_with_error(
|
||||
"Encountered unexpected character while parsing binary "sv,
|
||||
node_type::integer, "; underscores may only follow digits"sv
|
||||
"Encountered unexpected character while parsing "sv, traits::qualifier,
|
||||
' ', node_type::integer, "; expected "sv, traits::qualifier, " digit, saw '_'"sv
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!is_binary_digit(*cp))
|
||||
if (!traits::is_digit(*cp))
|
||||
abort_with_error(
|
||||
"Encountered unexpected character while parsing binary "sv,
|
||||
node_type::integer, "; expected binary digit, saw '"sv, *cp, '\''
|
||||
"Encountered unexpected character while parsing "sv, traits::qualifier,
|
||||
' ', node_type::integer, "; expected "sv, traits::qualifier,
|
||||
" digit, saw '"sv, *cp, '\''
|
||||
);
|
||||
if (length == sizeof(chars))
|
||||
abort_with_error(
|
||||
"Error parsing binary "sv, node_type::integer,
|
||||
"Error parsing "sv, traits::qualifier, ' ', node_type::integer,
|
||||
"; exceeds maximum length of "sv, sizeof(chars), " characters"sv
|
||||
);
|
||||
chars[length++] = static_cast<char>(cp->bytes[0]);
|
||||
@ -1360,399 +1433,84 @@ namespace toml::impl
|
||||
{
|
||||
eof_check();
|
||||
abort_with_error(
|
||||
"Encountered unexpected character while parsing binary "sv,
|
||||
node_type::integer, "; expected binary digit, saw '"sv, *cp, '\''
|
||||
"Encountered unexpected character while parsing "sv, traits::qualifier,
|
||||
' ', node_type::integer, "; expected "sv, traits::qualifier, " digit, saw '_'"sv
|
||||
);
|
||||
}
|
||||
|
||||
// check for leading zeroes
|
||||
if constexpr (base == 10)
|
||||
{
|
||||
if (chars[0] == '0')
|
||||
abort_with_error(
|
||||
"Error parsing "sv, traits::qualifier,
|
||||
' ', node_type::integer, "; leading zeroes are not allowed"sv
|
||||
);
|
||||
}
|
||||
|
||||
TOML_ERROR_CHECK({});
|
||||
|
||||
// single digits can be converted directly
|
||||
if (length == 1_sz)
|
||||
return chars[0] == '1' ? 1ull : 0ull;
|
||||
|
||||
TOML_ERROR_CHECK({});
|
||||
|
||||
// otherwise invoke charconv
|
||||
TOML_GCC_ATTR(uninitialized) int64_t result;
|
||||
auto parse_result = std::from_chars(chars, chars + length, result, 2);
|
||||
switch (parse_result.ec)
|
||||
{
|
||||
case std::errc{}: //ok
|
||||
return result;
|
||||
|
||||
case std::errc::invalid_argument:
|
||||
abort_with_error(
|
||||
"Error parsing binary "sv, node_type::integer,
|
||||
"; '"sv, std::string_view{ chars, length }, "' could not be interpreted as a value"sv
|
||||
);
|
||||
break;
|
||||
|
||||
case std::errc::result_out_of_range:
|
||||
abort_with_error(
|
||||
"Error parsing binary "sv, node_type::integer,
|
||||
"; '"sv, std::string_view{ chars, length }, "' is not representable in 64 bits"sv
|
||||
);
|
||||
break;
|
||||
|
||||
default: //??
|
||||
abort_with_error(
|
||||
"Error parsing binary "sv, node_type::integer,
|
||||
"; an unspecified error occurred while trying to interpret '",
|
||||
std::string_view{ chars, length }, "' as a value"sv
|
||||
);
|
||||
}
|
||||
|
||||
TOML_ERROR_CHECK({});
|
||||
TOML_UNREACHABLE;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
int64_t parse_octal_integer() TOML_MAY_THROW
|
||||
{
|
||||
TOML_ERROR_CHECK({});
|
||||
TOML_ASSERT(cp && *cp == U'0');
|
||||
|
||||
const auto eof_check = [this]() TOML_MAY_THROW
|
||||
{
|
||||
TOML_ERROR_CHECK();
|
||||
if (!cp)
|
||||
abort_with_error("Encountered EOF while parsing octal "sv, node_type::integer);
|
||||
};
|
||||
|
||||
// '0'
|
||||
if (*cp != U'0')
|
||||
abort_with_error(
|
||||
"Encountered unexpected character while parsing octal "sv, node_type::integer,
|
||||
"; expected '0', saw '"sv, *cp, '\''
|
||||
);
|
||||
advance();
|
||||
eof_check();
|
||||
|
||||
// 'o'
|
||||
if (*cp != U'o')
|
||||
abort_with_error(
|
||||
"Encountered unexpected character while parsing octal "sv, node_type::integer,
|
||||
"; expected 'o', saw '"sv, *cp, '\''
|
||||
);
|
||||
advance();
|
||||
eof_check();
|
||||
|
||||
TOML_ERROR_CHECK({});
|
||||
|
||||
// consume value chars
|
||||
TOML_GCC_ATTR(uninitialized) char chars[21]; //21 == strlen("777777777777777777777") (max 64-bit uint)
|
||||
size_t length = {};
|
||||
const utf8_codepoint* prev = {};
|
||||
while (true)
|
||||
{
|
||||
if (!cp || is_value_terminator(*cp))
|
||||
break;
|
||||
|
||||
if (*cp == U'_')
|
||||
if constexpr (base > 10)
|
||||
{
|
||||
if (!prev || !is_octal_digit(*prev))
|
||||
abort_with_error(
|
||||
"Encountered unexpected character while parsing octal "sv, node_type::integer,
|
||||
"; underscores may only follow digits"sv
|
||||
);
|
||||
return chars[0] >= 'A'
|
||||
? 10LL + static_cast<int64_t>(*cp - (*cp >= 'a' ? 'a' : 'A'))
|
||||
: static_cast<int64_t>(*cp - '0');
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!is_octal_digit(*cp))
|
||||
abort_with_error(
|
||||
"Encountered unexpected character while parsing octal "sv, node_type::integer,
|
||||
"; expected octal digit, saw '"sv, *cp, '\''
|
||||
);
|
||||
if (length == sizeof(chars))
|
||||
abort_with_error(
|
||||
"Error parsing octal "sv, node_type::integer,
|
||||
"; exceeds maximum length of "sv, sizeof(chars), " characters"sv
|
||||
);
|
||||
chars[length++] = static_cast<char>(cp->bytes[0]);
|
||||
}
|
||||
|
||||
prev = cp;
|
||||
advance();
|
||||
|
||||
TOML_ERROR_CHECK({});
|
||||
return static_cast<int64_t>(chars[0] - '0');
|
||||
}
|
||||
if (prev && *prev == U'_')
|
||||
{
|
||||
eof_check();
|
||||
abort_with_error(
|
||||
"Encountered unexpected character while parsing octal "sv, node_type::integer,
|
||||
"; expected octal digit, saw '"sv, *cp, '\''
|
||||
);
|
||||
}
|
||||
|
||||
// single digits can be converted directly
|
||||
if (length == 1_sz)
|
||||
return static_cast<int64_t>(chars[0] - '0');
|
||||
|
||||
TOML_ERROR_CHECK({});
|
||||
|
||||
// otherwise invoke charconv
|
||||
TOML_GCC_ATTR(uninitialized) int64_t result;
|
||||
auto parse_result = std::from_chars(chars, chars + length, result, 8);
|
||||
switch (parse_result.ec)
|
||||
{
|
||||
case std::errc{}: //ok
|
||||
return result;
|
||||
|
||||
case std::errc::invalid_argument:
|
||||
abort_with_error(
|
||||
"Error parsing octal "sv, node_type::integer,
|
||||
"; '"sv, std::string_view{ chars, length }, "' could not be interpreted as a value"sv
|
||||
);
|
||||
break;
|
||||
|
||||
case std::errc::result_out_of_range:
|
||||
abort_with_error(
|
||||
"Error parsing octal "sv, node_type::integer,
|
||||
"; '"sv, std::string_view{ chars, length }, "' is not representable in 64 bits"sv
|
||||
);
|
||||
break;
|
||||
|
||||
default: //??
|
||||
abort_with_error(
|
||||
"Error parsing octal "sv, node_type::integer,
|
||||
"; an unspecified error occurred while trying to interpret '",
|
||||
std::string_view{ chars, length }, "' as a value"sv
|
||||
);
|
||||
}
|
||||
TOML_ERROR_CHECK({});
|
||||
TOML_UNREACHABLE;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
int64_t parse_decimal_integer() TOML_MAY_THROW
|
||||
{
|
||||
TOML_ERROR_CHECK({});
|
||||
TOML_ASSERT(cp && (*cp == U'+' || *cp == U'-' || is_decimal_digit(*cp)));
|
||||
|
||||
const auto eof_check = [this]() TOML_MAY_THROW
|
||||
{
|
||||
TOML_ERROR_CHECK();
|
||||
if (!cp)
|
||||
abort_with_error("Encountered EOF while parsing "sv, node_type::integer);
|
||||
};
|
||||
|
||||
// sign
|
||||
const int64_t sign = *cp == U'-' ? -1ll : 1ll;
|
||||
if (*cp == U'+' || *cp == U'-')
|
||||
{
|
||||
advance();
|
||||
eof_check();
|
||||
}
|
||||
|
||||
TOML_ERROR_CHECK({});
|
||||
|
||||
// consume value chars
|
||||
TOML_GCC_ATTR(uninitialized) char chars[19]; //19 == strlen("9223372036854775807") (max 64-bit uint)
|
||||
size_t length = {};
|
||||
const utf8_codepoint* prev = {};
|
||||
while (true)
|
||||
{
|
||||
if (!cp || is_value_terminator(*cp))
|
||||
break;
|
||||
|
||||
if (*cp == U'_')
|
||||
{
|
||||
if (!prev || !is_decimal_digit(*prev))
|
||||
abort_with_error(
|
||||
"Encountered unexpected character while parsing "sv, node_type::integer,
|
||||
"; underscores may only follow digits"sv
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!is_decimal_digit(*cp))
|
||||
abort_with_error(
|
||||
"Encountered unexpected character while parsing "sv, node_type::integer,
|
||||
"; expected decimal digit, saw '"sv, *cp, '\''
|
||||
);
|
||||
if (length == sizeof(chars))
|
||||
abort_with_error(
|
||||
"Error parsing "sv, node_type::integer,
|
||||
"; exceeds maximum length of "sv, sizeof(chars), " characters"sv
|
||||
);
|
||||
chars[length++] = static_cast<char>(cp->bytes[0]);
|
||||
}
|
||||
|
||||
prev = cp;
|
||||
advance();
|
||||
TOML_ERROR_CHECK({});
|
||||
}
|
||||
if (prev && *prev == U'_')
|
||||
{
|
||||
eof_check();
|
||||
abort_with_error(
|
||||
"Encountered unexpected character while parsing "sv, node_type::integer,
|
||||
"; expected decimal digit, saw '"sv, *cp, '\''
|
||||
);
|
||||
}
|
||||
|
||||
// check for leading zeroes etc
|
||||
if (chars[0] == '0')
|
||||
abort_with_error(
|
||||
"Encountered unexpected character while parsing "sv, node_type::integer,
|
||||
"; leading zeroes are not allowed"sv
|
||||
);
|
||||
|
||||
TOML_ERROR_CHECK({});
|
||||
|
||||
// convert to int
|
||||
TOML_GCC_ATTR(uninitialized) uint64_t result;
|
||||
auto parse_result = std::from_chars(chars, chars + length, result);
|
||||
if (parse_result.ec == std::errc{} && (
|
||||
(sign < 0 && result > static_cast<uint64_t>(std::numeric_limits<int64_t>::max()) + 1ull)
|
||||
|| (sign > 0 && result > static_cast<uint64_t>(std::numeric_limits<int64_t>::max()))
|
||||
))
|
||||
parse_result.ec = std::errc::result_out_of_range;
|
||||
auto parse_result = std::from_chars(chars, chars + length, result, base);
|
||||
if constexpr (traits::is_signed)
|
||||
{
|
||||
if (parse_result.ec == std::errc{} && (
|
||||
(sign < 0 && result > static_cast<uint64_t>(std::numeric_limits<int64_t>::max()) + 1ull)
|
||||
|| (sign > 0 && result > static_cast<uint64_t>(std::numeric_limits<int64_t>::max()))
|
||||
))
|
||||
parse_result.ec = std::errc::result_out_of_range;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (parse_result.ec == std::errc{} &&
|
||||
result > static_cast<uint64_t>(std::numeric_limits<int64_t>::max())
|
||||
)
|
||||
parse_result.ec = std::errc::result_out_of_range;
|
||||
}
|
||||
switch (parse_result.ec)
|
||||
{
|
||||
case std::errc{}: //ok
|
||||
return static_cast<int64_t>(result) * sign;
|
||||
if constexpr (traits::is_signed)
|
||||
return static_cast<int64_t>(result) * sign;
|
||||
else
|
||||
return static_cast<int64_t>(result);
|
||||
|
||||
case std::errc::invalid_argument:
|
||||
abort_with_error(
|
||||
"Error parsing "sv, node_type::integer,
|
||||
"Error parsing "sv, traits::qualifier, ' ', node_type::integer,
|
||||
"; '"sv, std::string_view{ chars, length }, "' could not be interpreted as a value"sv
|
||||
);
|
||||
break;
|
||||
|
||||
case std::errc::result_out_of_range:
|
||||
abort_with_error(
|
||||
"Error parsing "sv, node_type::integer,
|
||||
"Error parsing "sv, traits::qualifier, ' ', node_type::integer,
|
||||
"; '"sv, std::string_view{ chars, length }, "' is not representable in 64 bits"sv
|
||||
);
|
||||
break;
|
||||
|
||||
default: //??
|
||||
abort_with_error(
|
||||
"Error parsing "sv, node_type::integer,
|
||||
"Error parsing "sv, traits::qualifier, ' ', node_type::integer,
|
||||
"; an unspecified error occurred while trying to interpret '",
|
||||
std::string_view{ chars, length }, "' as a value"sv
|
||||
);
|
||||
}
|
||||
TOML_ERROR_CHECK({});
|
||||
TOML_UNREACHABLE;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
int64_t parse_hex_integer() TOML_MAY_THROW
|
||||
{
|
||||
TOML_ERROR_CHECK({});
|
||||
TOML_ASSERT(cp && *cp == U'0');
|
||||
|
||||
const auto eof_check = [this]() TOML_MAY_THROW
|
||||
{
|
||||
TOML_ERROR_CHECK();
|
||||
if (!cp)
|
||||
abort_with_error("Encountered EOF while parsing hexadecimal "sv, node_type::integer);
|
||||
};
|
||||
|
||||
// '0'
|
||||
if (*cp != U'0')
|
||||
abort_with_error(
|
||||
"Encountered unexpected character while parsing hexadecimal "sv, node_type::integer,
|
||||
"; expected '0', saw '"sv, *cp, '\''
|
||||
);
|
||||
advance();
|
||||
eof_check();
|
||||
|
||||
// 'x' or 'X'
|
||||
if (*cp != U'x' && *cp != U'X')
|
||||
abort_with_error(
|
||||
"Encountered unexpected character while parsing hexadecimal "sv, node_type::integer,
|
||||
"; expected 'x' or 'X', saw '"sv, *cp, '\''
|
||||
);
|
||||
advance();
|
||||
eof_check();
|
||||
|
||||
TOML_ERROR_CHECK({});
|
||||
|
||||
// consume value chars
|
||||
TOML_GCC_ATTR(uninitialized) char chars[16]; //16 == strlen("FFFFFFFFFFFFFFFF") (max 64-bit uint)
|
||||
size_t length = {};
|
||||
const utf8_codepoint* prev = {};
|
||||
while (true)
|
||||
{
|
||||
if (!cp || is_value_terminator(*cp))
|
||||
break;
|
||||
|
||||
if (*cp == U'_')
|
||||
{
|
||||
if (!prev || !is_hex_digit(*prev))
|
||||
abort_with_error(
|
||||
"Encountered unexpected character while parsing hexadecimal "sv, node_type::integer,
|
||||
"; underscores may only follow digits"
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!is_hex_digit(*cp))
|
||||
abort_with_error(
|
||||
"Encountered unexpected character while parsing hexadecimal "sv, node_type::integer,
|
||||
"; expected hexadecimal digit, saw '"sv, *cp, '\''
|
||||
);
|
||||
if (length == sizeof(chars))
|
||||
abort_with_error(
|
||||
"Error parsing hexadecimal "sv, node_type::integer,
|
||||
"; exceeds maximum length of "sv, sizeof(chars), " characters"sv
|
||||
);
|
||||
chars[length++] = static_cast<char>(cp->bytes[0]);
|
||||
}
|
||||
|
||||
prev = cp;
|
||||
advance();
|
||||
TOML_ERROR_CHECK({});
|
||||
}
|
||||
if (prev && *prev == U'_')
|
||||
{
|
||||
eof_check();
|
||||
abort_with_error(
|
||||
"Encountered unexpected character while parsing hexadecimal "sv, node_type::integer,
|
||||
"; expected hexadecimal digit, saw '"sv, *cp, '\''
|
||||
);
|
||||
}
|
||||
|
||||
// single digits can be converted directly
|
||||
if (length == 1_sz)
|
||||
return chars[0] >= 'A'
|
||||
? static_cast<int64_t>(10 + (chars[0] - (chars[0] >= 'a' ? 'a' : 'A')))
|
||||
: static_cast<int64_t>(chars[0] - '0');
|
||||
|
||||
TOML_ERROR_CHECK({});
|
||||
|
||||
// otherwise invoke charconv
|
||||
TOML_GCC_ATTR(uninitialized) int64_t result;
|
||||
auto parse_result = std::from_chars(chars, chars + length, result, 16);
|
||||
switch (parse_result.ec)
|
||||
{
|
||||
case std::errc{}: //ok
|
||||
return result;
|
||||
|
||||
case std::errc::invalid_argument:
|
||||
abort_with_error(
|
||||
"Error parsing hexadecimal "sv, node_type::integer,
|
||||
"; '"sv, std::string_view{ chars, length }, "' could not be interpreted as a value"sv
|
||||
);
|
||||
break;
|
||||
|
||||
case std::errc::result_out_of_range:
|
||||
abort_with_error(
|
||||
"Error parsing hexadecimal "sv, node_type::integer,
|
||||
"; '"sv, std::string_view{ chars, length }, "' is not representable in 64 bits"sv
|
||||
);
|
||||
break;
|
||||
|
||||
default: //??
|
||||
abort_with_error(
|
||||
"Error parsing hexadecimal "sv, node_type::integer,
|
||||
"; an unspecified error occurred while trying to interpret '",
|
||||
std::string_view{ chars, length }, "' as a value"sv
|
||||
);
|
||||
}
|
||||
TOML_ERROR_CHECK({});
|
||||
TOML_UNREACHABLE;
|
||||
}
|
||||
@ -2359,8 +2117,8 @@ namespace toml::impl
|
||||
case U'E': [[fallthrough]];
|
||||
case U'e': [[fallthrough]];
|
||||
case U'.': val = std::make_unique<value<double>>(parse_float()); break;
|
||||
case U'b': val = std::make_unique<value<int64_t>>(parse_binary_integer()); break;
|
||||
case U'o': val = std::make_unique<value<int64_t>>(parse_octal_integer()); break;
|
||||
case U'b': val = std::make_unique<value<int64_t>>(parse_integer<2>()); break;
|
||||
case U'o': val = std::make_unique<value<int64_t>>(parse_integer<8>()); break;
|
||||
case U'X': [[fallthrough]];
|
||||
case U'x':
|
||||
{
|
||||
@ -2393,7 +2151,7 @@ namespace toml::impl
|
||||
if (val)
|
||||
break;
|
||||
|
||||
val = std::make_unique<value<int64_t>>(parse_hex_integer());
|
||||
val = std::make_unique<value<int64_t>>(parse_integer<16>());
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -2410,7 +2168,7 @@ namespace toml::impl
|
||||
{
|
||||
// 100
|
||||
case has_digits:
|
||||
val = std::make_unique<value<int64_t>>(parse_decimal_integer());
|
||||
val = std::make_unique<value<int64_t>>(parse_integer<10>());
|
||||
break;
|
||||
|
||||
// 1e1
|
||||
@ -2491,7 +2249,7 @@ namespace toml::impl
|
||||
// -100
|
||||
case has_digits | has_minus: [[fallthrough]];
|
||||
case has_digits | has_plus:
|
||||
val = std::make_unique<value<int64_t>>(parse_decimal_integer());
|
||||
val = std::make_unique<value<int64_t>>(parse_integer<10>());
|
||||
break;
|
||||
|
||||
// +1e1
|
||||
@ -3256,6 +3014,7 @@ namespace toml::impl
|
||||
|
||||
#undef TOML_ERROR_CHECK
|
||||
#undef TOML_ERROR
|
||||
#undef TOML_NORETURN
|
||||
}
|
||||
|
||||
namespace toml
|
||||
|
@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
#include "toml_common.h"
|
||||
#include "toml_date_time.h"
|
||||
|
||||
namespace toml::impl
|
||||
{
|
||||
@ -213,7 +213,7 @@ namespace toml::impl
|
||||
}
|
||||
|
||||
template <typename CHAR>
|
||||
inline void print_to_stream(const toml::time_offset& val, std::basic_ostream<CHAR>& stream) TOML_MAY_THROW
|
||||
inline void print_to_stream(toml::time_offset val, std::basic_ostream<CHAR>& stream) TOML_MAY_THROW
|
||||
{
|
||||
static_assert(sizeof(CHAR) == 1);
|
||||
if (!val.minutes)
|
||||
@ -253,34 +253,3 @@ namespace toml::impl
|
||||
print_to_stream(*val.time_offset, stream);
|
||||
}
|
||||
}
|
||||
|
||||
namespace toml
|
||||
{
|
||||
template <typename CHAR>
|
||||
inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const date& rhs) TOML_MAY_THROW
|
||||
{
|
||||
impl::print_to_stream(rhs, lhs);
|
||||
return lhs;
|
||||
}
|
||||
|
||||
template <typename CHAR>
|
||||
inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const time& rhs) TOML_MAY_THROW
|
||||
{
|
||||
impl::print_to_stream(rhs, lhs);
|
||||
return lhs;
|
||||
}
|
||||
|
||||
template <typename CHAR>
|
||||
inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const time_offset& rhs) TOML_MAY_THROW
|
||||
{
|
||||
impl::print_to_stream(rhs, lhs);
|
||||
return lhs;
|
||||
}
|
||||
|
||||
template <typename CHAR>
|
||||
inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const date_time& rhs) TOML_MAY_THROW
|
||||
{
|
||||
impl::print_to_stream(rhs, lhs);
|
||||
return lhs;
|
||||
}
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ namespace toml
|
||||
friend class impl::parser;
|
||||
friend class node_view<table>;
|
||||
|
||||
string_map<std::unique_ptr<node>> values;
|
||||
impl::string_map<std::unique_ptr<node>> values;
|
||||
bool inline_ = false;
|
||||
|
||||
public:
|
||||
|
@ -71,7 +71,7 @@ namespace toml::impl
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
constexpr bool is_hex_digit(char32_t codepoint) noexcept
|
||||
constexpr bool is_hexadecimal_digit(char32_t codepoint) noexcept
|
||||
{
|
||||
return (codepoint >= U'a' && codepoint <= U'f')
|
||||
|| (codepoint >= U'A' && codepoint <= U'F')
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
namespace toml::impl
|
||||
{
|
||||
/// \brief Returns true if a codepoint belongs to any of these categories: Ll, Lm, Lo, Lt, Lu
|
||||
//# Returns true if a codepoint belongs to any of these categories: Ll, Lm, Lo, Lt, Lu
|
||||
[[nodiscard]]
|
||||
constexpr bool is_unicode_letter(char32_t codepoint) noexcept
|
||||
{
|
||||
@ -465,7 +465,7 @@ namespace toml::impl
|
||||
// chunk summary: 125582 codepoints from 607 ranges (spanning a search area of 194932)
|
||||
}
|
||||
|
||||
/// \brief Returns true if a codepoint belongs to any of these categories: Nd, Nl
|
||||
//# Returns true if a codepoint belongs to any of these categories: Nd, Nl
|
||||
[[nodiscard]]
|
||||
constexpr bool is_unicode_number(char32_t codepoint) noexcept
|
||||
{
|
||||
@ -578,7 +578,7 @@ namespace toml::impl
|
||||
// chunk summary: 856 codepoints from 70 ranges (spanning a search area of 123642)
|
||||
}
|
||||
|
||||
/// \brief Returns true if a codepoint belongs to any of these categories: Mn, Mc
|
||||
//# Returns true if a codepoint belongs to any of these categories: Mn, Mc
|
||||
[[nodiscard]]
|
||||
constexpr bool is_unicode_combining_mark(char32_t codepoint) noexcept
|
||||
{
|
||||
|
@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
#include "toml_node.h"
|
||||
#include "toml_print_to_stream.h"
|
||||
|
||||
namespace toml
|
||||
{
|
||||
@ -16,22 +15,12 @@ namespace toml
|
||||
private:
|
||||
friend class impl::parser;
|
||||
|
||||
template <typename U>
|
||||
template <typename U, typename V>
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE
|
||||
toml::value<U>* as_value() noexcept
|
||||
static auto as_value([[maybe_unused]] V* ptr) noexcept
|
||||
{
|
||||
if constexpr (std::is_same_v<T, U>)
|
||||
return this;
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE
|
||||
const toml::value<U>* as_value() const noexcept
|
||||
{
|
||||
if constexpr (std::is_same_v<T, U>)
|
||||
return this;
|
||||
return ptr;
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
@ -82,21 +71,21 @@ namespace toml
|
||||
[[nodiscard]] bool is_time() const noexcept override { return std::is_same_v<T, time>; }
|
||||
[[nodiscard]] bool is_date_time() const noexcept override { return std::is_same_v<T, date_time>; }
|
||||
|
||||
[[nodiscard]] value<string>* as_string() noexcept override { return as_value<string>(); }
|
||||
[[nodiscard]] value<int64_t>* as_integer() noexcept override { return as_value<int64_t>(); }
|
||||
[[nodiscard]] value<double>* as_floating_point() noexcept override { return as_value<double>(); }
|
||||
[[nodiscard]] value<bool>* as_boolean() noexcept override { return as_value<bool>(); }
|
||||
[[nodiscard]] value<date>* as_date() noexcept override { return as_value<date>(); }
|
||||
[[nodiscard]] value<time>* as_time() noexcept override { return as_value<time>(); }
|
||||
[[nodiscard]] value<date_time>* as_date_time() noexcept override { return as_value<date_time>(); }
|
||||
[[nodiscard]] value<string>* as_string() noexcept override { return as_value<string>(this); }
|
||||
[[nodiscard]] value<int64_t>* as_integer() noexcept override { return as_value<int64_t>(this); }
|
||||
[[nodiscard]] value<double>* as_floating_point() noexcept override { return as_value<double>(this); }
|
||||
[[nodiscard]] value<bool>* as_boolean() noexcept override { return as_value<bool>(this); }
|
||||
[[nodiscard]] value<date>* as_date() noexcept override { return as_value<date>(this); }
|
||||
[[nodiscard]] value<time>* as_time() noexcept override { return as_value<time>(this); }
|
||||
[[nodiscard]] value<date_time>* as_date_time() noexcept override { return as_value<date_time>(this); }
|
||||
|
||||
[[nodiscard]] const value<string>* as_string() const noexcept override { return as_value<string>(); }
|
||||
[[nodiscard]] const value<int64_t>* as_integer() const noexcept override { return as_value<int64_t>(); }
|
||||
[[nodiscard]] const value<double>* as_floating_point() const noexcept override { return as_value<double>(); }
|
||||
[[nodiscard]] const value<bool>* as_boolean() const noexcept override { return as_value<bool>(); }
|
||||
[[nodiscard]] const value<date>* as_date() const noexcept override { return as_value<date>(); }
|
||||
[[nodiscard]] const value<time>* as_time() const noexcept override { return as_value<time>(); }
|
||||
[[nodiscard]] const value<date_time>* as_date_time() const noexcept override { return as_value<date_time>(); }
|
||||
[[nodiscard]] const value<string>* as_string() const noexcept override { return as_value<string>(this); }
|
||||
[[nodiscard]] const value<int64_t>* as_integer() const noexcept override { return as_value<int64_t>(this); }
|
||||
[[nodiscard]] const value<double>* as_floating_point() const noexcept override { return as_value<double>(this); }
|
||||
[[nodiscard]] const value<bool>* as_boolean() const noexcept override { return as_value<bool>(this); }
|
||||
[[nodiscard]] const value<date>* as_date() const noexcept override { return as_value<date>(this); }
|
||||
[[nodiscard]] const value<time>* as_time() const noexcept override { return as_value<time>(this); }
|
||||
[[nodiscard]] const value<date_time>* as_date_time() const noexcept override { return as_value<date_time>(this); }
|
||||
|
||||
[[nodiscard]] T& get() & noexcept { return val_; }
|
||||
[[nodiscard]] T&& get() && noexcept { return std::move(val_); }
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
import sys
|
||||
import os
|
||||
import os.path
|
||||
import os.path as path
|
||||
import traceback
|
||||
import hashlib
|
||||
import subprocess
|
||||
@ -16,26 +16,30 @@ def is_tool(name):
|
||||
|
||||
|
||||
def get_script_folder():
|
||||
return os.path.dirname(os.path.realpath(sys.argv[0]))
|
||||
return path.dirname(path.realpath(sys.argv[0]))
|
||||
|
||||
|
||||
|
||||
def read_all_text_from_file(path):
|
||||
print("Reading {}".format(path))
|
||||
file = open(path, 'r')
|
||||
text = file.read()
|
||||
file.close()
|
||||
with open(path, 'r') as file:
|
||||
text = file.read()
|
||||
return text
|
||||
|
||||
|
||||
|
||||
def run_python_script(script_path, *args):
|
||||
subprocess.check_call(
|
||||
['py' if is_tool('py') else 'python3', script_path] + [arg for arg in args]
|
||||
)
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
hpp_path = os.path.join(get_script_folder(), '..', 'toml.hpp')
|
||||
hpp_path = path.join(get_script_folder(), '..', 'toml.hpp')
|
||||
hash1 = hashlib.sha1(read_all_text_from_file(hpp_path).encode('utf-8')).hexdigest()
|
||||
print("Hash 1: {}".format(hash1))
|
||||
subprocess.check_call(
|
||||
['py' if is_tool('py') else 'python3', 'generate_single_header.py']
|
||||
)
|
||||
run_python_script('generate_single_header.py')
|
||||
hash2 = hashlib.sha1(read_all_text_from_file(hpp_path).encode('utf-8')).hexdigest()
|
||||
print("Hash 2: {}".format(hash2))
|
||||
if (hash1 != hash2):
|
||||
|
783
python/generate_documentation.py
Normal file
783
python/generate_documentation.py
Normal file
@ -0,0 +1,783 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
import re
|
||||
import os
|
||||
import os.path as path
|
||||
import traceback
|
||||
import datetime
|
||||
import subprocess
|
||||
import random
|
||||
import concurrent.futures
|
||||
import shutil
|
||||
import html
|
||||
import fnmatch
|
||||
import bs4 as soup
|
||||
|
||||
|
||||
|
||||
_inlineNamespaces = [
|
||||
"toml::literals",
|
||||
]
|
||||
_inlineNamespaceExplainer = 'All members of this namespace are automatically members of the parent namespace. ' \
|
||||
+ 'It does not require an explicit \'using\' statement.'
|
||||
|
||||
|
||||
|
||||
def is_tool(name):
|
||||
return shutil.which(name) is not None
|
||||
|
||||
|
||||
def is_collection(val):
|
||||
if isinstance(val, (list, tuple, dict, set)):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
|
||||
def get_all_files(dir, all=None, any=None):
|
||||
files = [f for f in [path.join(dir, f) for f in os.listdir(dir)] if path.isfile(f)]
|
||||
if (files and all is not None):
|
||||
if (not is_collection(all)):
|
||||
all = (all,)
|
||||
all = [f for f in all if f is not None]
|
||||
for fil in all:
|
||||
files = fnmatch.filter(files, fil)
|
||||
|
||||
if (files and any is not None):
|
||||
if (not is_collection(any)):
|
||||
any = (any,)
|
||||
any = [f for f in any if f is not None]
|
||||
if any:
|
||||
results = set()
|
||||
for fil in any:
|
||||
results.update(fnmatch.filter(files, fil))
|
||||
files = [f for f in results]
|
||||
return files
|
||||
|
||||
|
||||
|
||||
def print_value(name, val):
|
||||
print('{}:\n {}'.format(name, val))
|
||||
|
||||
|
||||
|
||||
def error_message(err, prefix="Error"):
|
||||
if (isinstance(err, Exception) or (is_collection(err) and isinstance(err[0], Exception))):
|
||||
exc = err[0] if is_collection(err) else err
|
||||
trace = err[1] if (is_collection(err) and len(err) > 1) else traceback.format_exc(err)
|
||||
print('{}: [{}] {}\n{}'.format(
|
||||
prefix,
|
||||
type(err).__name__,
|
||||
str(err),
|
||||
traceback.format_exc(err)
|
||||
),
|
||||
file=sys.stderr
|
||||
)
|
||||
else:
|
||||
print("{}: {}".format(prefix, err), file=sys.stderr)
|
||||
|
||||
|
||||
|
||||
class HTMLDocument(object):
|
||||
|
||||
def __init__(self, path):
|
||||
self.__path = path
|
||||
with open(path, 'r', encoding='utf-8') as f:
|
||||
self.__doc = soup.BeautifulSoup(f, 'html5lib', from_encoding='utf-8')
|
||||
self.head = self.__doc.head
|
||||
self.body = self.__doc.body
|
||||
|
||||
def flush(self):
|
||||
with open(self.__path, 'w', encoding='utf-8', newline='\n') as f:
|
||||
f.write(str(self.__doc))
|
||||
|
||||
def new_tag(self, name, parent=None, string=None, class_=None, index=None, before=None, after=None, **kwargs):
|
||||
tag = self.__doc.new_tag(name, **kwargs)
|
||||
if (string is not None):
|
||||
if (tag.string is not None):
|
||||
tag.string.replace_with(string)
|
||||
else:
|
||||
tag.string = soup.NavigableString(string)
|
||||
if (class_ is not None):
|
||||
tag['class'] = class_
|
||||
if (before is not None):
|
||||
before.insert_before(tag)
|
||||
elif (after is not None):
|
||||
after.insert_after(tag)
|
||||
elif (parent is not None):
|
||||
if (index is None or index < 0):
|
||||
parent.append(tag)
|
||||
else:
|
||||
parent.insert(index, tag)
|
||||
|
||||
return tag
|
||||
|
||||
def find_all_from_sections(self, name=None, select=None, section=None, **kwargs):
|
||||
tags = []
|
||||
sectionArgs = { }
|
||||
if (section is not None):
|
||||
sectionArgs['id'] = section
|
||||
sections = self.body.main.article.div.div.div('section', recursive=False, **sectionArgs)
|
||||
for sect in sections:
|
||||
matches = sect(name, **kwargs) if name is not None else [ sect ]
|
||||
if (select is not None):
|
||||
newMatches = []
|
||||
for match in matches:
|
||||
newMatches += match.select(select)
|
||||
matches = newMatches
|
||||
tags += matches
|
||||
return tags
|
||||
|
||||
|
||||
|
||||
def html_find_parent(tag,name,cutoff=None):
|
||||
parent = tag.parent
|
||||
while (parent is not None):
|
||||
if (cutoff is not None and parent is cutoff):
|
||||
return None
|
||||
if (parent.name == name):
|
||||
return parent;
|
||||
parent = parent.parent
|
||||
return parent
|
||||
|
||||
|
||||
|
||||
def html_replace_tag(tag,str):
|
||||
doc = soup.BeautifulSoup(str, 'html5lib')
|
||||
newTags = None
|
||||
if (len(doc.body.contents) > 0):
|
||||
newTags = [f for f in doc.body.contents]
|
||||
newTags = [f.extract() for f in newTags]
|
||||
prev = tag
|
||||
for newTag in newTags:
|
||||
prev.insert_after(newTag)
|
||||
prev = newTag
|
||||
else:
|
||||
newTags = []
|
||||
|
||||
if (isinstance(tag, soup.NavigableString)):
|
||||
tag.extract()
|
||||
else:
|
||||
tag.decompose()
|
||||
return newTags
|
||||
|
||||
|
||||
|
||||
class RegexReplacer(object):
|
||||
|
||||
def __substitute(self, m):
|
||||
self.__result = True
|
||||
self.__groups = [str(m.group(0))]
|
||||
self.__groups += [str(g) for g in m.groups()]
|
||||
return self.__handler(m)
|
||||
|
||||
def __init__(self, expression, handler, value):
|
||||
self.__handler = handler
|
||||
self.__result = False
|
||||
self.__value = expression.sub(lambda m: self.__substitute(m), value)
|
||||
if (not self.__result):
|
||||
self.__groups = []
|
||||
|
||||
def __str__(self):
|
||||
return self.__value
|
||||
|
||||
def __bool__(self):
|
||||
return self.__result
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self.__groups[key]
|
||||
|
||||
def __len__(self):
|
||||
return len(self.__groups)
|
||||
|
||||
|
||||
|
||||
#=======================================================================================================================
|
||||
|
||||
|
||||
|
||||
# allows the injection of <div> and <span> tags using [div] and [span] proxies.
|
||||
class CustomTagsFix(object):
|
||||
__expression = re.compile(r"\[\s*(span|div)(.*?)\s*\](.*?)\[\s*/\s*\1\s*\]", re.I)
|
||||
__allowedNames = ['dd', 'p']
|
||||
|
||||
@classmethod
|
||||
def __substitute(cls, m):
|
||||
return '<{}{}>{}</{}>'.format(
|
||||
m.group(1),
|
||||
html.unescape(m.group(2)),
|
||||
m.group(3),
|
||||
m.group(1)
|
||||
)
|
||||
|
||||
def __call__(self, file, doc):
|
||||
changed = False
|
||||
for name in self.__allowedNames:
|
||||
tags = doc.find_all_from_sections(name)
|
||||
for tag in tags:
|
||||
if (len(tag.contents) == 0 or html_find_parent(tag, 'a', doc.body) is not None):
|
||||
continue
|
||||
replacer = RegexReplacer(self.__expression, self.__substitute, str(tag))
|
||||
if (replacer):
|
||||
changed = True
|
||||
html_replace_tag(tag, str(replacer))
|
||||
return changed
|
||||
|
||||
|
||||
|
||||
#=======================================================================================================================
|
||||
|
||||
|
||||
|
||||
# adds custom links to the navbar.
|
||||
class NavBarFix(object):
|
||||
|
||||
__links = [
|
||||
('Report an issue', 'https://github.com/marzer/tomlplusplus/issues'),
|
||||
('Github', 'https://github.com/marzer/tomlplusplus/')
|
||||
]
|
||||
|
||||
def __call__(self, file, doc):
|
||||
list = doc.body.header.nav.div.div.select_one('#m-navbar-collapse').div.ol
|
||||
if (list.select_one('.tpp-injected') is None):
|
||||
for label, url in self.__links:
|
||||
doc.new_tag('a',
|
||||
parent=doc.new_tag('li', parent=list, class_='tpp-injected tpp-external-navbar', index=0),
|
||||
string=label,
|
||||
href=url,
|
||||
target='_blank'
|
||||
)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
|
||||
#=======================================================================================================================
|
||||
|
||||
|
||||
|
||||
# changes any links to index.html to link to namespaces.html instead (index.html is blank/unused)
|
||||
class IndexHrefFix(object):
|
||||
|
||||
def __call__(self, file, doc):
|
||||
links = doc.body('a', href='index.html')
|
||||
if (len(links) > 0):
|
||||
for link in links:
|
||||
link['href'] = 'namespaces.html'
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
|
||||
#=======================================================================================================================
|
||||
|
||||
|
||||
|
||||
# base type for modifier parsing fixers.
|
||||
class ModifiersFixBase(object):
|
||||
_modifierRegex = "defaulted|noexcept|constexpr|(?:pure )?virtual|protected|__(?:(?:vector|std|fast)call|cdecl)"
|
||||
_modifierClasses = {
|
||||
"defaulted" : "m-info",
|
||||
"noexcept" : "m-success",
|
||||
"constexpr" : "m-primary",
|
||||
"pure virtual" : "m-warning",
|
||||
"virtual" : "m-warning",
|
||||
"protected" : "m-warning",
|
||||
"__vectorcall" : "m-info",
|
||||
"__stdcall" : "m-info",
|
||||
"__fastcall" : "m-info",
|
||||
"__cdecl" : "m-info"
|
||||
}
|
||||
|
||||
|
||||
|
||||
#=======================================================================================================================
|
||||
|
||||
|
||||
|
||||
# fixes improperly-parsed modifiers on function signatures in the various 'detail view' sections.
|
||||
class ModifiersFix1(ModifiersFixBase):
|
||||
|
||||
__expression = re.compile(r'(\s+)({})(\s+)'.format(ModifiersFixBase._modifierRegex))
|
||||
__sections = ['pub-static-methods', 'pub-methods', 'friends', 'func-members']
|
||||
|
||||
@classmethod
|
||||
def __substitute(cls, m):
|
||||
return '{}<span class="tpp-injected m-label m-flat {}">{}</span>{}'.format(
|
||||
m.group(1),
|
||||
cls._modifierClasses[m.group(2)],
|
||||
m.group(2),
|
||||
m.group(3)
|
||||
)
|
||||
|
||||
def __call__(self, file, doc):
|
||||
changed = False
|
||||
for sect in self.__sections:
|
||||
tags = doc.find_all_from_sections('dt', select='span.m-doc-wrap', section=sect)
|
||||
for tag in tags:
|
||||
replacer = RegexReplacer(self.__expression, self.__substitute, str(tag))
|
||||
if (replacer):
|
||||
changed = True
|
||||
html_replace_tag(tag, str(replacer))
|
||||
return changed
|
||||
|
||||
|
||||
|
||||
#=======================================================================================================================
|
||||
|
||||
|
||||
|
||||
# fixes improperly-parsed modifiers on function signatures in the 'Function documentation' section.
|
||||
class ModifiersFix2(ModifiersFixBase):
|
||||
|
||||
__expression = re.compile(r'\s+({})\s+'.format(ModifiersFixBase._modifierRegex))
|
||||
|
||||
@classmethod
|
||||
def __substitute(cls, m, matches):
|
||||
matches.append(m.group(1))
|
||||
return ' '
|
||||
|
||||
def __call__(self, file, doc):
|
||||
changed = False
|
||||
sections = doc.find_all_from_sections(section=False) # all sections without an id
|
||||
section = None
|
||||
for s in sections:
|
||||
if (str(s.h2.string) == 'Function documentation'):
|
||||
section = s
|
||||
break
|
||||
if (section is not None):
|
||||
funcs = section(id=True)
|
||||
funcs = [f.find('h3') for f in funcs]
|
||||
for f in funcs:
|
||||
bumper = f.select_one('span.m-doc-wrap-bumper')
|
||||
end = f.select_one('span.m-doc-wrap').contents
|
||||
end = end[len(end)-1]
|
||||
matches = []
|
||||
bumperContent = self.__expression.sub(lambda m: self.__substitute(m, matches), str(bumper))
|
||||
if (matches):
|
||||
changed = True
|
||||
bumper = html_replace_tag(bumper, bumperContent)
|
||||
lastInserted = end.find('span')
|
||||
for match in matches:
|
||||
lastInserted = doc.new_tag('span',
|
||||
parent=end,
|
||||
string=match,
|
||||
class_='tpp-injected m-label {}'.format(self._modifierClasses[match]),
|
||||
before=lastInserted
|
||||
)
|
||||
lastInserted.insert_after(' ')
|
||||
return changed
|
||||
|
||||
|
||||
|
||||
#=======================================================================================================================
|
||||
|
||||
|
||||
|
||||
# base type for applying inline namespace annotations.
|
||||
class InlineNamespaceFixBase(object):
|
||||
_namespaceFiles = ['namespace{}.html'.format(ns.lower().replace('::','_1_1')) for ns in _inlineNamespaces]
|
||||
|
||||
|
||||
|
||||
#=======================================================================================================================
|
||||
|
||||
|
||||
|
||||
# adds inline namespace annotations in class and namespace trees.
|
||||
class InlineNamespaceFix1(InlineNamespaceFixBase):
|
||||
__allowedFiles = ['annotated.html', 'namespaces.html']
|
||||
|
||||
def __call__(self, file, doc):
|
||||
global _inlineNamespaceExplainer
|
||||
changed = False
|
||||
if (file in self.__allowedFiles):
|
||||
anchors = []
|
||||
for f in self._namespaceFiles:
|
||||
anchors += doc.body.find_all("a", href=f)
|
||||
for anchor in anchors:
|
||||
next = anchor.next_sibling
|
||||
while (next is not None and isinstance(next, soup.NavigableString)):
|
||||
next = next.next_sibling
|
||||
if (next is not None and next.get('class') is not None and 'tpp-injected' in next.get('class')):
|
||||
continue
|
||||
doc.new_tag('span',
|
||||
after=anchor,
|
||||
string='inline',
|
||||
title=_inlineNamespaceExplainer,
|
||||
class_='m-label m-info m-flat tpp-injected tpp-inline-namespace'
|
||||
)
|
||||
anchor.insert_after(' ')
|
||||
changed = True
|
||||
return changed
|
||||
|
||||
|
||||
|
||||
#=======================================================================================================================
|
||||
|
||||
|
||||
|
||||
# adds inline namespace annotations to the h1 element of inline namespace pages.
|
||||
class InlineNamespaceFix2(InlineNamespaceFixBase):
|
||||
|
||||
def __call__(self, file, doc):
|
||||
global _inlineNamespaceExplainer
|
||||
changed = False
|
||||
if (file in self._namespaceFiles):
|
||||
h1 = doc.body.find('h1')
|
||||
tag = h1.select_one('span.tpp-injected')
|
||||
if (tag is None):
|
||||
tag = doc.new_tag('span',
|
||||
parent=h1,
|
||||
string='inline',
|
||||
title=_inlineNamespaceExplainer,
|
||||
class_='m-label m-info tpp-injected tpp-inline-namespace'
|
||||
)
|
||||
tag.insert_before(' ')
|
||||
changed = True
|
||||
return changed
|
||||
|
||||
|
||||
|
||||
#=======================================================================================================================
|
||||
|
||||
|
||||
|
||||
# adds inline namespace annotations to sections with id=namespaces.
|
||||
class InlineNamespaceFix3(InlineNamespaceFixBase):
|
||||
|
||||
def __call__(self, file, doc):
|
||||
global _inlineNamespaceExplainer
|
||||
anchors = doc.find_all_from_sections('a', section='namespaces')
|
||||
changed = False
|
||||
for anchor in anchors:
|
||||
if (anchor.get('href') not in self._namespaceFiles):
|
||||
continue
|
||||
next = anchor.next_sibling
|
||||
while (next is not None and isinstance(next, soup.NavigableString)):
|
||||
next = next.next_sibling
|
||||
if (next is not None and next.get('class') is not None and 'tpp-injected' in next.get('class')):
|
||||
continue
|
||||
doc.new_tag('span',
|
||||
after=anchor,
|
||||
string='inline',
|
||||
title=_inlineNamespaceExplainer,
|
||||
class_='m-label m-info m-flat tpp-injected tpp-inline-namespace'
|
||||
)
|
||||
anchor.insert_after(' ')
|
||||
changed = True
|
||||
return changed
|
||||
|
||||
|
||||
|
||||
#=======================================================================================================================
|
||||
|
||||
|
||||
|
||||
# adds a custom footer to the main index pages.
|
||||
class FooterFix(object):
|
||||
__replacement = '<div id="tpp-custom-footer tpp-injected">Documentation generated {} using ' \
|
||||
+ '<a href="https://mcss.mosra.cz/">m.css</a></div>'.format(
|
||||
datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC")
|
||||
)
|
||||
|
||||
def __call__(self, file, doc):
|
||||
footer = doc.body.find(id='tpp-custom-footer')
|
||||
if (footer is None):
|
||||
return False
|
||||
html_replace_tag(footer, self.__replacement)
|
||||
return True
|
||||
|
||||
|
||||
|
||||
#=======================================================================================================================
|
||||
|
||||
|
||||
|
||||
# adds links to external sources where appropriate
|
||||
class ExtDocLinksFix(object):
|
||||
__types = [
|
||||
(r'(?:std::)?size_t', 'https://en.cppreference.com/w/cpp/types/size_t'),
|
||||
(r'(?:std::)?u?int(?:8|16|32|64)_ts?', 'https://en.cppreference.com/w/cpp/types/integer'),
|
||||
(r'std::pairs?', 'https://en.cppreference.com/w/cpp/utility/pair'),
|
||||
(r'std::bytes?', 'https://en.cppreference.com/w/cpp/types/byte'),
|
||||
(r'std::optionals?', 'https://en.cppreference.com/w/cpp/utility/optional'),
|
||||
(r'std::tuples?', 'https://en.cppreference.com/w/cpp/utility/tuple'),
|
||||
(r'std::integral_constants?', 'https://en.cppreference.com/w/cpp/types/integral_constant'),
|
||||
(r'std::char_traits', 'https://en.cppreference.com/w/cpp/string/char_traits'),
|
||||
(r'std::allocators?', 'https://en.cppreference.com/w/cpp/memory/allocator'),
|
||||
(r'std::enable_if(?:_t)?', 'https://en.cppreference.com/w/cpp/types/enable_if'),
|
||||
(r'std::conditional(?:_t)?', 'https://en.cppreference.com/w/cpp/types/conditional'),
|
||||
(r'std::unordered_maps?', 'https://en.cppreference.com/w/cpp/container/unordered_map'),
|
||||
(r'std::unordered_sets?', 'https://en.cppreference.com/w/cpp/container/unordered_set'),
|
||||
(r'std::maps?', 'https://en.cppreference.com/w/cpp/container/map'),
|
||||
(r'std::sets?', 'https://en.cppreference.com/w/cpp/container/set'),
|
||||
(r'std::vectors?', 'https://en.cppreference.com/w/cpp/container/vector'),
|
||||
(r'std::arrays?', 'https://en.cppreference.com/w/cpp/container/array'),
|
||||
(r'std::chrono::durations?', 'https://en.cppreference.com/w/cpp/chrono/duration'),
|
||||
(
|
||||
r'std::atomic(?:_(?:'
|
||||
+ r'bool|[su]?char(?:8_t|16_t|32_t)?|u?short'
|
||||
+ r'|u?int(?:8_t|16_t|32_t|64_t)?|u?l?long'
|
||||
+ r'))?',
|
||||
'https://en.cppreference.com/w/cpp/atomic/atomic'
|
||||
),
|
||||
(r'std::unique_ptrs?', 'https://en.cppreference.com/w/cpp/memory/unique_ptr'),
|
||||
(r'std::shared_ptrs?', 'https://en.cppreference.com/w/cpp/memory/shared_ptr'),
|
||||
(r'(?:std::)?nullptr_t', 'https://en.cppreference.com/w/cpp/types/nullptr_t'),
|
||||
(r'std::reverse_iterator', 'https://en.cppreference.com/w/cpp/iterator/reverse_iterator'),
|
||||
(r'std::(?:basic_|w)?istreams?', 'https://en.cppreference.com/w/cpp/io/basic_istream'),
|
||||
(r'std::(?:basic_|w)?ostreams?', 'https://en.cppreference.com/w/cpp/io/basic_ostream'),
|
||||
(r'std::(?:basic_|w)?iostreams?', 'https://en.cppreference.com/w/cpp/io/basic_iostream'),
|
||||
(r'std::(?:basic_|w)?ifstreams?', 'https://en.cppreference.com/w/cpp/io/basic_ifstream'),
|
||||
(r'std::(?:basic_|w)?ofstreams?', 'https://en.cppreference.com/w/cpp/io/basic_ofstream'),
|
||||
(r'std::(?:basic_|w)?fstreams?', 'https://en.cppreference.com/w/cpp/io/basic_fstream'),
|
||||
(r'std::(?:basic_|w)?istringstreams?', 'https://en.cppreference.com/w/cpp/io/basic_istringstream'),
|
||||
(r'std::(?:basic_|w)?ostringstreams?', 'https://en.cppreference.com/w/cpp/io/basic_ostringstream'),
|
||||
(r'std::(?:basic_|w)?stringstreams?', 'https://en.cppreference.com/w/cpp/io/basic_stringstream'),
|
||||
(r'std::(?:basic_|w|u8)?string_views?', 'https://en.cppreference.com/w/cpp/string/basic_string_view'),
|
||||
(r'std::(?:basic_|w|u8)?strings?', 'https://en.cppreference.com/w/cpp/string/basic_string'),
|
||||
(r'char(?:8|16|32)_ts?', 'https://en.cppreference.com/w/cpp/language/types'),
|
||||
(r'std::is_(?:nothrow_)?convertible(?:_v)?', 'https://en.cppreference.com/w/cpp/types/is_convertible'),
|
||||
(r'std::is_same(?:_v)?', 'https://en.cppreference.com/w/cpp/types/is_same'),
|
||||
(r'std::is_base_of(?:_v)?', 'https://en.cppreference.com/w/cpp/types/is_base_of'),
|
||||
(r'std::is_enum(?:_v)?', 'https://en.cppreference.com/w/cpp/types/is_enum'),
|
||||
(r'std::is_floating_point(?:_v)?', 'https://en.cppreference.com/w/cpp/types/is_floating_point'),
|
||||
(r'std::is_integral(?:_v)?', 'https://en.cppreference.com/w/cpp/types/is_integral'),
|
||||
(r'std::is_pointer(?:_v)?', 'https://en.cppreference.com/w/cpp/types/is_pointer'),
|
||||
(r'std::is_reference(?:_v)?', 'https://en.cppreference.com/w/cpp/types/is_reference'),
|
||||
(r'std::is_signed(?:_v)?', 'https://en.cppreference.com/w/cpp/types/is_signed'),
|
||||
(r'std::is_unsigned(?:_v)?', 'https://en.cppreference.com/w/cpp/types/is_unsigned'),
|
||||
(r'std::is_void(?:_v)?', 'https://en.cppreference.com/w/cpp/types/is_void'),
|
||||
(r'std::is_(?:nothrow_)?invocable(?:_r)?', 'https://en.cppreference.com/w/cpp/types/is_invocable'),
|
||||
(r'std::add_[lr]value_reference(?:_t)?', 'https://en.cppreference.com/w/cpp/types/add_reference'),
|
||||
(r'std::remove_reference(?:_t)?', 'https://en.cppreference.com/w/cpp/types/remove_reference'),
|
||||
(r'std::remove_cv(?:_t)?', 'https://en.cppreference.com/w/cpp/types/remove_cv'),
|
||||
(
|
||||
r'(?:L?P)?(?:'
|
||||
+ r'D?WORD(?:32|64|_PTR)?|HANDLE|HMODULE|BOOL(?:EAN)?'
|
||||
+ r'|U?SHORT|U?LONG|U?INT(?:8|16|32|64)?'
|
||||
+ r'|BYTE|VOID|C[WT]?STR'
|
||||
+ r')',
|
||||
'https://docs.microsoft.com/en-us/windows/desktop/winprog/windows-data-types'
|
||||
),
|
||||
(
|
||||
r'(?:__INTELLISENSE__|_MSC_FULL_VER|_MSC_VER|_MSVC_LANG|_WIN32|_WIN64)',
|
||||
'https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=vs-2019'
|
||||
)
|
||||
]
|
||||
__allowedNames = ['dd', 'p', 'dt', 'h3', 'td']
|
||||
|
||||
def __init__(self):
|
||||
self.__expressions = []
|
||||
for type, uri in self.__types:
|
||||
self.__expressions.append((re.compile(type+'(?!</a>)'), uri))
|
||||
|
||||
@classmethod
|
||||
def __substitute(cls, m, uri):
|
||||
return r'<a href="{}" class="m-doc tpp-injected tpp-external" target="_blank">{}</a>'.format(
|
||||
uri,
|
||||
m.group(0)
|
||||
)
|
||||
|
||||
def __process_tag(self, tag):
|
||||
for expr, uri in self.__expressions:
|
||||
for descendant in tag.descendants:
|
||||
if (not isinstance(descendant, soup.NavigableString) or html_find_parent(descendant, 'a', tag) is not None):
|
||||
continue
|
||||
replacer = RegexReplacer(expr, lambda m: self.__substitute(m, uri), html.escape(str(descendant), quote=False))
|
||||
if (replacer):
|
||||
html_replace_tag(descendant, str(replacer))
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def __call__(self, file, doc):
|
||||
changed = False
|
||||
for name in self.__allowedNames:
|
||||
for tag in doc.body.main.article.div.div(name):
|
||||
if (len(tag.contents) == 0 or html_find_parent(tag, 'a', doc.body) is not None):
|
||||
continue
|
||||
while (self.__process_tag(tag)):
|
||||
changed = True
|
||||
continue
|
||||
return changed
|
||||
|
||||
|
||||
|
||||
|
||||
#=======================================================================================================================
|
||||
|
||||
|
||||
|
||||
# collapses std::enable_if in template headers to reduce verbosity.
|
||||
class EnableIfFix(object):
|
||||
|
||||
__expression = re.compile(
|
||||
# group 1: everything left of and including "std::enable_if<" (or it's aliases)
|
||||
r'^(.+?(?:template<.+>\s*)?template\s*<.+?(?:typename|class)\s*(?:=\s*)?(?:<a.+?>\s*)?(?:std::enable_if(?:_t)?)\s*(?:</a>\s*)?<)\s*'
|
||||
# group 2: the SFINAE parameters we actually want from inside the std::enable_if
|
||||
+ r'(.+?)'
|
||||
# group 3: the rest of the template declaration on the right
|
||||
+ r'\s*(>\s*>.+?)$',
|
||||
re.S
|
||||
)
|
||||
|
||||
__spacingFix1 = re.compile(r'(_v|>::value)(&&|\|\|)')
|
||||
|
||||
@classmethod
|
||||
def __substitute(cls, m):
|
||||
return r'{}<span class="tpp-injected tpp-enable-if"><a href="#" onclick="ToggleEnableIf(this);return false;">...</a><span>{}</span></span>{}'.format(
|
||||
m.group(1),
|
||||
m.group(2),
|
||||
m.group(3)
|
||||
)
|
||||
|
||||
def __call__(self, file, doc):
|
||||
changed = False
|
||||
for template in doc.body('div', class_='m-doc-template'):
|
||||
replacer = RegexReplacer(self.__expression, lambda m: self.__substitute(m), str(template))
|
||||
if replacer:
|
||||
injected = html_replace_tag(template, str(replacer))[0].select_one(".tpp-enable-if")
|
||||
anchor = injected.a
|
||||
content = injected.span
|
||||
tweaks = []
|
||||
for tag in content.descendants:
|
||||
if (isinstance(tag, soup.NavigableString)):
|
||||
val = str(tag)
|
||||
replacer = RegexReplacer(self.__spacingFix1, lambda m: '{} {}'.format(m[1], m[2]), val)
|
||||
if replacer:
|
||||
tweaks.append((tag,str(replacer)))
|
||||
for tag, sub in tweaks:
|
||||
tag.replace_with(sub)
|
||||
anchor['title'] = content.get_text().strip().replace('"', '"')
|
||||
changed = True
|
||||
return changed
|
||||
|
||||
|
||||
|
||||
#=======================================================================================================================
|
||||
|
||||
|
||||
|
||||
_threadError = None
|
||||
|
||||
|
||||
|
||||
def postprocess_file(dir, file, fixes):
|
||||
global _threadError
|
||||
if (_threadError is not None):
|
||||
return False
|
||||
print("Post-processing {}".format(file))
|
||||
doc = HTMLDocument(path.join(dir, file))
|
||||
file = file.lower()
|
||||
changed = False
|
||||
for fix in fixes:
|
||||
if (fix(file, doc)):
|
||||
changed = True
|
||||
if (changed):
|
||||
doc.flush()
|
||||
return changed
|
||||
|
||||
|
||||
|
||||
def delete_directory(dir_path):
|
||||
if (path.exists(dir_path)):
|
||||
print('Deleting {}'.format(dir_path))
|
||||
shutil.rmtree(dir_path)
|
||||
|
||||
|
||||
|
||||
def get_script_folder():
|
||||
return path.dirname(path.realpath(sys.argv[0]))
|
||||
|
||||
|
||||
|
||||
def run_python_script(script_path, *args):
|
||||
subprocess.check_call(
|
||||
['py' if is_tool('py') else 'python3', script_path] + [arg for arg in args]
|
||||
)
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
global _threadError
|
||||
|
||||
num_threads = os.cpu_count() * 2
|
||||
root_dir = path.join(get_script_folder(), '..')
|
||||
docs_dir = path.join(root_dir, 'docs')
|
||||
xml_dir = path.join(docs_dir, 'xml')
|
||||
html_dir = path.join(docs_dir, 'html')
|
||||
mcss_dir = path.join(root_dir, 'extern', 'm.css')
|
||||
doxygen = path.join(mcss_dir, 'documentation', 'doxygen.py')
|
||||
|
||||
print_value('doc', docs_dir)
|
||||
print_value('xml', xml_dir)
|
||||
print_value('html', html_dir)
|
||||
print_value('m.css', mcss_dir)
|
||||
print_value('doxygen', doxygen)
|
||||
|
||||
# delete any previously generated html and xml
|
||||
delete_directory(xml_dir)
|
||||
delete_directory(html_dir)
|
||||
|
||||
# run doxygen (via m.css)
|
||||
run_python_script(doxygen, path.join(docs_dir, 'Doxyfile-mcss'))
|
||||
|
||||
# clean up xml and tmp files
|
||||
delete_directory(xml_dir)
|
||||
#for file in get_all_files(cwd, '*.tmp'):
|
||||
# try:
|
||||
# print('Deleting {}'.format(file))
|
||||
# os.remove(file)
|
||||
# except Exception as e:
|
||||
# fatal_error(e)
|
||||
|
||||
# post-process html files
|
||||
fixes = [
|
||||
CustomTagsFix()
|
||||
, NavBarFix()
|
||||
, IndexHrefFix()
|
||||
, ModifiersFix1()
|
||||
, ModifiersFix2()
|
||||
, InlineNamespaceFix1()
|
||||
, InlineNamespaceFix2()
|
||||
, InlineNamespaceFix3()
|
||||
, FooterFix()
|
||||
, ExtDocLinksFix()
|
||||
, EnableIfFix()
|
||||
]
|
||||
files = [path.split(f) for f in get_all_files(html_dir, any=('*.html', '*.htm'))]
|
||||
print_value("Files", files)
|
||||
if files:
|
||||
with concurrent.futures.ThreadPoolExecutor(max_workers=min(len(files), num_threads)) as executor:
|
||||
jobs = { executor.submit(postprocess_file, dir, file, fixes) : file for dir, file in files }
|
||||
for job in concurrent.futures.as_completed(jobs):
|
||||
file = jobs[job]
|
||||
try:
|
||||
print('Finished processing {}.'.format(file))
|
||||
except Exception as e:
|
||||
_threadError = (e, traceback.format_exc(e))
|
||||
executor.shutdown(False)
|
||||
break
|
||||
if (_threadError is not None):
|
||||
error_message(_threadError, prefix="Fatal error")
|
||||
sys.exit(-1)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
main()
|
||||
except Exception as err:
|
||||
print(
|
||||
'Fatal error: [{}] {}'.format(
|
||||
type(err).__name__,
|
||||
str(err)
|
||||
),
|
||||
file=sys.stderr
|
||||
)
|
||||
traceback.print_exc(file=sys.stderr)
|
||||
sys.exit(1)
|
||||
sys.exit()
|
@ -3,22 +3,21 @@
|
||||
import sys
|
||||
import re
|
||||
import os
|
||||
import os.path
|
||||
import os.path as path
|
||||
import traceback
|
||||
|
||||
|
||||
|
||||
|
||||
def get_script_folder():
|
||||
return os.path.dirname(os.path.realpath(sys.argv[0]))
|
||||
return path.dirname(path.realpath(sys.argv[0]))
|
||||
|
||||
|
||||
|
||||
def read_all_text_from_file(path):
|
||||
print("Reading {}".format(path))
|
||||
file = open(path, 'r')
|
||||
text = file.read()
|
||||
file.close()
|
||||
with open(path, 'r') as file:
|
||||
text = file.read()
|
||||
return text
|
||||
|
||||
|
||||
@ -48,7 +47,7 @@ class Preprocessor:
|
||||
return ''
|
||||
|
||||
self.processed_includes.append(incl)
|
||||
text = read_all_text_from_file(os.path.join(get_script_folder(), '..', 'include', 'toml++', incl))
|
||||
text = read_all_text_from_file(path.join(get_script_folder(), '..', 'include', 'toml++', incl))
|
||||
text = re.sub(r'^\s*#\s*pragma\s+once\s*$', '', text, 0, re.I | re.M)
|
||||
text = re.sub(r'^\s*//\s*clang-format\s+(?:off|on)\s*$', '', text, 0, re.I | re.M)
|
||||
|
||||
@ -58,7 +57,7 @@ class Preprocessor:
|
||||
|
||||
if (self.current_level == 1):
|
||||
header_text = '↓ ' + raw_incl
|
||||
lpad = 23 + ((25 * (self.header_indent % 4)) - int((len(header_text) + 4) / 2))
|
||||
lpad = 28 + ((25 * (self.header_indent % 4)) - int((len(header_text) + 4) / 2))
|
||||
self.header_indent += 1
|
||||
return '\n{}\n#pragma region {}\n\n{}\n\n#pragma endregion {}\n{}'.format(
|
||||
make_divider(header_text, lpad), '', text, '', make_divider('↑ ' + raw_incl, lpad))
|
||||
@ -78,7 +77,8 @@ def main():
|
||||
# preprocess header(s)
|
||||
source_text = Preprocessor()('toml.h')
|
||||
source_text = re.sub('\r\n', '\n', source_text, 0, re.I | re.M) # convert windows newlines
|
||||
source_text = re.sub('^[ \t]*//[/#!].+?$', '', source_text, 0, re.I | re.M) # remove 'magic' comments
|
||||
source_text = re.sub('(?:\n[ \t]*//[/#!<]+[^\n]*)+\n', '\n', source_text, 0, re.I | re.M) # remove 'magic' comment blocks
|
||||
source_text = re.sub('^[ \t]*//[/#!<]+.+?$', '', source_text, 0, re.I | re.M) # remove 'magic' comments
|
||||
source_text = re.sub('\n([ \t]*\n[ \t]*)+\n', '\n\n', source_text, 0, re.I | re.M) # remove double newlines
|
||||
source_text = re.sub('([^ \t])[ \t]+\n', '\\1\n', source_text, 0, re.I | re.M) # remove trailing whitespace
|
||||
source_text = source_text.strip()
|
||||
@ -111,39 +111,38 @@ that contributed to this header can be found at the beginnings and ends of the c
|
||||
TOML language specification:
|
||||
Latest: https://github.com/toml-lang/toml/blob/master/README.md
|
||||
v0.5.0: https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.5.0.md''')
|
||||
preamble.append(read_all_text_from_file(os.path.join(get_script_folder(), '..', 'LICENSE')))
|
||||
preamble.append(read_all_text_from_file(path.join(get_script_folder(), '..', 'LICENSE')))
|
||||
|
||||
# write the output file
|
||||
output_file_path = os.path.join(get_script_folder(), '..', 'toml.hpp')
|
||||
output_file_path = path.join(get_script_folder(), '..', 'toml.hpp')
|
||||
print("Writing to {}".format(output_file_path))
|
||||
output_file = open(output_file_path,'w', encoding='utf-8', newline='\n')
|
||||
if (len(preamble) > 0):
|
||||
print(make_divider(), file=output_file)
|
||||
for pre in preamble:
|
||||
print('//', file=output_file)
|
||||
for line in pre.strip().splitlines():
|
||||
print('//', file=output_file, end = '')
|
||||
if (len(line) > 0):
|
||||
print(' ', file=output_file, end = '')
|
||||
print(line, file=output_file)
|
||||
else:
|
||||
print('\n', file=output_file, end = '')
|
||||
print('//', file=output_file)
|
||||
print(make_divider(), file=output_file)
|
||||
print('''// clang-format off
|
||||
with open(output_file_path,'w', encoding='utf-8', newline='\n') as output_file:
|
||||
if (len(preamble) > 0):
|
||||
print(make_divider(), file=output_file)
|
||||
for pre in preamble:
|
||||
print('//', file=output_file)
|
||||
for line in pre.strip().splitlines():
|
||||
print('//', file=output_file, end = '')
|
||||
if (len(line) > 0):
|
||||
print(' ', file=output_file, end = '')
|
||||
print(line, file=output_file)
|
||||
else:
|
||||
print('\n', file=output_file, end = '')
|
||||
print('//', file=output_file)
|
||||
print(make_divider(), file=output_file)
|
||||
print('''// clang-format off
|
||||
#pragma once
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
|
||||
#endif
|
||||
''', file=output_file)
|
||||
print(source_text, file=output_file)
|
||||
print('''
|
||||
print(source_text, file=output_file)
|
||||
print('''
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
// clang-format on''', file=output_file)
|
||||
output_file.close()
|
||||
|
||||
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
import sys
|
||||
import re
|
||||
import os
|
||||
import os.path
|
||||
import os.path as path
|
||||
import math
|
||||
import requests
|
||||
import traceback
|
||||
@ -434,7 +434,7 @@ def emit_function(name, categories, file, codepoints):
|
||||
|
||||
# write the function
|
||||
|
||||
print('\n\t/// \\brief Returns true if a codepoint belongs to any of these categories: {}'.format(', '.join(categories)), file=file)
|
||||
print('\n\t//# Returns true if a codepoint belongs to any of these categories: {}'.format(', '.join(categories)), file=file)
|
||||
print('\t[[nodiscard]]', file=file)
|
||||
print('\tconstexpr bool {}(char32_t codepoint) noexcept\n\t{{'.format(name), file=file)
|
||||
root_chunk.print(file)
|
||||
@ -447,7 +447,7 @@ def emit_function(name, categories, file, codepoints):
|
||||
|
||||
|
||||
def get_script_folder():
|
||||
return os.path.dirname(os.path.realpath(sys.argv[0]))
|
||||
return path.dirname(path.realpath(sys.argv[0]))
|
||||
|
||||
|
||||
|
||||
@ -455,22 +455,21 @@ def main():
|
||||
|
||||
# get unicode character database
|
||||
codepoint_list = ''
|
||||
codepoint_file_path = os.path.join(get_script_folder(), 'UnicodeData.txt')
|
||||
if (not os.path.exists(codepoint_file_path)):
|
||||
codepoint_file_path = path.join(get_script_folder(), 'UnicodeData.txt')
|
||||
if (not path.exists(codepoint_file_path)):
|
||||
print("Couldn't find unicode database file, will download")
|
||||
response = requests.get(
|
||||
'https://www.unicode.org/Public/UCD/latest/ucd/UnicodeData.txt',
|
||||
timeout=1
|
||||
)
|
||||
codepoint_list = response.text
|
||||
codepoint_file = open(codepoint_file_path, 'w', newline='\n')
|
||||
print(codepoint_list, end='', file=codepoint_file)
|
||||
codepoint_file.close()
|
||||
with open(codepoint_file_path, 'w', encoding='utf-8', newline='\n') as codepoint_file:
|
||||
print(codepoint_list, end='', file=codepoint_file)
|
||||
else:
|
||||
print("Reading unicode database file into memory")
|
||||
codepoint_file = open(codepoint_file_path, 'r')
|
||||
codepoint_list = codepoint_file.read()
|
||||
codepoint_file.close()
|
||||
with open(codepoint_file_path, 'r') as codepoint_file:
|
||||
codepoint_list = codepoint_file.read()
|
||||
|
||||
|
||||
# parse the database file into codepoints
|
||||
re_codepoint = re.compile(r'^([0-9a-fA-F]+);(.+?);([a-zA-Z]+);')
|
||||
@ -498,19 +497,18 @@ def main():
|
||||
codepoints.sort(key=lambda r:r[0])
|
||||
|
||||
# write the output file
|
||||
output_file_path = os.path.join(get_script_folder(), '..', 'include', 'toml++', 'toml_utf8_generated.h')
|
||||
output_file_path = path.join(get_script_folder(), '..', 'include', 'toml++', 'toml_utf8_generated.h')
|
||||
print("Writing to {}".format(output_file_path))
|
||||
output_file = open(output_file_path, 'w', newline='\n')
|
||||
print('//# this file was generated by generate_unicode_functions.py', file=output_file)
|
||||
print('#pragma once', file=output_file)
|
||||
print('#include "toml_common.h"', file=output_file)
|
||||
print('\n#define TOML_ASSUME_CODEPOINT_BETWEEN(first, last)\t\\\n\tTOML_ASSUME(codepoint >= first);\t\t\t\t\\\n\tTOML_ASSUME(codepoint <= last)', file=output_file)
|
||||
print('\nnamespace toml::impl\n{', file=output_file, end='')
|
||||
emit_function('is_unicode_letter', ('Ll', 'Lm', 'Lo', 'Lt', 'Lu'), output_file, codepoints)
|
||||
emit_function('is_unicode_number', ('Nd', 'Nl'), output_file, codepoints)
|
||||
emit_function('is_unicode_combining_mark', ('Mn', 'Mc'), output_file, codepoints)
|
||||
print('}\n\n#undef TOML_ASSUME_CODEPOINT_BETWEEN', file=output_file)
|
||||
output_file.close()
|
||||
with open(output_file_path, 'w', encoding='utf-8', newline='\n') as output_file:
|
||||
print('//# this file was generated by generate_unicode_functions.py', file=output_file)
|
||||
print('#pragma once', file=output_file)
|
||||
print('#include "toml_common.h"', file=output_file)
|
||||
print('\n#define TOML_ASSUME_CODEPOINT_BETWEEN(first, last)\t\\\n\tTOML_ASSUME(codepoint >= first);\t\t\t\t\\\n\tTOML_ASSUME(codepoint <= last)', file=output_file)
|
||||
print('\nnamespace toml::impl\n{', file=output_file, end='')
|
||||
emit_function('is_unicode_letter', ('Ll', 'Lm', 'Lo', 'Lt', 'Lu'), output_file, codepoints)
|
||||
emit_function('is_unicode_number', ('Nd', 'Nl'), output_file, codepoints)
|
||||
emit_function('is_unicode_combining_mark', ('Mn', 'Mc'), output_file, codepoints)
|
||||
print('}\n\n#undef TOML_ASSUME_CODEPOINT_BETWEEN', file=output_file)
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
|
@ -55,5 +55,5 @@
|
||||
#if __has_include(<Catch2/single_include/catch2/catch.hpp>)
|
||||
#include <Catch2/single_include/catch2/catch.hpp>
|
||||
#else
|
||||
#error Catch2 is missing! You probably need to fetch submodules ("git submodule update --init --recursive")
|
||||
#error Catch2 is missing! You probably need to fetch submodules ("git submodule update --init --recursive extern/Catch2")
|
||||
#endif
|
||||
|
@ -43,9 +43,9 @@ void parsing_should_succeed(std::basic_string_view<CHAR> toml_str, FUNC&& func,
|
||||
catch (const toml::parse_error& err)
|
||||
{
|
||||
FAIL(
|
||||
"Parse error on line "sv << err.where().begin.line
|
||||
<< ", column "sv << err.where().begin.column
|
||||
<< ":\n"sv << err.what()
|
||||
"Parse error on line "sv << err.source().begin.line
|
||||
<< ", column "sv << err.source().begin.column
|
||||
<< ":\n"sv << err.description()
|
||||
);
|
||||
}
|
||||
|
||||
@ -58,9 +58,9 @@ void parsing_should_succeed(std::basic_string_view<CHAR> toml_str, FUNC&& func,
|
||||
else
|
||||
{
|
||||
FAIL(
|
||||
"Parse error on line "sv << result.error().where().begin.line
|
||||
<< ", column "sv << result.error().where().begin.column
|
||||
<< ":\n"sv << result.error().what()
|
||||
"Parse error on line "sv << result.error().source().begin.line
|
||||
<< ", column "sv << result.error().source().begin.column
|
||||
<< ":\n"sv << result.error().description()
|
||||
);
|
||||
return;
|
||||
}
|
||||
@ -75,9 +75,9 @@ void parsing_should_succeed(std::basic_string_view<CHAR> toml_str, FUNC&& func,
|
||||
else
|
||||
{
|
||||
FAIL(
|
||||
"Parse error on line "sv << result.error().where().begin.line
|
||||
<< ", column "sv << result.error().where().begin.column
|
||||
<< ":\n"sv << result.error().what()
|
||||
"Parse error on line "sv << result.error().source().begin.line
|
||||
<< ", column "sv << result.error().source().begin.column
|
||||
<< ":\n"sv << result.error().description()
|
||||
);
|
||||
return;
|
||||
}
|
||||
@ -160,7 +160,7 @@ void parse_expected_value(std::string_view value_str, const T& expected) noexcep
|
||||
|
||||
static constexpr auto is_val = [](char32_t codepoint) noexcept
|
||||
{
|
||||
if constexpr (std::is_same_v<string, promoted<T>>)
|
||||
if constexpr (std::is_same_v<string, impl::promoted<T>>)
|
||||
return codepoint == U'"' || codepoint == U'\'';
|
||||
else
|
||||
return !impl::is_whitespace(codepoint);
|
||||
@ -201,8 +201,8 @@ void parse_expected_value(std::string_view value_str, const T& expected) noexcep
|
||||
parsing_should_succeed(std::string_view{ value }, [&](table&& tbl) noexcept
|
||||
{
|
||||
CHECK(tbl.size() == 1);
|
||||
REQUIRE(tbl[S("val"sv)].as<promoted<T>>());
|
||||
CHECK(tbl[S("val"sv)].as<promoted<T>>()->get() == expected);
|
||||
REQUIRE(tbl[S("val"sv)].as<impl::promoted<T>>());
|
||||
CHECK(tbl[S("val"sv)].as<impl::promoted<T>>()->get() == expected);
|
||||
CHECK(tbl[S("val"sv)].get()->source().begin == begin);
|
||||
CHECK(tbl[S("val"sv)].get()->source().end == end);
|
||||
});
|
||||
|
@ -59,6 +59,7 @@
|
||||
<ClInclude Include="..\include\toml++\toml.h" />
|
||||
<ClInclude Include="..\include\toml++\toml_array.h" />
|
||||
<ClInclude Include="..\include\toml++\toml_common.h" />
|
||||
<ClInclude Include="..\include\toml++\toml_date_time.h" />
|
||||
<ClInclude Include="..\include\toml++\toml_default_formatter.h" />
|
||||
<ClInclude Include="..\include\toml++\toml_formatter.h" />
|
||||
<ClInclude Include="..\include\toml++\toml_json_formatter.h" />
|
||||
@ -74,6 +75,8 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\.editorconfig" />
|
||||
<None Include="..\python\ci_single_header_check.py" />
|
||||
<None Include="..\python\generate_documentation.py" />
|
||||
<None Include="..\python\generate_single_header.py" />
|
||||
<None Include="..\python\generate_unicode_functions.py" />
|
||||
<None Include="..\README.md" />
|
||||
|
@ -16,11 +16,14 @@
|
||||
<ClInclude Include="..\include\toml++\toml_formatter.h" />
|
||||
<ClInclude Include="..\include\toml++\toml_version.h" />
|
||||
<ClInclude Include="..\include\toml++\toml_print_to_stream.h" />
|
||||
<ClInclude Include="..\include\toml++\toml_date_time.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\.editorconfig" />
|
||||
<None Include="..\README.md" />
|
||||
<None Include="..\python\generate_single_header.py" />
|
||||
<None Include="..\python\generate_unicode_functions.py" />
|
||||
<None Include="..\python\generate_documentation.py" />
|
||||
<None Include="..\python\ci_single_header_check.py" />
|
||||
</ItemGroup>
|
||||
</Project>
|
Loading…
Reference in New Issue
Block a user