aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Spartan322 <Megacake1234@gmail.com>2023-11-28 11:09:26 +0100
committer Spartan322 <Megacake1234@gmail.com>2024-05-09 22:11:26 +0200
commit757114a3c5b748567b42f273c7b78ca039ae983c (patch)
treee07390b682052129c91f4b157068bcdd84ceecb4
parent7211a228e68c8a6b1ad1c1c5ec68c8d720b6d2ba (diff)
Add `deps/dryad` -> https://github.com/Spartan322/dryadadd/dryad
Add `deps/fmt` -> https://github.com/fmtlib/fmt Add `deps/range-v3` -> https://github.com/ericniebler/range-v3 Improve parser error and warning support Update .clang-format Update `deps/SCsub`
-rw-r--r--.clang-format8
-rw-r--r--.gitmodules9
-rw-r--r--deps/SCsub78
m---------deps/dryad0
m---------deps/fmt0
m---------deps/range-v30
-rw-r--r--include/openvic-dataloader/AbstractSyntaxTree.hpp111
-rw-r--r--include/openvic-dataloader/DiagnosticLogger.hpp390
-rw-r--r--include/openvic-dataloader/Error.hpp195
-rw-r--r--include/openvic-dataloader/File.hpp69
-rw-r--r--include/openvic-dataloader/NodeLocation.hpp33
-rw-r--r--include/openvic-dataloader/ParseState.hpp120
-rw-r--r--include/openvic-dataloader/Parser.hpp (renamed from include/openvic-dataloader/detail/BasicParser.hpp)12
-rw-r--r--include/openvic-dataloader/csv/LineObject.hpp2
-rw-r--r--include/openvic-dataloader/csv/Parser.hpp25
-rw-r--r--include/openvic-dataloader/detail/CallbackOStream.hpp31
-rw-r--r--include/openvic-dataloader/detail/ClassExport.hpp9
-rw-r--r--include/openvic-dataloader/detail/Concepts.hpp21
-rw-r--r--include/openvic-dataloader/detail/LexyFwdDeclaration.hpp8
-rw-r--r--include/openvic-dataloader/detail/LexyReportError.hpp (renamed from src/openvic-dataloader/detail/LexyReportError.hpp)5
-rw-r--r--include/openvic-dataloader/detail/OStreamOutputIterator.hpp (renamed from src/openvic-dataloader/detail/OStreamOutputIterator.hpp)1
-rw-r--r--include/openvic-dataloader/detail/OptionalConstexpr.hpp9
-rw-r--r--include/openvic-dataloader/detail/utility/Concepts.hpp45
-rw-r--r--include/openvic-dataloader/detail/utility/Constexpr.hpp (renamed from include/openvic-dataloader/detail/VectorConstexpr.hpp)6
-rw-r--r--include/openvic-dataloader/detail/utility/ErrorRange.hpp11
-rw-r--r--include/openvic-dataloader/detail/utility/PointerHash.hpp (renamed from include/openvic-dataloader/detail/PointerHash.hpp)0
-rw-r--r--include/openvic-dataloader/detail/utility/SelfType.hpp (renamed from include/openvic-dataloader/detail/SelfType.hpp)0
-rw-r--r--include/openvic-dataloader/detail/utility/TypeName.hpp (renamed from include/openvic-dataloader/detail/TypeName.hpp)0
-rw-r--r--include/openvic-dataloader/detail/utility/Utility.hpp38
-rw-r--r--include/openvic-dataloader/v2script/AbstractSyntaxTree.hpp398
-rw-r--r--include/openvic-dataloader/v2script/NodeLocationMap.hpp91
-rw-r--r--include/openvic-dataloader/v2script/Parser.hpp46
-rw-r--r--src/headless/main.cpp112
-rw-r--r--src/openvic-dataloader/AbstractSyntaxTree.cpp27
-rw-r--r--src/openvic-dataloader/DiagnosticLogger.cpp16
-rw-r--r--src/openvic-dataloader/File.cpp9
-rw-r--r--src/openvic-dataloader/NodeLocation.cpp26
-rw-r--r--src/openvic-dataloader/csv/CsvGrammar.hpp201
-rw-r--r--src/openvic-dataloader/csv/CsvParseState.hpp28
-rw-r--r--src/openvic-dataloader/csv/Parser.cpp161
-rw-r--r--src/openvic-dataloader/detail/BasicBufferHandler.hpp51
-rw-r--r--src/openvic-dataloader/detail/BufferError.hpp17
-rw-r--r--src/openvic-dataloader/detail/DetectUtf8.hpp12
-rw-r--r--src/openvic-dataloader/detail/LexyLitRange.hpp16
-rw-r--r--src/openvic-dataloader/detail/NullBuff.hpp8
-rw-r--r--src/openvic-dataloader/detail/ParseHandler.hpp145
-rw-r--r--src/openvic-dataloader/detail/Parser.cpp (renamed from src/openvic-dataloader/detail/BasicParser.cpp)14
-rw-r--r--src/openvic-dataloader/detail/StringLiteral.hpp232
-rw-r--r--src/openvic-dataloader/detail/Warnings.hpp4
-rw-r--r--src/openvic-dataloader/detail/dsl.hpp150
-rw-r--r--src/openvic-dataloader/v2script/AbstractSyntaxTree.cpp417
-rw-r--r--src/openvic-dataloader/v2script/AiBehaviorGrammar.hpp18
-rw-r--r--src/openvic-dataloader/v2script/DecisionGrammar.hpp115
-rw-r--r--src/openvic-dataloader/v2script/EffectGrammar.hpp31
-rw-r--r--src/openvic-dataloader/v2script/EventGrammar.hpp214
-rw-r--r--src/openvic-dataloader/v2script/LuaDefinesGrammar.hpp82
-rw-r--r--src/openvic-dataloader/v2script/ModifierGrammar.hpp49
-rw-r--r--src/openvic-dataloader/v2script/Parser.cpp280
-rw-r--r--src/openvic-dataloader/v2script/SimpleGrammar.hpp262
-rw-r--r--src/openvic-dataloader/v2script/TriggerGrammar.hpp31
60 files changed, 2892 insertions, 1607 deletions
diff --git a/.clang-format b/.clang-format
index 86fc638..93baaea 100644
--- a/.clang-format
+++ b/.clang-format
@@ -55,7 +55,11 @@ IncludeCategories:
Priority: 3
- Regex: ^<lexy/
Priority: 4
- - Regex: ^"openvic-dataloader/
+ - Regex: ^<dryad/
Priority: 5
- - Regex: .*
+ - Regex: ^<fmt/
Priority: 6
+ - Regex: ^"openvic-dataloader/
+ Priority: 7
+ - Regex: .*
+ Priority: 8
diff --git a/.gitmodules b/.gitmodules
index 0a1353b..0b7febe 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -5,3 +5,12 @@
[submodule "scripts"]
path = scripts
url = https://github.com/OpenVicProject/scripts
+[submodule "deps/dryad"]
+ path = deps/dryad
+ url = https://github.com/Spartan322/dryad
+[submodule "deps/fmt"]
+ path = deps/fmt
+ url = https://github.com/fmtlib/fmt
+[submodule "deps/range-v3"]
+ path = deps/range-v3
+ url = https://github.com/ericniebler/range-v3
diff --git a/deps/SCsub b/deps/SCsub
index eb27dab..1f04205 100644
--- a/deps/SCsub
+++ b/deps/SCsub
@@ -17,7 +17,7 @@ def build_lexy(env):
lexy_env.Append(CXXFLAGS=["-std=c++20"])
lexy_env.Append(CXXFLAGS=["-pedantic-errors", "-Werror", "-Wall", "-Wextra", "-Wconversion", "-Wsign-conversion"])
- if lexy_env.get("use_llvm"):
+ if lexy_env["CXX"] == "clang++":
lexy_env.Append(CXXFLAGS=["-Wno-shift-op-parentheses", "-Wno-parentheses-equality"])
else:
lexy_env.Append(CXXFLAGS=[
@@ -41,5 +41,79 @@ def build_lexy(env):
env.Append(LIBPATH=[lexy_env.Dir("lexy/src")])
env.Prepend(LIBS=[library_name])
+def build_dryad(env):
+ paths = ["dryad/include"]
+ sources = env.GlobRecursive("*.cpp", paths)
+ env.dryad_sources = sources
+
+ env.Append(CPPPATH=[env.Dir("dryad/include")])
+ if env.get("is_msvc", False):
+ env.Append(CXXFLAGS=["/external:I", env.Dir("dryad/include"), "/external:W0"])
+ else:
+ env.Append(CXXFLAGS=["-isystem", env.Dir("dryad/include")])
+
+def build_fmt(env):
+ fmt_env = env.Clone()
+
+ # Require C++20
+ if fmt_env.get("is_msvc", False):
+ fmt_env.Append(CXXFLAGS=["/std:c++20"])
+
+ fmt_env.Append(CXXFLAGS=["/WX", "/W3", "/D", "_CRT_SECURE_NO_WARNINGS"])
+ else:
+ fmt_env.Append(CXXFLAGS=["-std=c++20"])
+
+ fmt_env.Append(CXXFLAGS=[
+ "-Werror", "-Wall", "-Wextra", "-pedantic", "-Wconversion", "-Wundef"
+ ])
+ if fmt_env["CXX"] == "clang++":
+ fmt_env.Append(CXXFLAGS=[
+ "-Wweak-vtables", "-Wshadow",
+ "-Wno-gnu-zero-variadic-macro-arguments"
+ ])
+ else:
+ fmt_env.Append(CXXFLAGS=[
+ "-Wsign-conversion", "-Wold-style-cast",
+ "-Wundef", "-Wredundant-decls", "-Wwrite-strings",
+ "-Wpointer-arith", "-Wcast-qual", "-Wformat=2",
+ "-Wmissing-include-dirs", "-Wcast-align", "-Wctor-dtor-privacy",
+ "-Wdisabled-optimization", "-Winvalid-pch", "-Woverloaded-virtual",
+ "-Wconversion", "-Wundef", "-Wno-ctor-dtor-privacy", "-Wno-format-nonliteral",
+ "-Wno-dangling-else", "-Wno-unused-local-typedefs", "-Wdouble-promotion",
+ "-Wtrampolines", "-Wzero-as-null-pointer-constant", "-Wuseless-cast",
+ "-Wvector-operation-performance", "-Wsized-deallocation", "-Wshadow",
+ "-Wshift-overflow=2", "-Wnull-dereference", "-Wduplicated-cond"
+ ])
+
+ paths = ["fmt/include", "fmt/src"]
+ fmt_env.Append(CPPPATH=[[fmt_env.Dir(p) for p in paths]])
+ sources = env.GlobRecursive("*.cc", paths, "fmt.cc")
+ env.lexy_sources = sources
+ library_name = "libfmt" + env["LIBSUFFIX"]
+ library = fmt_env.StaticLibrary(target="fmt/src/" + library_name, source=sources)
+ Default(library)
+
+ env.Append(CPPPATH=[fmt_env.Dir("fmt/include")])
+ if env.get("is_msvc", False):
+ env.Append(CXXFLAGS=["/external:I", fmt_env.Dir("fmt/include"), "/external:W0"])
+ else:
+ env.Append(CXXFLAGS=["-isystem", fmt_env.Dir("fmt/include")])
+ env.Append(CXXFLAGS=[""])
+ env.Append(LIBPATH=[fmt_env.Dir("fmt/src")])
+ env.Prepend(LIBS=[library_name])
+
+def build_range_v3(env):
+ paths = ["range-v3/include"]
+ sources = env.GlobRecursive("*.cpp", paths)
+ env.range_v3_sources = sources
+
+ env.Append(CPPPATH=[env.Dir("range-v3/include")])
+ if env.get("is_msvc", False):
+ env.Append(CXXFLAGS=["/external:I", env.Dir("range-v3/include"), "/external:W0"])
+ else:
+ env.Append(CXXFLAGS=["-isystem", env.Dir("range-v3/include")])
-build_lexy(env) \ No newline at end of file
+build_dryad(env)
+build_fmt(env)
+build_lexy(env)
+build_range_v3(env) \ No newline at end of file
diff --git a/deps/dryad b/deps/dryad
new file mode 160000
+Subproject 3aa3d7606cb007436bb3433ddf83b8bdcf1ecc4
diff --git a/deps/fmt b/deps/fmt
new file mode 160000
+Subproject f5e54359df4c26b6230fc61d38aa29458139308
diff --git a/deps/range-v3 b/deps/range-v3
new file mode 160000
+Subproject 97452bb3eb74a73fc86504421a6a27c92bce6b9
diff --git a/include/openvic-dataloader/AbstractSyntaxTree.hpp b/include/openvic-dataloader/AbstractSyntaxTree.hpp
new file mode 100644
index 0000000..db81eeb
--- /dev/null
+++ b/include/openvic-dataloader/AbstractSyntaxTree.hpp
@@ -0,0 +1,111 @@
+#pragma once
+
+#include <concepts>
+#include <cstdio>
+#include <string_view>
+#include <utility>
+
+#include <openvic-dataloader/File.hpp>
+#include <openvic-dataloader/NodeLocation.hpp>
+#include <openvic-dataloader/detail/utility/Utility.hpp>
+
+#include <dryad/node.hpp>
+#include <dryad/node_map.hpp>
+#include <dryad/symbol.hpp>
+#include <dryad/tree.hpp>
+
+#include <fmt/core.h>
+
+namespace ovdl {
+ struct AbstractSyntaxTree {
+ struct SymbolId;
+ using index_type = std::uint32_t;
+ using symbol_type = dryad::symbol<SymbolId, index_type>;
+ using symbol_interner_type = dryad::symbol_interner<SymbolId, char, index_type>;
+
+ symbol_type intern(const char* str, std::size_t length);
+ symbol_type intern(std::string_view str);
+ const char* intern_cstr(const char* str, std::size_t length);
+ const char* intern_cstr(std::string_view str);
+ symbol_interner_type& symbol_interner();
+ const symbol_interner_type& symbol_interner() const;
+
+ protected:
+ symbol_interner_type _symbol_interner;
+ };
+
+ template<typename T>
+ concept IsAst =
+ std::derived_from<T, AbstractSyntaxTree> &&
+ requires(
+ T t,
+ const T ct,
+ const typename T::node_type* node,
+ NodeLocation loc //
+ ) {
+ requires IsFile<typename T::file_type>;
+ typename T::root_node_type;
+ typename T::node_type;
+ requires std::derived_from<typename T::root_node_type, typename T::node_type>;
+ { t.set_location(node, loc) } -> std::same_as<void>;
+ { t.location_of(node) } -> std::same_as<NodeLocation>;
+ { t.root() } -> std::same_as<typename T::root_node_type*>;
+ { ct.root() } -> std::same_as<const typename T::root_node_type*>;
+ { t.file() } -> std::same_as<typename T::file_type&>;
+ { ct.file() } -> std::same_as<const typename T::file_type&>;
+ };
+
+ template<IsFile FileT, std::derived_from<typename FileT::node_type> RootNodeT>
+ struct BasicAbstractSyntaxTree : AbstractSyntaxTree {
+ using file_type = FileT;
+ using root_node_type = RootNodeT;
+ using node_type = typename file_type::node_type;
+
+ explicit BasicAbstractSyntaxTree(file_type&& file) : _file(std::move(file)) {}
+ explicit BasicAbstractSyntaxTree(lexy::buffer<typename file_type::encoding_type, void>&& buffer) : _file(std::move(buffer)) {}
+
+ void set_location(const node_type* n, NodeLocation loc) {
+ _file.set_location(n, loc);
+ }
+
+ NodeLocation location_of(const node_type* n) const {
+ return _file.location_of(n);
+ }
+
+ root_node_type* root() {
+ return _tree.root();
+ }
+
+ const root_node_type* root() const {
+ return _tree.root();
+ }
+
+ file_type& file() {
+ return _file;
+ }
+
+ const file_type& file() const {
+ return _file;
+ }
+
+ template<typename T, typename... Args>
+ T* create(NodeLocation loc, Args&&... args) {
+ auto node = _tree.template create<T>(DRYAD_FWD(args)...);
+ set_location(node, loc);
+ return node;
+ }
+
+ template<typename T, typename... Args>
+ T* create(const char* begin, const char* end, Args&&... args) {
+ return create<T>(NodeLocation::make_from(begin, end), DRYAD_FWD(args)...);
+ }
+
+ void set_root(root_node_type* node) {
+ _tree.set_root(node);
+ }
+
+ protected:
+ dryad::tree<root_node_type> _tree;
+ file_type _file;
+ };
+} \ No newline at end of file
diff --git a/include/openvic-dataloader/DiagnosticLogger.hpp b/include/openvic-dataloader/DiagnosticLogger.hpp
new file mode 100644
index 0000000..1fa2784
--- /dev/null
+++ b/include/openvic-dataloader/DiagnosticLogger.hpp
@@ -0,0 +1,390 @@
+#pragma once
+
+#include <concepts>
+#include <cstdarg>
+#include <cstdio>
+#include <ostream>
+#include <string>
+#include <utility>
+
+#include <openvic-dataloader/AbstractSyntaxTree.hpp>
+#include <openvic-dataloader/Error.hpp>
+#include <openvic-dataloader/File.hpp>
+#include <openvic-dataloader/NodeLocation.hpp>
+#include <openvic-dataloader/detail/LexyReportError.hpp>
+#include <openvic-dataloader/detail/OStreamOutputIterator.hpp>
+
+#include <lexy/input/base.hpp>
+#include <lexy/input/buffer.hpp>
+#include <lexy/visualize.hpp>
+
+#include <dryad/_detail/config.hpp>
+#include <dryad/abstract_node.hpp>
+#include <dryad/arena.hpp>
+#include <dryad/node.hpp>
+#include <dryad/tree.hpp>
+
+#include <fmt/core.h>
+
+#include "openvic-dataloader/detail/CallbackOStream.hpp"
+#include "openvic-dataloader/detail/utility/ErrorRange.hpp"
+#include "openvic-dataloader/detail/utility/Utility.hpp"
+
+#include <lexy_ext/report_error.hpp>
+
+namespace ovdl {
+ struct DiagnosticLogger {
+ using AnnotationKind = lexy_ext::annotation_kind;
+ using DiagnosticKind = lexy_ext::diagnostic_kind;
+
+ using error_range = detail::error_range;
+
+ explicit operator bool() const;
+ bool errored() const;
+ bool warned() const;
+
+ NodeLocation location_of(const error::Error* error) const;
+
+ template<std::derived_from<DiagnosticLogger> Logger>
+ struct ErrorCallback {
+ ErrorCallback(Logger& logger) : _logger(&logger) {}
+
+ struct sink_t {
+ using return_type = std::size_t;
+
+ template<typename Input, typename Tag>
+ void operator()(lexy::error_context<Input> const& context, lexy::error_for<Input, Tag> const& error) {
+ using Reader = lexy::input_reader<Input>;
+ error::Error* result;
+
+ if constexpr (std::is_same_v<Tag, lexy::expected_literal>) {
+ auto string = lexy::_detail::make_literal_lexeme<typename Reader::encoding>(error.string(), error.length());
+ NodeLocation loc = NodeLocation::make_from(string.begin(), string.end());
+ auto message = _logger.intern_cstr(fmt::format("expected '{}'", string.data()));
+ result = _logger.template create<error::ExpectedLiteral>(loc, message, context.production());
+ } else if constexpr (std::is_same_v<Tag, lexy::expected_keyword>) {
+ auto string = lexy::_detail::make_literal_lexeme<typename Reader::encoding>(error.string(), error.length());
+ NodeLocation loc = NodeLocation::make_from(string.begin(), string.end());
+ auto message = _logger.intern_cstr(fmt::format("expected keyword '{}'", string.data()));
+ result = _logger.template create<error::ExpectedKeyword>(loc, message, context.production());
+ } else if constexpr (std::is_same_v<Tag, lexy::expected_char_class>) {
+ auto message = _logger.intern_cstr(fmt::format("expected {}", error.name()));
+ result = _logger.template create<error::ExpectedCharClass>(error.position(), message, context.production());
+ } else {
+ NodeLocation loc = NodeLocation::make_from(error.begin(), error.end());
+ auto message = _logger.intern_cstr(error.message());
+ result = _logger.template create<error::GenericParseError>(loc, message, context.production());
+ }
+
+ if constexpr (requires { _logger.insert(result); }) {
+ _logger.insert(result);
+ }
+
+ _count++;
+ }
+
+ std::size_t finish() && {
+ return _count;
+ }
+
+ Logger& _logger;
+ std::size_t _count;
+ };
+
+ constexpr auto sink() const {
+ return sink_t { *_logger, 0 };
+ }
+
+ mutable Logger* _logger;
+ };
+
+ template<typename T, typename... Args>
+ T* create(NodeLocation loc, Args&&... args) {
+ using node_creator = dryad::node_creator<decltype(DRYAD_DECLVAL(T).kind()), void>;
+ T* result = _tree.create<T>(DRYAD_FWD(args)...);
+ _map.insert(result, loc);
+ return result;
+ }
+
+ template<typename T>
+ T* create() {
+ using node_creator = dryad::node_creator<decltype(DRYAD_DECLVAL(T).kind()), void>;
+ T* result = _tree.create<T>();
+ return result;
+ }
+
+ protected:
+ bool _errored = false;
+ bool _warned = false;
+ dryad::node_map<const error::Error, NodeLocation> _map;
+ dryad::tree<error::Root> _tree;
+
+ struct SymbolId;
+ using index_type = std::uint32_t;
+ using symbol_type = dryad::symbol<SymbolId, index_type>;
+ using symbol_interner_type = dryad::symbol_interner<SymbolId, char, index_type>;
+ symbol_interner_type _symbol_interner;
+
+ public:
+ symbol_type intern(const char* str, std::size_t length) {
+ return _symbol_interner.intern(str, length);
+ }
+ symbol_type intern(std::string_view str) {
+ return intern(str.data(), str.size());
+ }
+ const char* intern_cstr(const char* str, std::size_t length) {
+ return intern(str, length).c_str(_symbol_interner);
+ }
+ const char* intern_cstr(std::string_view str) {
+ return intern_cstr(str.data(), str.size());
+ }
+ symbol_interner_type& symbol_interner() {
+ return _symbol_interner;
+ }
+ const symbol_interner_type& symbol_interner() const {
+ return _symbol_interner;
+ }
+ };
+
+ template<IsFile FileT>
+ struct BasicDiagnosticLogger : DiagnosticLogger {
+ using file_type = FileT;
+
+ template<typename... Args>
+ using format_str = fmt::basic_format_string<char, fmt::type_identity_t<Args>...>;
+
+ explicit BasicDiagnosticLogger(const file_type& file)
+ : _file(&file) {
+ _tree.set_root(_tree.create<error::Root>());
+ }
+
+ struct Writer;
+
+ template<typename... Args>
+ Writer error(format_str<Args...> fmt, Args&&... args) {
+ return log(DiagnosticKind::error, fmt, std::forward<Args>(args)...);
+ }
+
+ template<typename... Args>
+ Writer warning(format_str<Args...> fmt, Args&&... args) {
+ return log(DiagnosticKind::warning, fmt, std::forward<Args>(args)...);
+ }
+
+ template<typename... Args>
+ Writer note(format_str<Args...> fmt, Args&&... args) {
+ return log(DiagnosticKind::note, fmt, std::forward<Args>(args)...);
+ }
+
+ template<typename... Args>
+ Writer info(format_str<Args...> fmt, Args&&... args) {
+ return log(DiagnosticKind::info, fmt, std::forward<Args>(args)...);
+ }
+
+ template<typename... Args>
+ Writer debug(format_str<Args...> fmt, Args&&... args) {
+ return log(DiagnosticKind::debug, fmt, std::forward<Args>(args)...);
+ }
+
+ template<typename... Args>
+ Writer fixit(format_str<Args...> fmt, Args&&... args) {
+ return log(DiagnosticKind::fixit, fmt, std::forward<Args>(args)...);
+ }
+
+ template<typename... Args>
+ Writer help(format_str<Args...> fmt, Args&&... args) {
+ return log(DiagnosticKind::help, fmt, std::forward<Args>(args)...);
+ }
+
+ Writer error(std::string_view sv) {
+ return log(DiagnosticKind::error, fmt::runtime(sv));
+ }
+
+ Writer warning(std::string_view sv) {
+ return log(DiagnosticKind::warning, fmt::runtime(sv));
+ }
+
+ Writer note(std::string_view sv) {
+ return log(DiagnosticKind::note, fmt::runtime(sv));
+ }
+
+ Writer info(std::string_view sv) {
+ return log(DiagnosticKind::info, fmt::runtime(sv));
+ }
+
+ Writer debug(std::string_view sv) {
+ return log(DiagnosticKind::debug, fmt::runtime(sv));
+ }
+
+ Writer fixit(std::string_view sv) {
+ return log(DiagnosticKind::fixit, fmt::runtime(sv));
+ }
+
+ Writer help(std::string_view sv) {
+ return log(DiagnosticKind::help, fmt::runtime(sv));
+ }
+
+ auto error_callback() {
+ return ErrorCallback(*this);
+ }
+
+ template<typename CharT>
+ static void _write_to_buffer(const CharT* s, std::streamsize n, void* output_str) {
+ auto* output = reinterpret_cast<std::basic_string<CharT>*>(output_str);
+ output->append(s, n);
+ }
+
+ template<typename CharT>
+ auto make_callback_stream(std::basic_string<CharT>& output) {
+ return detail::make_callback_stream<CharT>(&_write_to_buffer<CharT>, reinterpret_cast<void*>(&output));
+ }
+
+ template<typename CharT>
+ detail::OStreamOutputIterator make_ostream_iterator(std::basic_ostream<CharT>& stream) {
+ return detail::OStreamOutputIterator { stream };
+ }
+
+ struct Writer {
+ template<typename... Args>
+ [[nodiscard]] Writer& primary(NodeLocation loc, format_str<Args...> fmt, Args&&... args) {
+ return annotation(AnnotationKind::primary, loc, fmt, std::forward<Args>(args)...);
+ }
+
+ template<typename... Args>
+ [[nodiscard]] Writer& secondary(NodeLocation loc, format_str<Args...> fmt, Args&&... args) {
+ return annotation(AnnotationKind::secondary, loc, fmt, std::forward<Args>(args)...);
+ }
+
+ [[nodiscard]] Writer& primary(NodeLocation loc, std::string_view sv) {
+ return annotation(AnnotationKind::primary, loc, fmt::runtime(sv));
+ }
+
+ [[nodiscard]] Writer& secondary(NodeLocation loc, std::string_view sv) {
+ return annotation(AnnotationKind::secondary, loc, fmt::runtime(sv));
+ }
+
+ void finish() {}
+
+ template<typename... Args>
+ [[nodiscard]] Writer& annotation(AnnotationKind kind, NodeLocation loc, format_str<Args...> fmt, Args&&... args) {
+ auto begin_loc = lexy::get_input_location(_file->buffer(), loc.begin());
+
+ std::basic_string<typename decltype(fmt.get())::value_type> output;
+ auto stream = _logger.make_callback_stream(output);
+ auto iter = _logger.make_ostream_iterator(stream);
+
+ _impl.write_empty_annotation(iter);
+ _impl.write_annotation(iter, kind, begin_loc, loc.end(),
+ [&](auto out, lexy::visualization_options) {
+ return lexy::_detail::write_str(out, fmt::format(fmt, std::forward<Args>(args)...).c_str());
+ });
+
+ error::Annotation* annotation;
+ auto message = _logger.intern_cstr(output);
+ switch (kind) {
+ case AnnotationKind::primary:
+ _logger.create<error::PrimaryAnnotation>(loc, message);
+ break;
+ case AnnotationKind::secondary:
+ _logger.create<error::SecondaryAnnotation>(loc, message);
+ break;
+ default: detail::unreachable();
+ }
+ _semantic->push_back(annotation);
+ return *this;
+ }
+
+ private:
+ Writer(BasicDiagnosticLogger& logger, const file_type* file, error::Semantic* semantic)
+ : _file(file),
+ _impl(file->buffer(), { lexy::visualize_fancy }),
+ _logger(logger),
+ _semantic(semantic) {}
+
+ const file_type* _file;
+ lexy_ext::diagnostic_writer<lexy::buffer<typename file_type::encoding_type>> _impl;
+ BasicDiagnosticLogger& _logger;
+ error::Semantic* _semantic;
+
+ friend BasicDiagnosticLogger;
+ };
+
+ using diagnostic_writer = lexy_ext::diagnostic_writer<lexy::buffer<typename file_type::encoding_type>>;
+
+ template<std::derived_from<error::Error> T, typename... Args>
+ void log_with_impl(diagnostic_writer& impl, T* error, DiagnosticKind kind, format_str<Args...> fmt, Args&&... args) {
+ std::basic_string<typename decltype(fmt.get())::value_type> output;
+ auto stream = make_callback_stream(output);
+ auto iter = make_ostream_iterator(stream);
+
+ impl.write_message(iter, kind,
+ [&](auto out, lexy::visualization_options) {
+ return lexy::_detail::write_str(out, fmt::format(fmt, std::forward<Args>(args)...).c_str());
+ });
+ impl.write_path(iter, _file->path());
+
+ auto message = intern_cstr(output);
+ error->_set_message(message);
+ insert(error);
+ }
+
+ template<std::derived_from<error::Error> T, typename... Args>
+ void log_with_error(T* error, DiagnosticKind kind, format_str<Args...> fmt, Args&&... args) {
+ auto impl = diagnostic_writer { _file->buffer() };
+ log_with_impl(impl, error, kind, fmt, std::forward<Args>(args)...);
+ }
+
+ template<std::derived_from<error::Error> T, typename... Args>
+ void create_log(DiagnosticKind kind, format_str<Args...> fmt, Args&&... args) {
+ log_with_error(create<T>(), kind, fmt, std::forward<Args>(args)...);
+ }
+
+ template<typename... Args>
+ Writer log(DiagnosticKind kind, format_str<Args...> fmt, Args&&... args) {
+ error::Semantic* semantic;
+
+ switch (kind) {
+ case DiagnosticKind::error:
+ semantic = create<error::SemanticError>();
+ break;
+ case DiagnosticKind::warning:
+ semantic = create<error::SemanticWarning>();
+ break;
+ case DiagnosticKind::info:
+ semantic = create<error::SemanticInfo>();
+ break;
+ case DiagnosticKind::debug:
+ semantic = create<error::SemanticDebug>();
+ break;
+ case DiagnosticKind::fixit:
+ semantic = create<error::SemanticFixit>();
+ break;
+ case DiagnosticKind::help:
+ semantic = create<error::SemanticHelp>();
+ break;
+ default: detail::unreachable();
+ }
+
+ Writer result(*this, _file, semantic);
+
+ log_with_impl(result._impl, semantic, kind, fmt, std::forward<Args>(args)...);
+
+ if (kind == DiagnosticKind::error)
+ _errored = true;
+ if (kind == DiagnosticKind::warning)
+ _warned = true;
+
+ return result;
+ }
+
+ error_range get_errors() const {
+ return _tree.root()->errors();
+ }
+
+ private:
+ void insert(error::Error* root) {
+ _tree.root()->insert_back(root);
+ }
+
+ const file_type* _file;
+ };
+} \ No newline at end of file
diff --git a/include/openvic-dataloader/Error.hpp b/include/openvic-dataloader/Error.hpp
new file mode 100644
index 0000000..fd3254d
--- /dev/null
+++ b/include/openvic-dataloader/Error.hpp
@@ -0,0 +1,195 @@
+#pragma once
+
+#include <cstdint>
+#include <string_view>
+
+#include <openvic-dataloader/File.hpp>
+#include <openvic-dataloader/detail/utility/Utility.hpp>
+
+#include <dryad/abstract_node.hpp>
+#include <dryad/node.hpp>
+
+namespace ovdl {
+ template<IsFile>
+ struct BasicDiagnosticLogger;
+}
+
+namespace ovdl::error {
+ enum class [[nodiscard]] ErrorKind : std::uint64_t {
+ Root,
+
+ BufferError,
+
+ // Parse Error //
+ ExpectedLiteral,
+ ExpectedKeyword,
+ ExpectedCharClass,
+ GenericParseError,
+
+ FirstParseError = ExpectedLiteral,
+ LastParseError = GenericParseError,
+
+ // Semantic Diagnostic //
+ SemanticError,
+ SemanticWarning,
+ SemanticInfo,
+ SemanticDebug,
+ SemanticFixit,
+ SemanticHelp,
+
+ FirstSemantic = SemanticError,
+ LastSemantic = SemanticHelp,
+
+ PrimaryAnnotation,
+ SecondaryAnnotation,
+
+ FirstAnnotation = PrimaryAnnotation,
+ LastAnnotation = SecondaryAnnotation,
+ };
+
+ static constexpr std::string_view get_kind_name(ErrorKind kind) {
+ switch (kind) {
+ using enum ErrorKind;
+ case ExpectedLiteral: return "expected literal";
+ case ExpectedKeyword: return "expected keyword";
+ case ExpectedCharClass: return "expected char class";
+ case GenericParseError: return "generic";
+ default: detail::unreachable();
+ }
+ }
+
+ struct Error : dryad::abstract_node_all<ErrorKind> {
+ const char* message() const { return _message; }
+
+ protected:
+ DRYAD_ABSTRACT_NODE_CTOR(Error);
+
+ void _set_message(const char* message) { _message = message; }
+ const char* _message;
+
+ template<IsFile>
+ friend struct ovdl::BasicDiagnosticLogger;
+ };
+
+ using ErrorList = dryad::unlinked_node_list<Error>;
+
+ struct Annotation;
+ using AnnotationList = dryad::unlinked_node_list<Annotation>;
+
+ struct Root : dryad::basic_node<ErrorKind::Root, dryad::container_node<Error>> {
+ explicit Root(dryad::node_ctor ctor) : node_base(ctor) {}
+
+ DRYAD_CHILD_NODE_RANGE_GETTER(Error, errors, nullptr, this);
+
+ void insert_back(Error* error) {
+ insert_child_after(_last, error);
+ _last = error;
+ }
+
+ private:
+ Error* _last = nullptr;
+ };
+
+ struct BufferError : dryad::basic_node<ErrorKind::BufferError, Error> {
+ explicit BufferError(dryad::node_ctor ctor, const char* message) : node_base(ctor) {
+ _set_message(message);
+ }
+
+ explicit BufferError(dryad::node_ctor ctor) : node_base(ctor) {}
+ };
+
+ struct ParseError : dryad::abstract_node_range<Error, ErrorKind::FirstParseError, ErrorKind::LastParseError> {
+ const char* production_name() const { return _production_name; }
+
+ protected:
+ explicit ParseError(dryad::node_ctor ctor,
+ ErrorKind kind,
+ const char* message,
+ const char* production_name)
+ : node_base(ctor, kind),
+ _production_name(production_name) {
+ _set_message(message);
+ };
+
+ const char* _production_name;
+ };
+
+ template<ErrorKind NodeKind>
+ struct _ParseError_t : dryad::basic_node<NodeKind, ParseError> {
+ explicit _ParseError_t(dryad::node_ctor ctor, const char* message, const char* production_name)
+ : dryad::basic_node<NodeKind, ParseError>(ctor, message, production_name) {}
+ };
+
+ using ExpectedLiteral = _ParseError_t<ErrorKind::ExpectedLiteral>;
+ using ExpectedKeyword = _ParseError_t<ErrorKind::ExpectedKeyword>;
+ using ExpectedCharClass = _ParseError_t<ErrorKind::ExpectedCharClass>;
+ using GenericParseError = _ParseError_t<ErrorKind::GenericParseError>;
+
+ struct Semantic : dryad::abstract_node_range<dryad::container_node<Error>, ErrorKind::FirstSemantic, ErrorKind::LastSemantic> {
+ DRYAD_CHILD_NODE_RANGE_GETTER(Annotation, annotations, nullptr, this);
+
+ void push_back(Annotation* annotation);
+ void push_back(AnnotationList p_annotations);
+
+ protected:
+ explicit Semantic(dryad::node_ctor ctor, ErrorKind kind)
+ : node_base(ctor, kind) {};
+
+ explicit Semantic(dryad::node_ctor ctor, ErrorKind kind, const char* message)
+ : node_base(ctor, kind) {
+ insert_child_list_after(nullptr, AnnotationList {});
+ _set_message(message);
+ };
+
+ explicit Semantic(dryad::node_ctor ctor, ErrorKind kind, const char* message, AnnotationList annotations)
+ : node_base(ctor, kind) {
+ insert_child_list_after(nullptr, annotations);
+ _set_message(message);
+ };
+ };
+
+ template<ErrorKind NodeKind>
+ struct _SemanticError_t : dryad::basic_node<NodeKind, Semantic> {
+ using base_node = dryad::basic_node<NodeKind, Semantic>;
+
+ explicit _SemanticError_t(dryad::node_ctor ctor)
+ : base_node(ctor) {}
+
+ explicit _SemanticError_t(dryad::node_ctor ctor, const char* message)
+ : base_node(ctor, message) {}
+
+ explicit _SemanticError_t(dryad::node_ctor ctor, const char* message, AnnotationList annotations)
+ : base_node(ctor, message, annotations) {}
+ };
+
+ using SemanticError = _SemanticError_t<ErrorKind::SemanticError>;
+ using SemanticWarning = _SemanticError_t<ErrorKind::SemanticWarning>;
+ using SemanticInfo = _SemanticError_t<ErrorKind::SemanticInfo>;
+ using SemanticDebug = _SemanticError_t<ErrorKind::SemanticDebug>;
+ using SemanticFixit = _SemanticError_t<ErrorKind::SemanticFixit>;
+ using SemanticHelp = _SemanticError_t<ErrorKind::SemanticHelp>;
+
+ struct Annotation : dryad::abstract_node_range<Error, ErrorKind::FirstAnnotation, ErrorKind::LastAnnotation> {
+ protected:
+ explicit Annotation(dryad::node_ctor ctor, ErrorKind kind, const char* message) : node_base(ctor, kind) {
+ _set_message(message);
+ }
+ };
+
+ template<ErrorKind NodeKind>
+ struct _Annotation_t : dryad::basic_node<NodeKind, Annotation> {
+ explicit _Annotation_t(dryad::node_ctor ctor, const char* message)
+ : dryad::basic_node<NodeKind, Annotation>(ctor, message) {}
+ };
+
+ using PrimaryAnnotation = _Annotation_t<ErrorKind::PrimaryAnnotation>;
+ using SecondaryAnnotation = _Annotation_t<ErrorKind::SecondaryAnnotation>;
+
+ inline void Semantic::push_back(Annotation* annotation) {
+ insert_child_after(annotations().end().deref(), annotation);
+ }
+
+ inline void Semantic::push_back(AnnotationList p_annotations) {
+ insert_child_list_after(annotations().end().deref(), p_annotations);
+ }
+} \ No newline at end of file
diff --git a/include/openvic-dataloader/File.hpp b/include/openvic-dataloader/File.hpp
new file mode 100644
index 0000000..caa4a0a
--- /dev/null
+++ b/include/openvic-dataloader/File.hpp
@@ -0,0 +1,69 @@
+#pragma once
+
+#include <concepts>
+
+#include <openvic-dataloader/NodeLocation.hpp>
+#include <openvic-dataloader/detail/LexyFwdDeclaration.hpp>
+
+#include <dryad/node_map.hpp>
+
+namespace ovdl {
+ template<typename T>
+ concept IsEncoding = requires(T t) {
+ typename T::char_type;
+ typename T::int_type;
+ { T::template is_secondary_char_type<typename T::char_type>() } -> std::same_as<bool>;
+ { T::eof() } -> std::same_as<typename T::int_type>;
+ { T::to_int_type(typename T::char_type {}) } -> std::same_as<typename T::int_type>;
+ };
+
+ struct File {
+ explicit File(const char* path);
+
+ const char* path() const noexcept;
+
+ protected:
+ const char* _path;
+ };
+
+ template<typename T>
+ concept IsFile =
+ std::derived_from<T, File> && IsEncoding<typename T::encoding_type> &&
+ requires(T t, const typename T::node_type* node, NodeLocation location) {
+ { t.buffer() } -> std::same_as<const lexy::buffer<typename T::encoding_type, void>&>;
+ { t.set_location(node, location) } -> std::same_as<void>;
+ { t.location_of(node) } -> std::same_as<NodeLocation>;
+ };
+
+ template<typename EncodingT, typename NodeT>
+ struct BasicFile : File {
+ using encoding_type = EncodingT;
+ using node_type = NodeT;
+
+ explicit BasicFile(const char* path, lexy::buffer<encoding_type, void>&& buffer)
+ : File(path),
+ _buffer(static_cast<std ::remove_reference_t<decltype(buffer)>&&>(buffer)) {}
+
+ explicit BasicFile(lexy::buffer<encoding_type, void>&& buffer)
+ : File(""),
+ _buffer(static_cast<std ::remove_reference_t<decltype(buffer)>&&>(buffer)) {}
+
+ const lexy::buffer<encoding_type, void>& buffer() const {
+ return _buffer;
+ }
+
+ void set_location(const node_type* n, NodeLocation loc) {
+ _map.insert(n, loc);
+ }
+
+ NodeLocation location_of(const node_type* n) const {
+ auto result = _map.lookup(n);
+ DRYAD_ASSERT(result != nullptr, "every Node should have a NodeLocation");
+ return *result;
+ }
+
+ protected:
+ lexy::buffer<encoding_type, void> _buffer;
+ dryad::node_map<const node_type, NodeLocation> _map;
+ };
+} \ No newline at end of file
diff --git a/include/openvic-dataloader/NodeLocation.hpp b/include/openvic-dataloader/NodeLocation.hpp
new file mode 100644
index 0000000..117560b
--- /dev/null
+++ b/include/openvic-dataloader/NodeLocation.hpp
@@ -0,0 +1,33 @@
+#pragma once
+
+#include <cstdint>
+
+namespace ovdl {
+ struct NodeLocation {
+ const char* _begin = nullptr;
+ const char* _end = nullptr;
+
+ NodeLocation();
+ NodeLocation(const char* pos);
+ NodeLocation(const char* begin, const char* end);
+
+ NodeLocation(const NodeLocation&) noexcept;
+ NodeLocation& operator=(const NodeLocation&);
+
+ NodeLocation(NodeLocation&&);
+ NodeLocation& operator=(NodeLocation&&);
+
+ const char* begin() const;
+ const char* end() const;
+
+ bool is_synthesized() const;
+
+ static NodeLocation make_from(const char* begin, const char* end);
+ };
+
+ struct FilePosition {
+ std::uint32_t start_line = std::uint32_t(-1), end_line = std::uint32_t(-1), start_column = std::uint32_t(-1), end_column = std::uint32_t(-1);
+
+ inline constexpr bool is_empty() { return start_line == std::uint32_t(-1) && end_line == std::uint32_t(-1) && start_column == std::uint32_t(-1) && end_column == std::uint32_t(-1); }
+ };
+} \ No newline at end of file
diff --git a/include/openvic-dataloader/ParseState.hpp b/include/openvic-dataloader/ParseState.hpp
new file mode 100644
index 0000000..5655606
--- /dev/null
+++ b/include/openvic-dataloader/ParseState.hpp
@@ -0,0 +1,120 @@
+#pragma once
+
+#include <concepts>
+
+#include <openvic-dataloader/AbstractSyntaxTree.hpp>
+#include <openvic-dataloader/DiagnosticLogger.hpp>
+
+#include <dryad/tree.hpp>
+
+namespace ovdl {
+ template<typename T>
+ concept IsParseState = requires(
+ T t,
+ const T ct,
+ typename T::ast_type::file_type&& file,
+ lexy::buffer<typename T::ast_type::file_type::encoding_type>&& buffer,
+ const char* path //
+ ) {
+ requires IsAst<typename T::ast_type>;
+ requires std::derived_from<typename T::diagnostic_logger_type, DiagnosticLogger>;
+ { T { std::move(file) } } -> std::same_as<T>;
+ { T { std::move(buffer) } } -> std::same_as<T>;
+ { T { path, std::move(buffer) } } -> std::same_as<T>;
+ { t.ast() } -> std::same_as<typename T::ast_type&>;
+ { ct.ast() } -> std::same_as<const typename T::ast_type&>;
+ { t.logger() } -> std::same_as<typename T::diagnostic_logger_type&>;
+ { ct.logger() } -> std::same_as<const typename T::diagnostic_logger_type&>;
+ };
+
+ template<IsAst AstT>
+ struct ParseState {
+ using ast_type = AstT;
+ using diagnostic_logger_type = BasicDiagnosticLogger<typename ast_type::file_type>;
+
+ ParseState(typename ast_type::file_type&& file)
+ : _ast { std::move(file) },
+ _logger { _ast.file() } {}
+
+ ParseState(lexy::buffer<typename ast_type::file_type::encoding_type>&& buffer)
+ : ParseState(typename ast_type::file_type { std::move(buffer) }) {}
+
+ ParseState(const char* path, lexy::buffer<typename ast_type::file_type::encoding_type>&& buffer)
+ : ParseState(typename ast_type::file_type { path, std::move(buffer) }) {}
+
+ ast_type& ast() {
+ return _ast;
+ }
+
+ const ast_type& ast() const {
+ return _ast;
+ }
+
+ diagnostic_logger_type& logger() {
+ return _logger;
+ }
+
+ const diagnostic_logger_type& logger() const {
+ return _logger;
+ }
+
+ private:
+ ast_type _ast;
+ diagnostic_logger_type _logger;
+ };
+
+ template<typename T>
+ concept IsFileParseState = requires(
+ T t,
+ const T ct,
+ typename T::file_type&& file,
+ lexy::buffer<typename T::file_type::encoding_type>&& buffer,
+ const char* path //
+ ) {
+ requires IsFile<typename T::file_type>;
+ requires std::derived_from<typename T::diagnostic_logger_type, DiagnosticLogger>;
+ { T { std::move(file) } } -> std::same_as<T>;
+ { T { std::move(buffer) } } -> std::same_as<T>;
+ { T { path, std::move(buffer) } } -> std::same_as<T>;
+ { t.file() } -> std::same_as<typename T::file_type&>;
+ { ct.file() } -> std::same_as<const typename T::file_type&>;
+ { t.logger() } -> std::same_as<typename T::diagnostic_logger_type&>;
+ { ct.logger() } -> std::same_as<const typename T::diagnostic_logger_type&>;
+ };
+
+ template<IsFile FileT>
+ struct FileParseState {
+ using file_type = FileT;
+ using diagnostic_logger_type = BasicDiagnosticLogger<file_type>;
+
+ FileParseState(file_type&& file)
+ : _file { std::move(file) },
+ _logger { file } {}
+
+ FileParseState(lexy::buffer<typename file_type::encoding_type>&& buffer)
+ : FileParseState(file_type { std::move(buffer) }) {}
+
+ FileParseState(const char* path, lexy::buffer<typename file_type::encoding_type>&& buffer)
+ : FileParseState(file_type { path, std::move(buffer) }) {}
+
+ file_type& file() {
+ return _file;
+ }
+
+ const file_type& file() const {
+ return _file;
+ }
+
+ diagnostic_logger_type& logger() {
+ return _logger;
+ }
+
+ const diagnostic_logger_type& logger() const {
+ return _logger;
+ }
+
+ private:
+ file_type _file;
+ diagnostic_logger_type _logger;
+ };
+} \ No newline at end of file
diff --git a/include/openvic-dataloader/detail/BasicParser.hpp b/include/openvic-dataloader/Parser.hpp
index 7524bb5..c1f266b 100644
--- a/include/openvic-dataloader/detail/BasicParser.hpp
+++ b/include/openvic-dataloader/Parser.hpp
@@ -2,15 +2,12 @@
#include <string>
#include <string_view>
-#include <vector>
#include <openvic-dataloader/ParseError.hpp>
#include <openvic-dataloader/ParseWarning.hpp>
-#include <openvic-dataloader/detail/Concepts.hpp>
namespace ovdl::detail {
- class BasicParser {
- public:
+ struct BasicParser {
BasicParser();
void set_error_log_to_null();
@@ -22,16 +19,13 @@ namespace ovdl::detail {
bool has_fatal_error() const;
bool has_warning() const;
- const std::vector<ParseError>& get_errors() const;
- const std::vector<ParseWarning>& get_warnings() const;
std::string_view get_file_path() const;
protected:
- std::vector<ParseError> _errors;
- std::vector<ParseWarning> _warnings;
-
std::reference_wrapper<std::ostream> _error_stream;
std::string _file_path;
bool _has_fatal_error = false;
+ bool _has_error = false;
+ bool _has_warning = false;
};
} \ No newline at end of file
diff --git a/include/openvic-dataloader/csv/LineObject.hpp b/include/openvic-dataloader/csv/LineObject.hpp
index 87b4d31..ca632cd 100644
--- a/include/openvic-dataloader/csv/LineObject.hpp
+++ b/include/openvic-dataloader/csv/LineObject.hpp
@@ -13,7 +13,7 @@
#include <utility>
#include <vector>
-#include <openvic-dataloader/detail/VectorConstexpr.hpp>
+#include <openvic-dataloader/detail/utility/Constexpr.hpp>
namespace ovdl::csv {
/// LineObject should be able to recognize the differences between:
diff --git a/include/openvic-dataloader/csv/Parser.hpp b/include/openvic-dataloader/csv/Parser.hpp
index aa2a0fe..ccf732a 100644
--- a/include/openvic-dataloader/csv/Parser.hpp
+++ b/include/openvic-dataloader/csv/Parser.hpp
@@ -2,8 +2,13 @@
#include <filesystem>
+#include <openvic-dataloader/Error.hpp>
+#include <openvic-dataloader/Parser.hpp>
#include <openvic-dataloader/csv/LineObject.hpp>
-#include <openvic-dataloader/detail/BasicParser.hpp>
+#include <openvic-dataloader/detail/utility/Concepts.hpp>
+#include <openvic-dataloader/detail/utility/ErrorRange.hpp>
+
+#include <dryad/node.hpp>
namespace ovdl::csv {
enum class EncodingType {
@@ -15,6 +20,7 @@ namespace ovdl::csv {
class Parser final : public detail::BasicParser {
public:
Parser();
+ Parser(std::basic_ostream<char>& error_stream);
static Parser from_buffer(const char* data, std::size_t size);
static Parser from_buffer(const char* start, const char* end);
@@ -28,24 +34,33 @@ namespace ovdl::csv {
constexpr Parser& load_from_file(const char* path);
Parser& load_from_file(const std::filesystem::path& path);
- constexpr Parser& load_from_file(const detail::Has_c_str auto& path);
+ constexpr Parser& load_from_file(const detail::HasCstr auto& path) {
+ return load_from_file(path.c_str());
+ }
bool parse_csv(bool handle_strings = false);
const std::vector<csv::LineObject>& get_lines() const;
+ using error_range = ovdl::detail::error_range;
+ Parser::error_range get_errors() const;
+
+ const FilePosition get_error_position(const error::Error* error) const;
+
+ void print_errors_to(std::basic_ostream<char>& stream) const;
+
Parser(Parser&&);
Parser& operator=(Parser&&);
~Parser();
private:
- class BufferHandler;
- std::unique_ptr<BufferHandler> _buffer_handler;
+ class ParseHandler;
+ std::unique_ptr<ParseHandler> _parse_handler;
std::vector<csv::LineObject> _lines;
template<typename... Args>
- constexpr void _run_load_func(detail::LoadCallback<BufferHandler, Args...> auto func, Args... args);
+ constexpr void _run_load_func(detail::LoadCallback<ParseHandler, Args...> auto func, Args... args);
};
using Windows1252Parser = Parser<EncodingType::Windows1252>;
diff --git a/include/openvic-dataloader/detail/CallbackOStream.hpp b/include/openvic-dataloader/detail/CallbackOStream.hpp
index 641d53f..f7cfc4a 100644
--- a/include/openvic-dataloader/detail/CallbackOStream.hpp
+++ b/include/openvic-dataloader/detail/CallbackOStream.hpp
@@ -6,10 +6,10 @@
#include <type_traits>
namespace ovdl::detail {
- template<typename Callback, class CHAR_T, class traits = std::char_traits<CHAR_T>>
- class BasicCallbackStreamBuffer : public std::basic_streambuf<CHAR_T, traits> {
+ template<typename Callback, class CharT, class traits = std::char_traits<CharT>>
+ class BasicCallbackStreamBuffer : public std::basic_streambuf<CharT, traits> {
public:
- using base_type = std::basic_streambuf<CHAR_T, traits>;
+ using base_type = std::basic_streambuf<CharT, traits>;
using callback_type = Callback;
using char_type = typename base_type::char_type;
using int_type = typename base_type::int_type;
@@ -29,11 +29,12 @@ namespace ovdl::detail {
};
int_type overflow(int_type ch) override {
+ auto c = static_cast<char_type>(ch);
if constexpr (std::is_same_v<void, typename decltype(std::function { _callback })::result_type>) {
- _callback(&ch, 1, _user_data);
+ _callback(&c, 1, _user_data);
return 1;
} else {
- return _callback(&ch, 1, _user_data); // returns the number of characters successfully written.
+ return _callback(&c, 1, _user_data); // returns the number of characters successfully written.
}
}
@@ -64,22 +65,28 @@ namespace ovdl::detail {
CallbackWStreamBuffer(Callback cb, void* user_data = nullptr) : base_type(cb, user_data) {}
};
- template<typename Callback, class CHAR_T, class traits = std::char_traits<CHAR_T>>
- class BasicCallbackStream : public std::basic_ostream<CHAR_T, traits> {
+ template<class CharT, typename Callback, class traits = std::char_traits<CharT>>
+ class BasicCallbackStream : public std::basic_ostream<CharT, traits> {
public:
- using base_type = std::basic_ostream<CHAR_T, traits>;
+ using base_type = std::basic_ostream<CharT, traits>;
BasicCallbackStream(Callback cb, void* user_data = nullptr)
: m_sbuf(cb, user_data),
- std::basic_ios<CHAR_T, traits>(&m_sbuf),
- std::basic_ostream<CHAR_T, traits>(&m_sbuf) {
- std::basic_ios<CHAR_T, traits>::init(&m_sbuf);
+ std::basic_ios<CharT, traits>(&m_sbuf),
+ std::basic_ostream<CharT, traits>(&m_sbuf) {
+ std::basic_ios<CharT, traits>::init(&m_sbuf);
}
private:
- BasicCallbackStreamBuffer<Callback, CHAR_T, traits> m_sbuf;
+ BasicCallbackStreamBuffer<Callback, CharT, traits> m_sbuf;
};
+ template<typename CharT>
+ auto make_callback_stream(auto&& cb, void* user_data = nullptr) {
+ using Callback = std::decay_t<decltype(cb)>;
+ return BasicCallbackStream<CharT, Callback> { std::forward<Callback>(cb), user_data };
+ }
+
template<typename Callback>
class CallbackStream : public BasicCallbackStream<Callback, char> {
public:
diff --git a/include/openvic-dataloader/detail/ClassExport.hpp b/include/openvic-dataloader/detail/ClassExport.hpp
deleted file mode 100644
index 27098ed..0000000
--- a/include/openvic-dataloader/detail/ClassExport.hpp
+++ /dev/null
@@ -1,9 +0,0 @@
-#pragma once
-
-#ifdef _MSC_VER
-#define OVDL_EXPORT __declspec(dllexport)
-#elif defined(__GNUC__)
-#define OVDL_EXPORT __attribute__((visibility("default")))
-#else
-#define OVDL_EXPORT
-#endif \ No newline at end of file
diff --git a/include/openvic-dataloader/detail/Concepts.hpp b/include/openvic-dataloader/detail/Concepts.hpp
deleted file mode 100644
index 3ca210c..0000000
--- a/include/openvic-dataloader/detail/Concepts.hpp
+++ /dev/null
@@ -1,21 +0,0 @@
-#pragma once
-
-#include <concepts>
-#include <optional>
-#include <utility>
-
-#include <openvic-dataloader/ParseError.hpp>
-
-namespace ovdl::detail {
- template<typename T, typename Self, typename... Args>
- concept LoadCallback =
- requires(T t, Self* self, Args... args) {
- { t(self, std::forward<Args>(args)...) } -> std::same_as<std::optional<ParseError>>;
- };
-
- template<typename T>
- concept Has_c_str =
- requires(T t) {
- { t.c_str() } -> std::same_as<const char*>;
- };
-} \ No newline at end of file
diff --git a/include/openvic-dataloader/detail/LexyFwdDeclaration.hpp b/include/openvic-dataloader/detail/LexyFwdDeclaration.hpp
new file mode 100644
index 0000000..554c88d
--- /dev/null
+++ b/include/openvic-dataloader/detail/LexyFwdDeclaration.hpp
@@ -0,0 +1,8 @@
+#pragma once
+
+namespace lexy {
+ struct default_encoding;
+
+ template<typename Encoding, typename MemoryResource>
+ struct buffer;
+} \ No newline at end of file
diff --git a/src/openvic-dataloader/detail/LexyReportError.hpp b/include/openvic-dataloader/detail/LexyReportError.hpp
index 213090b..3c32bd1 100644
--- a/src/openvic-dataloader/detail/LexyReportError.hpp
+++ b/include/openvic-dataloader/detail/LexyReportError.hpp
@@ -7,11 +7,12 @@
#include <openvic-dataloader/ParseData.hpp>
#include <openvic-dataloader/ParseError.hpp>
-#include <openvic-dataloader/detail/Concepts.hpp>
#include <lexy/input_location.hpp>
#include <lexy/visualize.hpp>
+#include "openvic-dataloader/detail/utility/Concepts.hpp"
+
#include <lexy_ext/report_error.hpp>
namespace ovdl::detail {
@@ -86,7 +87,7 @@ namespace ovdl::detail {
return { _iter, _opts, path };
}
- constexpr _ReportError path(const detail::Has_c_str auto& path_object) const {
+ constexpr _ReportError path(const detail::HasCstr auto& path_object) const {
return path(path_object.c_str());
}
diff --git a/src/openvic-dataloader/detail/OStreamOutputIterator.hpp b/include/openvic-dataloader/detail/OStreamOutputIterator.hpp
index 81f6c89..8f120c7 100644
--- a/src/openvic-dataloader/detail/OStreamOutputIterator.hpp
+++ b/include/openvic-dataloader/detail/OStreamOutputIterator.hpp
@@ -1,5 +1,6 @@
#pragma once
+#include <memory>
#include <ostream>
namespace ovdl::detail {
diff --git a/include/openvic-dataloader/detail/OptionalConstexpr.hpp b/include/openvic-dataloader/detail/OptionalConstexpr.hpp
deleted file mode 100644
index bcb12a7..0000000
--- a/include/openvic-dataloader/detail/OptionalConstexpr.hpp
+++ /dev/null
@@ -1,9 +0,0 @@
-#pragma once
-
-// THANK YOU APPLE FOR YOUR UTTER DISREGARD FOR C++20
-
-#if __cpp_lib_optional >= 202106L
-#define OVDL_OPTIONAL_CONSTEXPR constexpr
-#else
-#define OVDL_OPTIONAL_CONSTEXPR inline
-#endif \ No newline at end of file
diff --git a/include/openvic-dataloader/detail/utility/Concepts.hpp b/include/openvic-dataloader/detail/utility/Concepts.hpp
new file mode 100644
index 0000000..0ba91cc
--- /dev/null
+++ b/include/openvic-dataloader/detail/utility/Concepts.hpp
@@ -0,0 +1,45 @@
+#pragma once
+
+#include <concepts>
+#include <cstdint>
+#include <functional>
+#include <utility>
+
+namespace ovdl {
+ struct NodeLocation;
+ struct File;
+ namespace detail {
+ enum class buffer_error : std::uint8_t;
+ }
+}
+
+namespace ovdl::detail {
+ template<typename T, typename... Ts>
+ concept any_of = (std::same_as<T, Ts> || ...);
+
+ template<typename T>
+ concept HasCstr =
+ requires(T t) {
+ { t.c_str() } -> std::same_as<const char*>;
+ };
+
+ template<typename T>
+ concept HasPath = requires(T& t) {
+ { t.path() } -> std::same_as<const char*>;
+ };
+
+ template<typename T, typename Self, typename... Args>
+ concept LoadCallback =
+ requires(T&& t, Self&& self, Args&&... args) {
+ { std::invoke(std::forward<T>(t), std::forward<Self>(self), std::forward<Args>(args)...) } -> std::same_as<ovdl::detail::buffer_error>;
+ };
+
+ template<typename T>
+ concept IsEncoding = requires(T t) {
+ typename T::char_type;
+ typename T::int_type;
+ { T::template is_secondary_char_type<typename T::char_type>() } -> std::same_as<bool>;
+ { T::eof() } -> std::same_as<typename T::int_type>;
+ { T::to_int_type(typename T::char_type {}) } -> std::same_as<typename T::int_type>;
+ };
+} \ No newline at end of file
diff --git a/include/openvic-dataloader/detail/VectorConstexpr.hpp b/include/openvic-dataloader/detail/utility/Constexpr.hpp
index 7e7fa34..49479c5 100644
--- a/include/openvic-dataloader/detail/VectorConstexpr.hpp
+++ b/include/openvic-dataloader/detail/utility/Constexpr.hpp
@@ -2,6 +2,12 @@
// THANK YOU APPLE FOR YOUR UTTER DISREGARD FOR C++20
+#if __cpp_lib_optional >= 202106L
+#define OVDL_OPTIONAL_CONSTEXPR constexpr
+#else
+#define OVDL_OPTIONAL_CONSTEXPR inline
+#endif
+
#if __cpp_lib_constexpr_vector >= 201907L
#define OVDL_VECTOR_CONSTEXPR constexpr
#else
diff --git a/include/openvic-dataloader/detail/utility/ErrorRange.hpp b/include/openvic-dataloader/detail/utility/ErrorRange.hpp
new file mode 100644
index 0000000..a427f6c
--- /dev/null
+++ b/include/openvic-dataloader/detail/utility/ErrorRange.hpp
@@ -0,0 +1,11 @@
+#pragma once
+
+#include <utility>
+
+#include <openvic-dataloader/Error.hpp>
+
+#include <dryad/node.hpp>
+
+namespace ovdl::detail {
+ using error_range = decltype(std::declval<const error::Root*>()->errors());
+} \ No newline at end of file
diff --git a/include/openvic-dataloader/detail/PointerHash.hpp b/include/openvic-dataloader/detail/utility/PointerHash.hpp
index c0d28bc..c0d28bc 100644
--- a/include/openvic-dataloader/detail/PointerHash.hpp
+++ b/include/openvic-dataloader/detail/utility/PointerHash.hpp
diff --git a/include/openvic-dataloader/detail/SelfType.hpp b/include/openvic-dataloader/detail/utility/SelfType.hpp
index 5209700..5209700 100644
--- a/include/openvic-dataloader/detail/SelfType.hpp
+++ b/include/openvic-dataloader/detail/utility/SelfType.hpp
diff --git a/include/openvic-dataloader/detail/TypeName.hpp b/include/openvic-dataloader/detail/utility/TypeName.hpp
index 1a34a0f..1a34a0f 100644
--- a/include/openvic-dataloader/detail/TypeName.hpp
+++ b/include/openvic-dataloader/detail/utility/TypeName.hpp
diff --git a/include/openvic-dataloader/detail/utility/Utility.hpp b/include/openvic-dataloader/detail/utility/Utility.hpp
new file mode 100644
index 0000000..138a029
--- /dev/null
+++ b/include/openvic-dataloader/detail/utility/Utility.hpp
@@ -0,0 +1,38 @@
+#pragma once
+
+#include <string_view>
+#include <type_traits>
+
+#include "openvic-dataloader/detail/utility/TypeName.hpp"
+
+namespace ovdl::detail {
+ [[noreturn]] inline void unreachable() {
+ // Uses compiler specific extensions if possible.
+ // Even if no extension is used, undefined behavior is still raised by
+ // an empty function body and the noreturn attribute.
+#ifdef __GNUC__ // GCC, Clang, ICC
+ __builtin_unreachable();
+#elif defined(_MSC_VER) // MSVC
+ __assume(false);
+#endif
+ }
+
+ template<typename Kind>
+ constexpr std::string_view get_kind_name() {
+ constexpr auto name = type_name<Kind>();
+
+ return name;
+ }
+
+ template<typename EnumT>
+ requires std::is_enum_v<EnumT>
+ constexpr std::underlying_type_t<EnumT> to_underlying(EnumT e) {
+ return static_cast<std::underlying_type_t<EnumT>>(e);
+ }
+
+ template<typename EnumT>
+ requires std::is_enum_v<EnumT>
+ constexpr EnumT from_underlying(std::underlying_type_t<EnumT> ut) {
+ return static_cast<EnumT>(ut);
+ }
+} \ No newline at end of file
diff --git a/include/openvic-dataloader/v2script/AbstractSyntaxTree.hpp b/include/openvic-dataloader/v2script/AbstractSyntaxTree.hpp
index 689ab6e..1e7b2c3 100644
--- a/include/openvic-dataloader/v2script/AbstractSyntaxTree.hpp
+++ b/include/openvic-dataloader/v2script/AbstractSyntaxTree.hpp
@@ -1,310 +1,200 @@
#pragma once
-#include <cstddef>
-#include <cstdint>
-#include <iostream>
-#include <memory>
-#include <string>
+#include <cstdio>
#include <string_view>
-#include <type_traits>
-#include <utility>
-#include <vector>
-#include <openvic-dataloader/detail/OptionalConstexpr.hpp>
-#include <openvic-dataloader/detail/SelfType.hpp>
-#include <openvic-dataloader/detail/TypeName.hpp>
+#include <openvic-dataloader/AbstractSyntaxTree.hpp>
+#include <openvic-dataloader/File.hpp>
+#include <openvic-dataloader/NodeLocation.hpp>
+#include <openvic-dataloader/ParseState.hpp>
+#include <openvic-dataloader/detail/LexyFwdDeclaration.hpp>
-namespace lexy {
- struct nullopt;
-}
+#include <dryad/_detail/assert.hpp>
+#include <dryad/_detail/config.hpp>
+#include <dryad/abstract_node.hpp>
+#include <dryad/node.hpp>
+#include <dryad/symbol.hpp>
+#include <dryad/tree.hpp>
-namespace ovdl::v2script {
- class Parser;
-}
+namespace ovdl::v2script::ast {
+ enum class NodeKind {
+ FileTree,
-#define OVDL_PRINT_FUNC_DEF std::ostream& print(std::ostream& stream, std::size_t indent) const override
+ // FlatValues //
+ IdentifierValue, // straight_identifier_value
+ StringValue, // "plain string value"
-// defines get_type_static and get_type for string type naming
-#define OVDL_RT_TYPE_DEF \
- static constexpr std::string_view get_type_static() { return ::ovdl::detail::type_name<type>(); } \
- constexpr std::string_view get_type() const override { return ::ovdl::detail::type_name<std::decay_t<decltype(*this)>>(); }
+ FirstFlatValue = IdentifierValue,
+ LastFlatValue = StringValue,
-// defines type for self-class referencing
-#define OVDL_TYPE_DEFINE_SELF \
- struct _self_type_tag {}; \
- constexpr auto _self_type_helper() -> decltype(::ovdl::detail::Writer<_self_type_tag, decltype(this)> {}); \
- using type = ::ovdl::detail::Read<_self_type_tag>;
+ // Values //
+ ListValue, // { <StatementList> }
+ NullValue,
-namespace ovdl::v2script::ast {
+ FirstValue = FirstFlatValue,
+ LastValue = NullValue,
- struct Node;
- using NodePtr = Node*;
- using NodeCPtr = const Node*;
- using NodeUPtr = std::unique_ptr<Node>;
+ // Statements //
+ EventStatement, // (country_event|province_event) = { id = <FlatValue> ... }
+ AssignStatement, // <IdentifierValue> = <Value>
+ ValueStatement, // <Value>
- struct NodeLocation {
- const char* _begin = nullptr;
- const char* _end = nullptr;
+ FirstStatement = EventStatement,
+ LastStatement = ValueStatement,
+ };
- NodeLocation() = default;
- NodeLocation(const char* pos) : _begin(pos),
- _end(pos) {}
- NodeLocation(const char* begin, const char* end) : _begin(begin),
- _end(end) {}
+ constexpr std::string_view get_kind_name(NodeKind kind) {
+ switch (kind) {
+ using enum NodeKind;
+ case FileTree: return "file tree";
+ case IdentifierValue: return "identifier value";
+ case StringValue: return "string value";
+ case ListValue: return "list value";
+ case NullValue: return "null value";
+ case EventStatement: return "event statement";
+ case AssignStatement: return "assign statement";
+ case ValueStatement: return "value statement";
+ default: detail::unreachable();
+ }
+ }
- NodeLocation(const NodeLocation&) = default;
- NodeLocation& operator=(const NodeLocation&) = default;
+ using Node = dryad::node<NodeKind>;
+ using NodeList = dryad::unlinked_node_list<Node>;
- NodeLocation(NodeLocation&&) = default;
- NodeLocation& operator=(NodeLocation&&) = default;
+ struct Value;
- const char* begin() const { return _begin; }
- const char* end() const { return _end; }
+ struct FlatValue;
+ struct IdentifierValue;
+ struct StringValue;
- static inline NodeLocation make_from(const char* begin, const char* end) {
- end++;
- if (begin >= end) return NodeLocation(begin);
- return NodeLocation(begin, end);
- }
- };
+ struct ListValue;
- struct Node {
- Node(const Node&) = delete;
- Node& operator=(const Node&) = delete;
- Node(NodeLocation location) : _location(location) {}
- Node(Node&&) = default;
- Node& operator=(Node&&) = default;
- virtual ~Node() = default;
+ struct Statement;
+ using StatementList = dryad::unlinked_node_list<Statement>;
- virtual std::ostream& print(std::ostream& stream, std::size_t indent) const = 0;
- static std::ostream& print_ptr(std::ostream& stream, NodeCPtr node, std::size_t indent);
- explicit operator std::string() const;
+ struct EventStatement;
+ using EventStatementList = dryad::unlinked_node_list<EventStatement>;
- static constexpr std::string_view get_type_static() { return detail::type_name<Node>(); }
- constexpr virtual std::string_view get_type() const = 0;
+ struct AssignStatement;
+ using AssignStatementList = dryad::unlinked_node_list<AssignStatement>;
- static constexpr std::string_view get_base_type_static() { return detail::type_name<Node>(); }
- constexpr virtual std::string_view get_base_type() const { return get_base_type_static(); }
+ struct Value : dryad::abstract_node_range<Node, NodeKind::FirstValue, NodeKind::LastValue> {
+ DRYAD_ABSTRACT_NODE_CTOR(Value);
+ };
- template<typename T>
- constexpr bool is_type() const {
- return get_type().compare(detail::type_name<T>()) == 0;
+ struct FlatValue : dryad::abstract_node_range<Value, NodeKind::FirstFlatValue, NodeKind::LastFlatValue> {
+ AbstractSyntaxTree::symbol_type value() const {
+ return _value;
}
- template<typename T>
- constexpr bool is_derived_from() const {
- return is_type<T>() || get_base_type().compare(detail::type_name<T>()) == 0;
+ const char* value(const AbstractSyntaxTree::symbol_interner_type& symbols) const {
+ return _value.c_str(symbols);
}
- template<typename T>
- constexpr T* cast_to() {
- if (is_derived_from<T>() || is_type<Node>()) return (static_cast<T*>(this));
- return nullptr;
- }
+ protected:
+ explicit FlatValue(dryad::node_ctor ctor, NodeKind kind, AbstractSyntaxTree::symbol_type value)
+ : node_base(ctor, kind),
+ _value(value) {}
- template<typename T>
- constexpr const T* const cast_to() const {
- if (is_derived_from<T>() || is_type<Node>()) return (static_cast<const T*>(this));
- return nullptr;
- }
+ protected:
+ AbstractSyntaxTree::symbol_type _value;
+ };
- const NodeLocation location() const { return _location; }
+ struct IdentifierValue : dryad::basic_node<NodeKind::IdentifierValue, FlatValue> {
+ explicit IdentifierValue(dryad::node_ctor ctor, AbstractSyntaxTree::symbol_type value) : node_base(ctor, value) {}
+ };
- struct line_col {
- uint32_t line;
- uint32_t column;
- };
+ struct StringValue : dryad::basic_node<NodeKind::StringValue, FlatValue> {
+ explicit StringValue(dryad::node_ctor ctor, AbstractSyntaxTree::symbol_type value) : node_base(ctor, value) {}
+ };
- private:
- friend class ::ovdl::v2script::Parser;
- const line_col get_begin_line_col(const Parser& parser) const;
- const line_col get_end_line_col(const Parser& parser) const;
+ struct ListValue : dryad::basic_node<NodeKind::ListValue, dryad::container_node<Value>> {
+ explicit ListValue(dryad::node_ctor ctor, StatementList statements);
+ explicit ListValue(dryad::node_ctor ctor, AssignStatementList statements)
+ : node_base(ctor) {
+ insert_child_list_after(nullptr, statements);
+ }
+
+ explicit ListValue(dryad::node_ctor ctor) : ListValue(ctor, StatementList {}) {
+ }
+
+ DRYAD_CHILD_NODE_RANGE_GETTER(Statement, statements, nullptr, this->node_after(_last_statement));
private:
- NodeLocation _location;
+ Node* _last_statement;
};
- inline std::ostream& operator<<(std::ostream& stream, Node const& node) {
- return node.print(stream, 0);
- }
- inline std::ostream& operator<<(std::ostream& stream, NodeCPtr node) {
- return Node::print_ptr(stream, node, 0);
- }
- inline std::ostream& operator<<(std::ostream& stream, Node::line_col const& val) {
- return stream << '(' << val.line << ':' << val.column << ')';
- }
+ struct NullValue : dryad::basic_node<NodeKind::NullValue, Value> {
+ explicit NullValue(dryad::node_ctor ctor) : node_base(ctor) {}
+ };
- template<class T, class... Args>
- NodePtr make_node_ptr(Args&&... args) {
- if constexpr (std::is_pointer_v<NodePtr>) {
- return new T(std::forward<Args>(args)...);
- } else {
- return NodePtr(new T(std::forward<Args>(args)...));
+ struct Statement : dryad::abstract_node_range<dryad::container_node<Node>, NodeKind::FirstStatement, NodeKind::LastStatement> {
+ explicit Statement(dryad::node_ctor ctor, NodeKind kind, Value* right)
+ : node_base(ctor, kind) {
+ insert_child_after(nullptr, right);
}
- }
- template<typename To, typename From>
- To& cast_node_ptr(const From& from) {
- if constexpr (std::is_pointer_v<NodePtr>) {
- return *static_cast<To*>(from);
- } else {
- return *static_cast<To*>(from.get());
+ explicit Statement(dryad::node_ctor ctor, NodeKind kind, Value* left, Value* right)
+ : node_base(ctor, kind) {
+ insert_child_after(nullptr, left);
+ insert_child_after(left, right);
}
- }
+ };
- template<typename To, typename From>
- const To& cast_node_cptr(const From& from) {
- if constexpr (std::is_pointer_v<NodePtr>) {
- return *static_cast<const To*>(from);
- } else {
- return *static_cast<const To*>(from.get());
+ struct EventStatement : dryad::basic_node<NodeKind::EventStatement, Statement> {
+ explicit EventStatement(dryad::node_ctor ctor, bool is_province_event, ListValue* list)
+ : basic_node(ctor, list),
+ _is_province_event(is_province_event) {
}
- }
- void copy_into_node_ptr_vector(const std::vector<NodePtr>& source, std::vector<NodeUPtr>& dest);
-
- struct AbstractStringNode : public Node {
- std::string _name;
- AbstractStringNode();
- AbstractStringNode(std::string&& name, bool allow_newline);
- AbstractStringNode(NodeLocation location);
- AbstractStringNode(NodeLocation location, std::string&& name, bool allow_newline);
- OVDL_TYPE_DEFINE_SELF;
- OVDL_RT_TYPE_DEF;
- OVDL_PRINT_FUNC_DEF;
- static constexpr std::string_view get_base_type_static() { return detail::type_name<AbstractStringNode>(); }
- constexpr std::string_view get_base_type() const override { return ::ovdl::detail::type_name<std::decay_t<decltype(*this)>>(); }
- };
+ bool is_province_event() const { return _is_province_event; }
-#define OVDL_AST_STRING_NODE(NAME) \
- struct NAME final : public AbstractStringNode { \
- NAME(); \
- NAME(std::string&& name, bool allow_newline = true); \
- NAME(lexy::nullopt); \
- NAME(NodeLocation location); \
- NAME(NodeLocation location, std::string&& name, bool allow_newline = true); \
- NAME(NodeLocation location, lexy::nullopt); \
- OVDL_TYPE_DEFINE_SELF; \
- OVDL_RT_TYPE_DEF; \
- OVDL_PRINT_FUNC_DEF; \
- }
+ DRYAD_CHILD_NODE_GETTER(Value, right, nullptr);
- // Value Expression Nodes
- OVDL_AST_STRING_NODE(IdentifierNode);
- OVDL_AST_STRING_NODE(StringNode);
-
- // Assignment Nodes
- OVDL_AST_STRING_NODE(FactorNode);
- OVDL_AST_STRING_NODE(MonthNode);
- OVDL_AST_STRING_NODE(NameNode);
- OVDL_AST_STRING_NODE(FireOnlyNode);
- OVDL_AST_STRING_NODE(IdNode);
- OVDL_AST_STRING_NODE(TitleNode);
- OVDL_AST_STRING_NODE(DescNode);
- OVDL_AST_STRING_NODE(PictureNode);
- OVDL_AST_STRING_NODE(IsTriggeredNode);
-
-#undef OVDL_AST_STRING_NODE
-
- struct AssignNode final : public Node {
- std::string _name;
- NodeUPtr _initializer;
- AssignNode(NodeLocation location, NodeCPtr name, NodePtr init);
- OVDL_TYPE_DEFINE_SELF;
- OVDL_RT_TYPE_DEF;
- OVDL_PRINT_FUNC_DEF;
+ private:
+ bool _is_province_event;
};
- struct AbstractListNode : public Node {
- std::vector<NodeUPtr> _statements;
- AbstractListNode(const std::vector<NodePtr>& statements = std::vector<NodePtr> {});
- AbstractListNode(NodeLocation location, const std::vector<NodePtr>& statements = std::vector<NodePtr> {});
- OVDL_TYPE_DEFINE_SELF;
- OVDL_RT_TYPE_DEF;
- OVDL_PRINT_FUNC_DEF;
- static constexpr std::string_view get_base_type_static() { return detail::type_name<AbstractListNode>(); }
- constexpr std::string_view get_base_type() const override { return ::ovdl::detail::type_name<std::decay_t<decltype(*this)>>(); }
+ struct AssignStatement : dryad::basic_node<NodeKind::AssignStatement, Statement> {
+ explicit AssignStatement(dryad::node_ctor ctor, Value* left, Value* right)
+ : node_base(ctor, left, right) {
+ }
+ DRYAD_CHILD_NODE_GETTER(Value, left, nullptr);
+ DRYAD_CHILD_NODE_GETTER(Value, right, left());
};
-#define OVDL_AST_LIST_NODE(NAME) \
- struct NAME final : public AbstractListNode { \
- NAME(const std::vector<NodePtr>& statements = std::vector<NodePtr> {}); \
- NAME(lexy::nullopt); \
- NAME(NodeLocation location, const std::vector<NodePtr>& statements = std::vector<NodePtr> {}); \
- NAME(NodeLocation location, lexy::nullopt); \
- OVDL_TYPE_DEFINE_SELF; \
- OVDL_RT_TYPE_DEF; \
- OVDL_PRINT_FUNC_DEF; \
- }
-
- OVDL_AST_LIST_NODE(FileNode);
- OVDL_AST_LIST_NODE(ListNode);
-
- OVDL_AST_LIST_NODE(ModifierNode);
- OVDL_AST_LIST_NODE(MtthNode);
- OVDL_AST_LIST_NODE(EventOptionNode);
- OVDL_AST_LIST_NODE(BehaviorListNode);
- OVDL_AST_LIST_NODE(DecisionListNode);
-
-#undef OVDL_AST_LIST_NODE
-
-#define OVDL_AST_LIST_EXTEND(NAME) \
- NAME(lexy::nullopt); \
- NAME(NodeLocation location, lexy::nullopt); \
- OVDL_TYPE_DEFINE_SELF; \
- OVDL_RT_TYPE_DEF; \
- OVDL_PRINT_FUNC_DEF
-
- struct EventNode final : public AbstractListNode {
- OVDL_AST_LIST_EXTEND(EventNode);
- enum class Type {
- Country,
- Province
- } _type;
- EventNode(Type type, const std::vector<NodePtr>& statements = {});
- EventNode(NodeLocation location, Type type, const std::vector<NodePtr>& statements = {});
+ struct ValueStatement : dryad::basic_node<NodeKind::ValueStatement, Statement> {
+ explicit ValueStatement(dryad::node_ctor ctor, Value* value)
+ : node_base(ctor, value) {
+ }
+ DRYAD_CHILD_NODE_GETTER(Value, value, nullptr);
};
- struct DecisionNode final : public AbstractListNode {
- OVDL_AST_LIST_EXTEND(DecisionNode);
- NodeUPtr _name;
- DecisionNode(NodePtr name, const std::vector<NodePtr>& statements = {});
- DecisionNode(NodeLocation location, NodePtr name, const std::vector<NodePtr>& statements = {});
- };
+ struct FileTree : dryad::basic_node<NodeKind::FileTree, dryad::container_node<Node>> {
+ explicit FileTree(dryad::node_ctor ctor, StatementList statements);
+ explicit FileTree(dryad::node_ctor ctor, AssignStatementList statements) : node_base(ctor) {
+ insert_child_list_after(nullptr, statements);
+ }
- struct EventMtthModifierNode final : public AbstractListNode {
- OVDL_AST_LIST_EXTEND(EventMtthModifierNode);
- NodeUPtr _factor_value;
- EventMtthModifierNode() : AbstractListNode() {}
- EventMtthModifierNode(NodeLocation location) : AbstractListNode(location) {}
- };
+ explicit FileTree(dryad::node_ctor ctor) : FileTree(ctor, StatementList {}) {
+ }
- // Packed single case
- struct ExecutionNode final : public Node {
- enum class Type {
- Effect,
- Trigger
- } _type;
- NodeUPtr _name;
- NodeUPtr _initializer;
- ExecutionNode(Type type, NodePtr name, NodePtr init);
- ExecutionNode(NodeLocation location, Type type, NodePtr name, NodePtr init);
- OVDL_TYPE_DEFINE_SELF;
- OVDL_RT_TYPE_DEF;
- OVDL_PRINT_FUNC_DEF;
- };
+ DRYAD_CHILD_NODE_RANGE_GETTER(Statement, statements, nullptr, this->node_after(_last_node));
- struct ExecutionListNode final : public AbstractListNode {
- OVDL_AST_LIST_EXTEND(ExecutionListNode);
- ExecutionNode::Type _type;
- ExecutionListNode(ExecutionNode::Type type, const std::vector<NodePtr>& statements);
- ExecutionListNode(NodeLocation location, ExecutionNode::Type type, const std::vector<NodePtr>& statements);
+ private:
+ Node* _last_node;
};
-#undef OVDL_AST_LIST_EXTEND
+ using File = ovdl::BasicFile<lexy::default_encoding, Node>;
+ struct AbstractSyntaxTree : ovdl::BasicAbstractSyntaxTree<File, FileTree> {
+ using BasicAbstractSyntaxTree::BasicAbstractSyntaxTree;
-}
+ std::string make_list_visualizer() const;
+ std::string make_native_visualizer() const;
+ };
+ using ParseState = ovdl::ParseState<AbstractSyntaxTree>;
-#undef OVDL_PRINT_FUNC_DECL
-#undef OVDL_PRINT_FUNC_DEF
-#undef OVDL_TYPE_DEFINE_SELF \ No newline at end of file
+ static_assert(IsFile<ast::File>, "File failed IsFile concept");
+ static_assert(IsAst<ast::AbstractSyntaxTree>, "AbstractSyntaxTree failed IsAst concept");
+ static_assert(IsParseState<ast::ParseState>, "ParseState failed IsParseState concept");
+} \ No newline at end of file
diff --git a/include/openvic-dataloader/v2script/NodeLocationMap.hpp b/include/openvic-dataloader/v2script/NodeLocationMap.hpp
deleted file mode 100644
index aa88d62..0000000
--- a/include/openvic-dataloader/v2script/NodeLocationMap.hpp
+++ /dev/null
@@ -1,91 +0,0 @@
-#pragma once
-
-#include <unordered_map>
-
-#include <openvic-dataloader/detail/PointerHash.hpp>
-#include <openvic-dataloader/v2script/AbstractSyntaxTree.hpp>
-
-#include <lexy/input_location.hpp>
-
-namespace ovdl::v2script::ast {
- // TODO: FOR THE LOVE OF GOD USE A DIFFERENT HASH MULTIMAP TYPE
- // See src/openvic-dataloader/v2script/Parser.cpp#252
- template<typename Input>
- struct NodeLocationMap : public std::unordered_multimap<NodeCPtr, const lexy::input_location<Input>, detail::PointerHash<Node>> {
- NodeLocationMap() = default;
- NodeLocationMap(const Input& input, const Node& top_node) {
- generate_location_map(input, top_node);
- }
-
- NodeLocationMap(const NodeLocationMap&) = default;
- NodeLocationMap(NodeLocationMap&&) = default;
-
- NodeLocationMap& operator=(const NodeLocationMap&) = default;
- NodeLocationMap& operator=(NodeLocationMap&&) = default;
-
- lexy::input_location_anchor<Input> generate_location_map(const Input& input, NodeCPtr node);
- lexy::input_location_anchor<Input> generate_location_map(const Input& input, NodeCPtr node, lexy::input_location_anchor<Input> anchor);
- lexy::input_location_anchor<Input> generate_begin_location_for(const Input& input, NodeCPtr node, lexy::input_location_anchor<Input> anchor);
- lexy::input_location_anchor<Input> generate_end_location_for(const Input& input, NodeCPtr node, lexy::input_location_anchor<Input> anchor);
- };
-
- template<typename Input>
- constexpr const lexy::input_location<Input> make_begin_loc(const NodeLocation location, const Input& input, lexy::input_location_anchor<Input> anchor) {
- return lexy::get_input_location(input, location.begin(), anchor);
- }
-
- template<typename Input>
- constexpr const lexy::input_location<Input> make_begin_loc(const NodeLocation location, const Input& input) {
- return lexy::get_input_location(input, location.begin());
- }
-
- template<typename Input>
- constexpr const lexy::input_location<Input> make_end_loc(const NodeLocation location, const Input& input, lexy::input_location_anchor<Input> anchor) {
- return lexy::get_input_location(input, location.end(), anchor);
- }
-
- template<typename Input>
- constexpr const lexy::input_location<Input> make_end_loc(const NodeLocation location, const Input& input) {
- return lexy::get_input_location(input, location.end());
- }
-}
-
-namespace ovdl::v2script::ast {
- template<typename Input>
- lexy::input_location_anchor<Input> NodeLocationMap<Input>::generate_location_map(const Input& input, NodeCPtr node) {
- return generate_location_map(input, node, lexy::input_location_anchor(input));
- }
-
- template<typename Input>
- lexy::input_location_anchor<Input> NodeLocationMap<Input>::generate_location_map(const Input& input, NodeCPtr node, lexy::input_location_anchor<Input> anchor) {
- if (!node) return anchor;
- anchor = generate_begin_location_for(input, node, anchor);
- if (auto list_node = node->cast_to<ast::AbstractListNode>(); list_node) {
- for (auto& inner_node : list_node->_statements) {
- anchor = generate_location_map(input, inner_node.get(), anchor);
- }
- } else if (auto assign_node = node->cast_to<ast::AssignNode>(); assign_node) {
- anchor = generate_location_map(input, assign_node->_initializer.get(), anchor);
- }
- // TODO: implement for EventNode, DecisionNode, EventMtthModifierNode, ExecutionNode, ExecutionListNode
- if (!node->location().end() || node->location().begin() >= node->location().end())
- return anchor;
- return generate_end_location_for(input, node, anchor);
- }
-
- template<typename Input>
- lexy::input_location_anchor<Input> NodeLocationMap<Input>::generate_begin_location_for(const Input& input, NodeCPtr node, lexy::input_location_anchor<Input> anchor) {
- if (node->location().begin() == nullptr) return anchor;
- lexy::input_location<Input> next_loc = make_begin_loc(node->location(), input, anchor);
- this->emplace(node, next_loc);
- return next_loc.anchor();
- }
-
- template<typename Input>
- lexy::input_location_anchor<Input> NodeLocationMap<Input>::generate_end_location_for(const Input& input, NodeCPtr node, lexy::input_location_anchor<Input> anchor) {
- if (node->location().end() == nullptr) return anchor;
- lexy::input_location<Input> next_loc = make_end_loc(node->location(), input, anchor);
- this->emplace(node, next_loc);
- return next_loc.anchor();
- }
-} \ No newline at end of file
diff --git a/include/openvic-dataloader/v2script/Parser.hpp b/include/openvic-dataloader/v2script/Parser.hpp
index 885946d..cef1faf 100644
--- a/include/openvic-dataloader/v2script/Parser.hpp
+++ b/include/openvic-dataloader/v2script/Parser.hpp
@@ -3,21 +3,26 @@
#include <cstddef>
#include <filesystem>
#include <memory>
+#include <ostream>
+#include <string>
#include <string_view>
-#include <openvic-dataloader/ParseError.hpp>
-#include <openvic-dataloader/ParseWarning.hpp>
-#include <openvic-dataloader/detail/BasicParser.hpp>
-#include <openvic-dataloader/detail/Concepts.hpp>
+#include <openvic-dataloader/Error.hpp>
+#include <openvic-dataloader/NodeLocation.hpp>
+#include <openvic-dataloader/Parser.hpp>
+#include <openvic-dataloader/detail/utility/Concepts.hpp>
#include <openvic-dataloader/v2script/AbstractSyntaxTree.hpp>
-namespace ovdl::v2script {
+#include <dryad/node.hpp>
- using FileNode = ast::FileNode;
+namespace ovdl::v2script {
+ using FileTree = ast::FileTree;
+ using FilePosition = ovdl::FilePosition;
class Parser final : public detail::BasicParser {
public:
Parser();
+ Parser(std::basic_ostream<char>& error_stream);
static Parser from_buffer(const char* data, std::size_t size);
static Parser from_buffer(const char* start, const char* end);
@@ -31,19 +36,30 @@ namespace ovdl::v2script {
constexpr Parser& load_from_file(const char* path);
Parser& load_from_file(const std::filesystem::path& path);
- constexpr Parser& load_from_file(const detail::Has_c_str auto& path);
+ constexpr Parser& load_from_file(const detail::HasCstr auto& path) {
+ return load_from_file(path.c_str());
+ }
bool simple_parse();
bool event_parse();
bool decision_parse();
bool lua_defines_parse();
- const FileNode* get_file_node() const;
+ const FileTree* get_file_node() const;
+
+ std::string_view value(const ovdl::v2script::ast::FlatValue& node) const;
+
+ std::string make_native_string() const;
+ std::string make_list_string() const;
+
+ const FilePosition get_position(const ast::Node* node) const;
+
+ using error_range = ovdl::detail::error_range;
+ Parser::error_range get_errors() const;
- void generate_node_location_map();
+ const FilePosition get_error_position(const error::Error* error) const;
- const ast::Node::line_col get_node_begin(const ast::NodeCPtr node) const;
- const ast::Node::line_col get_node_end(const ast::NodeCPtr node) const;
+ void print_errors_to(std::basic_ostream<char>& stream) const;
Parser(Parser&&);
Parser& operator=(Parser&&);
@@ -51,12 +67,10 @@ namespace ovdl::v2script {
~Parser();
private:
- friend class ::ovdl::v2script::ast::Node;
- class BufferHandler;
- std::unique_ptr<BufferHandler> _buffer_handler;
- std::unique_ptr<FileNode> _file_node;
+ class ParseHandler;
+ std::unique_ptr<ParseHandler> _parse_handler;
template<typename... Args>
- constexpr void _run_load_func(detail::LoadCallback<BufferHandler, Args...> auto func, Args... args);
+ constexpr void _run_load_func(detail::LoadCallback<Parser::ParseHandler*, Args...> auto func, Args... args);
};
} \ No newline at end of file
diff --git a/src/headless/main.cpp b/src/headless/main.cpp
index 688b479..7279a6e 100644
--- a/src/headless/main.cpp
+++ b/src/headless/main.cpp
@@ -12,6 +12,11 @@
#include <openvic-dataloader/v2script/AbstractSyntaxTree.hpp>
#include <openvic-dataloader/v2script/Parser.hpp>
+enum class VisualizationType {
+ Native, // <name> = { <contents> }
+ List // - <type> : <multiline contents>
+};
+
std::string_view trim(std::string_view str) {
std::string_view::iterator begin = str.begin();
std::string_view::iterator end = str.end();
@@ -38,7 +43,8 @@ bool insenitive_trim_eq(std::string_view lhs, std::string_view rhs) {
template<ovdl::csv::EncodingType Encoding>
int print_csv(const std::string_view path) {
- auto parser = ovdl::csv::Parser<Encoding>::from_file(path);
+ auto parser = ovdl::csv::Parser<Encoding>(std::cerr);
+ parser.load_from_file(path);
if (parser.has_error()) {
return 1;
}
@@ -49,9 +55,7 @@ int print_csv(const std::string_view path) {
}
if (parser.has_warning()) {
- for (auto& warning : parser.get_warnings()) {
- std::cerr << "Warning: " << warning.message << std::endl;
- }
+ parser.print_errors_to(std::cerr);
}
std::cout << "lines:\t\t" << parser.get_lines().size() << std::endl;
@@ -62,8 +66,9 @@ int print_csv(const std::string_view path) {
return EXIT_SUCCESS;
}
-int print_lua(const std::string_view path) {
- auto parser = ovdl::v2script::Parser::from_file(path);
+int print_lua(const std::string_view path, VisualizationType visual_type) {
+ auto parser = ovdl::v2script::Parser(std::cerr);
+ parser.load_from_file(path);
if (parser.has_error()) {
return 1;
}
@@ -74,32 +79,20 @@ int print_lua(const std::string_view path) {
}
if (parser.has_warning()) {
- for (auto& warning : parser.get_warnings()) {
- std::cerr << "Warning: " << warning.message << std::endl;
- }
+ parser.print_errors_to(std::cerr);
}
- parser.generate_node_location_map();
-
- for (const auto& node : parser.get_file_node()->_statements) {
- std::cout << node->get_type() << ": " << parser.get_node_begin(node.get()) << std::endl;
- if (auto assign_node = node->cast_to<ovdl::v2script::ast::AssignNode>(); assign_node) {
- auto lnode_ptr = assign_node->_initializer.get();
- std::cout << lnode_ptr->get_type() << " begin: " << parser.get_node_begin(lnode_ptr) << std::endl;
- std::cout << lnode_ptr->get_type() << " end: " << parser.get_node_end(lnode_ptr) << std::endl;
- if (auto list_node = lnode_ptr->cast_to<ovdl::v2script::ast::AbstractListNode>(); list_node) {
- for (const auto& inode : list_node->_statements) {
- std::cout << inode->get_type() << ": " << parser.get_node_begin(inode.get()) << std::endl;
- }
- }
- }
+ switch (visual_type) {
+ using enum VisualizationType;
+ case Native: std::cout << parser.make_native_string() << '\n'; break;
+ case List: std::cout << parser.make_list_string() << '\n'; break;
}
- std::cout << parser.get_file_node() << std::endl;
return EXIT_SUCCESS;
}
-int print_v2script_simple(const std::string_view path) {
- auto parser = ovdl::v2script::Parser::from_file(path);
+int print_v2script_simple(const std::string_view path, VisualizationType visual_type) {
+ auto parser = ovdl::v2script::Parser(std::cerr);
+ parser.load_from_file(path);
if (parser.has_error()) {
return 1;
}
@@ -110,50 +103,59 @@ int print_v2script_simple(const std::string_view path) {
}
if (parser.has_warning()) {
- for (auto& warning : parser.get_warnings()) {
- std::cerr << "Warning: " << warning.message << std::endl;
- }
+ parser.print_errors_to(std::cerr);
}
- parser.generate_node_location_map();
-
- for (const auto& node : parser.get_file_node()->_statements) {
- std::cout << node->get_type() << ": " << parser.get_node_begin(node.get()) << std::endl;
- if (auto assign_node = node->cast_to<ovdl::v2script::ast::AssignNode>(); assign_node) {
- auto lnode_ptr = assign_node->_initializer.get();
- std::cout << lnode_ptr->get_type() << " begin: " << parser.get_node_begin(lnode_ptr) << std::endl;
- std::cout << lnode_ptr->get_type() << " end: " << parser.get_node_end(lnode_ptr) << std::endl;
- if (auto list_node = lnode_ptr->cast_to<ovdl::v2script::ast::AbstractListNode>(); list_node) {
- for (const auto& inode : list_node->_statements) {
- std::cout << inode->get_type() << ": " << parser.get_node_begin(inode.get()) << std::endl;
- }
- }
- }
+ switch (visual_type) {
+ using enum VisualizationType;
+ case Native: std::cout << parser.make_native_string() << '\n'; break;
+ case List: std::cout << parser.make_list_string() << '\n'; break;
}
- std::cout << parser.get_file_node() << std::endl;
return EXIT_SUCCESS;
}
int main(int argc, char** argv) {
- switch (argc) {
+ std::vector<std::string> args;
+ args.reserve(argc);
+ for (size_t index = 0; index < argc; index++) {
+ args.push_back(argv[index]);
+ }
+
+ VisualizationType type = VisualizationType::Native;
+ if (args.size() >= 2) {
+ std::string_view type_str = args[1];
+ if (insenitive_trim_eq(type_str, "list")) {
+ type = VisualizationType::List;
+ args.erase(args.begin() + 1);
+ } else if (insenitive_trim_eq(type_str, "native")) {
+ type = VisualizationType::Native;
+ args.erase(args.begin() + 1);
+ }
+ }
+
+ switch (args.size()) {
case 2:
- if (insenitive_trim_eq(std::filesystem::path(argv[1]).extension().string(), ".lua")) {
- return print_lua(argv[1]);
+ if (insenitive_trim_eq(std::filesystem::path(args[1]).extension().string(), ".lua")) {
+ return print_lua(args[1], type);
}
- return print_v2script_simple(argv[1]);
+ return print_v2script_simple(args[1], type);
case 4:
- if (insenitive_trim_eq(argv[1], "csv") && insenitive_trim_eq(argv[2], "utf"))
- return print_csv<ovdl::csv::EncodingType::Utf8>(argv[3]);
+ if (insenitive_trim_eq(args[1], "csv") && insenitive_trim_eq(args[2], "utf"))
+ return print_csv<ovdl::csv::EncodingType::Utf8>(args[3]);
goto default_jump;
case 3:
- if (insenitive_trim_eq(argv[1], "csv"))
- return print_csv<ovdl::csv::EncodingType::Windows1252>(argv[2]);
+ if (insenitive_trim_eq(args[1], "csv"))
+ return print_csv<ovdl::csv::EncodingType::Windows1252>(args[2]);
+ if (insenitive_trim_eq(args[1], "lua"))
+ return print_lua(args[2], type);
[[fallthrough]];
default:
default_jump:
- std::fprintf(stderr, "usage: %s <filename>\n", argv[0]);
- std::fprintf(stderr, "usage: %s csv <filename>\n", argv[0]);
- std::fprintf(stderr, "usage: %s csv utf <filename>", argv[0]);
+ std::fprintf(stderr, "usage: %s <filename>\n", args[0].c_str());
+ std::fprintf(stderr, "usage: %s list <options> <filename>\n", args[0].c_str());
+ std::fprintf(stderr, "usage: %s native <options> <filename>\n", args[0].c_str());
+ std::fprintf(stderr, "usage: %s lua <filename>\n", args[0].c_str());
+ std::fprintf(stderr, "usage: %s csv [utf] <filename>\n", args[0].c_str());
return EXIT_FAILURE;
}
diff --git a/src/openvic-dataloader/AbstractSyntaxTree.cpp b/src/openvic-dataloader/AbstractSyntaxTree.cpp
new file mode 100644
index 0000000..11a90dc
--- /dev/null
+++ b/src/openvic-dataloader/AbstractSyntaxTree.cpp
@@ -0,0 +1,27 @@
+#include <openvic-dataloader/AbstractSyntaxTree.hpp>
+
+using namespace ovdl;
+
+AbstractSyntaxTree::symbol_type AbstractSyntaxTree::intern(const char* str, std::size_t length) {
+ return _symbol_interner.intern(str, length);
+}
+
+AbstractSyntaxTree::symbol_type AbstractSyntaxTree::intern(std::string_view str) {
+ return intern(str.data(), str.size());
+}
+
+const char* AbstractSyntaxTree::intern_cstr(const char* str, std::size_t length) {
+ return intern(str, length).c_str(_symbol_interner);
+}
+
+const char* AbstractSyntaxTree::intern_cstr(std::string_view str) {
+ return intern_cstr(str.data(), str.size());
+}
+
+AbstractSyntaxTree::symbol_interner_type& AbstractSyntaxTree::symbol_interner() {
+ return _symbol_interner;
+}
+
+const AbstractSyntaxTree::symbol_interner_type& AbstractSyntaxTree::symbol_interner() const {
+ return _symbol_interner;
+} \ No newline at end of file
diff --git a/src/openvic-dataloader/DiagnosticLogger.cpp b/src/openvic-dataloader/DiagnosticLogger.cpp
new file mode 100644
index 0000000..aae3dcb
--- /dev/null
+++ b/src/openvic-dataloader/DiagnosticLogger.cpp
@@ -0,0 +1,16 @@
+#include <openvic-dataloader/DiagnosticLogger.hpp>
+
+using namespace ovdl;
+
+DiagnosticLogger::operator bool() const {
+ return !_errored;
+}
+
+bool DiagnosticLogger::errored() const { return _errored; }
+bool DiagnosticLogger::warned() const { return _warned; }
+
+
+NodeLocation DiagnosticLogger::location_of(const error::Error* error) const {
+ auto result = _map.lookup(error);
+ return result ? *result : NodeLocation{};
+} \ No newline at end of file
diff --git a/src/openvic-dataloader/File.cpp b/src/openvic-dataloader/File.cpp
new file mode 100644
index 0000000..9b27bf0
--- /dev/null
+++ b/src/openvic-dataloader/File.cpp
@@ -0,0 +1,9 @@
+#include <openvic-dataloader/File.hpp>
+
+using namespace ovdl;
+
+File::File(const char* path) : _path(path) {}
+
+const char* File::path() const noexcept {
+ return _path;
+} \ No newline at end of file
diff --git a/src/openvic-dataloader/NodeLocation.cpp b/src/openvic-dataloader/NodeLocation.cpp
new file mode 100644
index 0000000..9e4f669
--- /dev/null
+++ b/src/openvic-dataloader/NodeLocation.cpp
@@ -0,0 +1,26 @@
+#include <openvic-dataloader/NodeLocation.hpp>
+
+using namespace ovdl;
+
+NodeLocation::NodeLocation() = default;
+NodeLocation::NodeLocation(const char* pos) : _begin(pos),
+ _end(pos) {}
+NodeLocation::NodeLocation(const char* begin, const char* end) : _begin(begin),
+ _end(end) {}
+
+NodeLocation::NodeLocation(const NodeLocation&) noexcept = default;
+NodeLocation& NodeLocation::operator=(const NodeLocation&) = default;
+
+NodeLocation::NodeLocation(NodeLocation&&) = default;
+NodeLocation& NodeLocation::operator=(NodeLocation&&) = default;
+
+const char* NodeLocation::begin() const { return _begin; }
+const char* NodeLocation::end() const { return _end; }
+
+bool NodeLocation::is_synthesized() const { return _begin == nullptr && _end == nullptr; }
+
+NodeLocation NodeLocation::make_from(const char* begin, const char* end) {
+ end++;
+ if (begin >= end) return NodeLocation(begin);
+ return NodeLocation(begin, end);
+}
diff --git a/src/openvic-dataloader/csv/CsvGrammar.hpp b/src/openvic-dataloader/csv/CsvGrammar.hpp
index 712bddc..5451f26 100644
--- a/src/openvic-dataloader/csv/CsvGrammar.hpp
+++ b/src/openvic-dataloader/csv/CsvGrammar.hpp
@@ -7,14 +7,17 @@
#include <vector>
#include <openvic-dataloader/csv/LineObject.hpp>
+#include <openvic-dataloader/csv/Parser.hpp>
#include <lexy/callback.hpp>
#include <lexy/dsl.hpp>
-#include "detail/LexyLitRange.hpp"
+#include "detail/dsl.hpp"
// Grammar Definitions //
namespace ovdl::csv::grammar {
+ using EncodingType = ovdl::csv::EncodingType;
+
template<typename T>
concept ParseChars = requires() {
{ T::character };
@@ -51,123 +54,117 @@ namespace ovdl::csv::grammar {
.map<'"'>('"');
template<ParseOptions Options>
- struct StringValue {
- static constexpr auto rule = [] {
- // Arbitrary code points
- auto c = Options.character - Options.control;
-
- auto back_escape = lexy::dsl::backslash_escape //
- .symbol<escaped_symbols>();
+ struct CsvGrammar {
+ struct StringValue {
+ static constexpr auto rule = [] {
+ // Arbitrary code points
+ auto c = Options.character - Options.control;
- auto quote_escape = lexy::dsl::escape(lexy::dsl::lit_c<'"'>) //
- .template symbol<escaped_quote>();
+ auto back_escape = lexy::dsl::backslash_escape //
+ .symbol<escaped_symbols>();
- return lexy::dsl::delimited(lexy::dsl::lit_c<'"'>, lexy::dsl::not_followed_by(lexy::dsl::lit_c<'"'>, lexy::dsl::lit_c<'"'>))(c, back_escape, quote_escape);
- }();
-
- static constexpr auto value = lexy::as_string<std::string>;
- };
+ auto quote_escape = lexy::dsl::escape(lexy::dsl::lit_c<'"'>) //
+ .template symbol<escaped_quote>();
- template<ParseOptions Options>
- struct PlainValue {
- static constexpr auto rule = [] {
- if constexpr (Options.SupportStrings) {
- return lexy::dsl::identifier(Options.character - (lexy::dsl::lit_b<Options.SepChar> / lexy::dsl::ascii::newline));
- } else {
- auto escape_check_char = Options.character - (lexy::dsl::lit_b<Options.SepChar> / lexy::dsl::ascii::newline);
- auto id_check_char = escape_check_char - lexy::dsl::lit_b<'\\'>;
- auto id_segment = lexy::dsl::identifier(id_check_char);
- auto escape_segement = lexy::dsl::token(escape_check_char);
- auto escape_sym = lexy::dsl::symbol<escaped_symbols>(escape_segement);
- auto escape_rule = lexy::dsl::lit_b<'\\'> >> escape_sym;
- return lexy::dsl::list(id_segment | escape_rule);
- }
- }();
- static constexpr auto value = lexy::as_string<std::string>;
- };
+ return lexy::dsl::delimited(lexy::dsl::lit_c<'"'>, lexy::dsl::not_followed_by(lexy::dsl::lit_c<'"'>, lexy::dsl::lit_c<'"'>))(c, back_escape, quote_escape);
+ }();
- template<ParseOptions Options>
- struct Value {
- static constexpr auto rule = [] {
- if constexpr (Options.SupportStrings) {
- return lexy::dsl::p<StringValue<Options>> | lexy::dsl::p<PlainValue<Options>>;
- } else {
- return lexy::dsl::p<PlainValue<Options>>;
- }
- }();
- static constexpr auto value = lexy::forward<std::string>;
- };
-
- template<ParseOptions Options>
- struct SepConst {
- static constexpr auto rule = lexy::dsl::lit_b<Options.SepChar>;
- static constexpr auto value = lexy::constant(1);
- };
+ static constexpr auto value = lexy::as_string<std::string>;
+ };
- template<ParseOptions Options>
- struct Seperator {
- static constexpr auto rule = lexy::dsl::list(lexy::dsl::p<SepConst<Options>>);
- static constexpr auto value = lexy::count;
- };
+ struct PlainValue {
+ static constexpr auto rule = [] {
+ if constexpr (Options.SupportStrings) {
+ return lexy::dsl::identifier(Options.character - (lexy::dsl::lit_b<Options.SepChar> / lexy::dsl::ascii::newline));
+ } else {
+ auto escape_check_char = Options.character - (lexy::dsl::lit_b<Options.SepChar> / lexy::dsl::ascii::newline);
+ auto id_check_char = escape_check_char - lexy::dsl::lit_b<'\\'>;
+ auto id_segment = lexy::dsl::identifier(id_check_char);
+ auto escape_segement = lexy::dsl::token(escape_check_char);
+ auto escape_sym = lexy::dsl::symbol<escaped_symbols>(escape_segement);
+ auto escape_rule = lexy::dsl::lit_b<'\\'> >> escape_sym;
+ return lexy::dsl::list(id_segment | escape_rule);
+ }
+ }();
+ static constexpr auto value = lexy::as_string<std::string>;
+ };
- template<ParseOptions Options>
- struct LineEnd {
- static constexpr auto rule = lexy::dsl::list(lexy::dsl::p<Value<Options>>, lexy::dsl::trailing_sep(lexy::dsl::p<Seperator<Options>>));
- static constexpr auto value = lexy::fold_inplace<ovdl::csv::LineObject>(
- std::initializer_list<ovdl::csv::LineObject::value_type> {},
- [](ovdl::csv::LineObject& result, auto&& arg) {
- if constexpr (std::is_same_v<std::decay_t<decltype(arg)>, std::size_t>) {
- // Count seperators, adds to previous value, making it a position
- using position_type = ovdl::csv::LineObject::position_type;
- result.emplace_back(static_cast<position_type>(arg + result.back().first), "");
+ struct Value {
+ static constexpr auto rule = [] {
+ if constexpr (Options.SupportStrings) {
+ return lexy::dsl::p<StringValue> | lexy::dsl::p<PlainValue>;
} else {
- if (result.empty()) result.emplace_back(0u, LEXY_MOV(arg));
- else {
- auto& [pos, value] = result.back();
- value = arg;
- }
+ return lexy::dsl::p<PlainValue>;
}
- });
- };
+ }();
+ static constexpr auto value = lexy::forward<std::string>;
+ };
- template<ParseOptions Options>
- struct Line {
- static constexpr auto suffix_setter(ovdl::csv::LineObject& line) {
- auto& [position, value] = line.back();
- if (value.empty()) {
- line.set_suffix_end(position);
- line.pop_back();
- } else {
- line.set_suffix_end(position + 1);
- }
+ struct SepConst {
+ static constexpr auto rule = lexy::dsl::lit_b<Options.SepChar>;
+ static constexpr auto value = lexy::constant(1);
};
- static constexpr auto rule = lexy::dsl::p<LineEnd<Options>> | lexy::dsl::p<Seperator<Options>> >> lexy::dsl::opt(lexy::dsl::p<LineEnd<Options>>);
- static constexpr auto value =
- lexy::callback<ovdl::csv::LineObject>(
- [](ovdl::csv::LineObject&& line) {
- suffix_setter(line);
- return LEXY_MOV(line);
- },
- [](std::size_t prefix_count, ovdl::csv::LineObject&& line) {
- line.set_prefix_end(prefix_count);
- // position needs to be adjusted to prefix
- for (auto& [position, value] : line) {
- position += prefix_count;
+ struct Seperator {
+ static constexpr auto rule = lexy::dsl::list(lexy::dsl::p<SepConst>);
+ static constexpr auto value = lexy::count;
+ };
+
+ struct LineEnd {
+ static constexpr auto rule = lexy::dsl::list(lexy::dsl::p<Value>, lexy::dsl::trailing_sep(lexy::dsl::p<Seperator>));
+ static constexpr auto value = lexy::fold_inplace<ovdl::csv::LineObject>(
+ std::initializer_list<ovdl::csv::LineObject::value_type> {},
+ [](ovdl::csv::LineObject& result, auto&& arg) {
+ if constexpr (std::is_same_v<std::decay_t<decltype(arg)>, std::size_t>) {
+ // Count seperators, adds to previous value, making it a position
+ using position_type = ovdl::csv::LineObject::position_type;
+ result.emplace_back(static_cast<position_type>(arg + result.back().first), "");
+ } else {
+ if (result.empty()) result.emplace_back(0u, LEXY_MOV(arg));
+ else {
+ auto& [pos, value] = result.back();
+ value = arg;
+ }
}
- suffix_setter(line);
- return LEXY_MOV(line);
- },
- [](std::size_t suffix_count, lexy::nullopt = {}) {
- return ovdl::csv::LineObject(0, {}, suffix_count + 1);
});
+ };
+
+ struct Line {
+ static constexpr auto suffix_setter(ovdl::csv::LineObject& line) {
+ auto& [position, value] = line.back();
+ if (value.empty()) {
+ line.set_suffix_end(position);
+ line.pop_back();
+ } else {
+ line.set_suffix_end(position + 1);
+ }
+ };
+
+ static constexpr auto rule = lexy::dsl::p<LineEnd> | lexy::dsl::p<Seperator> >> lexy::dsl::opt(lexy::dsl::p<LineEnd>);
+ static constexpr auto value =
+ lexy::callback<ovdl::csv::LineObject>(
+ [](ovdl::csv::LineObject&& line) {
+ suffix_setter(line);
+ return LEXY_MOV(line);
+ },
+ [](std::size_t prefix_count, ovdl::csv::LineObject&& line) {
+ line.set_prefix_end(prefix_count);
+ // position needs to be adjusted to prefix
+ for (auto& [position, value] : line) {
+ position += prefix_count;
+ }
+ suffix_setter(line);
+ return LEXY_MOV(line);
+ },
+ [](std::size_t suffix_count, lexy::nullopt = {}) {
+ return ovdl::csv::LineObject(0, {}, suffix_count + 1);
+ });
+ };
};
template<ParseOptions Options>
struct File {
- static constexpr auto rule = lexy::dsl::terminator(lexy::dsl::eof).opt_list(
- lexy::dsl::p<Line<Options>> | lexy::dsl::newline
- );
+ static constexpr auto rule = lexy::dsl::terminator(lexy::dsl::eof).opt_list(lexy::dsl::p<typename CsvGrammar<Options>::Line> | lexy::dsl::newline);
static constexpr auto value = lexy::as_list<std::vector<ovdl::csv::LineObject>>;
};
@@ -199,7 +196,7 @@ namespace ovdl::csv::grammar {
namespace ovdl::csv::grammar::windows1252 {
struct windows1252_t {
- static constexpr auto character = detail::lexydsl::make_range<0x01, 0xFF>();
+ static constexpr auto character = dsl::make_range<0x01, 0xFF>();
static constexpr auto control =
lexy::dsl::ascii::control /
lexy::dsl::lit_b<0x81> / lexy::dsl::lit_b<0x8D> / lexy::dsl::lit_b<0x8F> /
diff --git a/src/openvic-dataloader/csv/CsvParseState.hpp b/src/openvic-dataloader/csv/CsvParseState.hpp
new file mode 100644
index 0000000..2390453
--- /dev/null
+++ b/src/openvic-dataloader/csv/CsvParseState.hpp
@@ -0,0 +1,28 @@
+#pragma once
+
+#include <openvic-dataloader/File.hpp>
+#include <openvic-dataloader/ParseState.hpp>
+#include <openvic-dataloader/csv/LineObject.hpp>
+#include <openvic-dataloader/csv/Parser.hpp>
+
+#include <lexy/encoding.hpp>
+
+template<ovdl::csv::EncodingType>
+struct LexyEncodingFrom {
+};
+
+template<>
+struct LexyEncodingFrom<ovdl::csv::EncodingType::Windows1252> {
+ using encoding = lexy::default_encoding;
+};
+
+template<>
+struct LexyEncodingFrom<ovdl::csv::EncodingType::Utf8> {
+ using encoding = lexy::utf8_char_encoding;
+};
+
+template<ovdl::csv::EncodingType Encoding>
+using CsvFile = ovdl::BasicFile<typename LexyEncodingFrom<Encoding>::encoding, std::vector<ovdl::csv::LineObject>>;
+
+template<ovdl::csv::EncodingType Encoding>
+using CsvParseState = ovdl::FileParseState<CsvFile<Encoding>>; \ No newline at end of file
diff --git a/src/openvic-dataloader/csv/Parser.cpp b/src/openvic-dataloader/csv/Parser.cpp
index 0ca3402..849ea05 100644
--- a/src/openvic-dataloader/csv/Parser.cpp
+++ b/src/openvic-dataloader/csv/Parser.cpp
@@ -1,47 +1,34 @@
-#include <memory>
#include <vector>
+#include <openvic-dataloader/File.hpp>
#include <openvic-dataloader/csv/LineObject.hpp>
#include <openvic-dataloader/csv/Parser.hpp>
-#include <openvic-dataloader/detail/ClassExport.hpp>
+#include <openvic-dataloader/detail/LexyReportError.hpp>
+#include <openvic-dataloader/detail/OStreamOutputIterator.hpp>
+#include <openvic-dataloader/detail/utility/Utility.hpp>
#include <lexy/action/parse.hpp>
#include <lexy/encoding.hpp>
#include <lexy/input/buffer.hpp>
#include <lexy/input/file.hpp>
-#include "csv/CsvGrammar.hpp"
-#include "detail/BasicBufferHandler.hpp"
-#include "detail/LexyReportError.hpp"
-#include "detail/OStreamOutputIterator.hpp"
+#include "CsvGrammar.hpp"
+#include "CsvParseState.hpp"
+#include "detail/NullBuff.hpp"
+#include "detail/ParseHandler.hpp"
using namespace ovdl;
using namespace ovdl::csv;
-/// BufferHandler ///
-
-template<EncodingType>
-struct LexyEncodingFrom {
-};
-
-template<>
-struct LexyEncodingFrom<EncodingType::Windows1252> {
- using encoding = lexy::default_encoding;
-};
-
-template<>
-struct LexyEncodingFrom<EncodingType::Utf8> {
- using encoding = lexy::utf8_char_encoding;
-};
+/// ParseHandler ///
template<EncodingType Encoding>
-class Parser<Encoding>::BufferHandler final : public detail::BasicBufferHandler<typename LexyEncodingFrom<Encoding>::encoding> {
-public:
- template<typename Node, typename ErrorCallback>
- std::optional<std::vector<ParseError>> parse(const ErrorCallback& callback) {
- auto result = lexy::parse<Node>(this->_buffer, callback);
+struct Parser<Encoding>::ParseHandler final : detail::BasicFileParseHandler<CsvParseState<Encoding>> {
+ template<typename Node>
+ std::optional<DiagnosticLogger::error_range> parse() {
+ auto result = lexy::parse<Node>(this->buffer(), *this->_parse_state, this->_parse_state->logger().error_callback());
if (!result) {
- return result.errors();
+ return this->_parse_state->logger().get_errors();
}
_lines = std::move(result.value());
return std::nullopt;
@@ -59,8 +46,14 @@ private:
template<EncodingType Encoding>
Parser<Encoding>::Parser()
- : _buffer_handler(std::make_unique<BufferHandler>()) {
- set_error_log_to_stderr();
+ : _parse_handler(std::make_unique<ParseHandler>()) {
+ set_error_log_to_null();
+}
+
+template<EncodingType Encoding>
+Parser<Encoding>::Parser(std::basic_ostream<char>& error_stream)
+ : _parse_handler(std::make_unique<ParseHandler>()) {
+ set_error_log_to(error_stream);
}
template<EncodingType Encoding>
@@ -115,28 +108,31 @@ Parser<Encoding> Parser<Encoding>::from_file(const std::filesystem::path& path)
///
template<EncodingType Encoding>
template<typename... Args>
-constexpr void Parser<Encoding>::_run_load_func(detail::LoadCallback<BufferHandler, Args...> auto func, Args... args) {
- _warnings.clear();
- _errors.clear();
+constexpr void Parser<Encoding>::_run_load_func(detail::LoadCallback<ParseHandler, Args...> auto func, Args... args) {
_has_fatal_error = false;
- if (auto error = func(_buffer_handler.get(), std::forward<Args>(args)...); error) {
- _has_fatal_error = error.value().type == ParseError::Type::Fatal;
- _errors.push_back(error.value());
- _error_stream.get() << "Error: " << _errors.back().message << '\n';
+ auto error = func(_parse_handler.get(), std::forward<Args>(args)...);
+ auto error_message = _parse_handler->make_error_from(error);
+ if (!error_message.empty()) {
+ _has_error = true;
+ _has_fatal_error = true;
+ _parse_handler->parse_state().logger().template create_log<error::BufferError>(DiagnosticLogger::DiagnosticKind::error, fmt::runtime(error_message));
+ }
+ if (has_error() && &_error_stream.get() != &detail::cnull) {
+ print_errors_to(_error_stream.get());
}
}
template<EncodingType Encoding>
constexpr Parser<Encoding>& Parser<Encoding>::load_from_buffer(const char* data, std::size_t size) {
// Type can't be deduced?
- _run_load_func(std::mem_fn(&BufferHandler::load_buffer_size), data, size);
+ _run_load_func(std::mem_fn(&ParseHandler::load_buffer_size), data, size);
return *this;
}
template<EncodingType Encoding>
constexpr Parser<Encoding>& Parser<Encoding>::load_from_buffer(const char* start, const char* end) {
// Type can't be deduced?
- _run_load_func(std::mem_fn(&BufferHandler::load_buffer), start, end);
+ _run_load_func(std::mem_fn(&ParseHandler::load_buffer), start, end);
return *this;
}
@@ -149,7 +145,7 @@ template<EncodingType Encoding>
constexpr Parser<Encoding>& Parser<Encoding>::load_from_file(const char* path) {
_file_path = path;
// Type can be deduced??
- _run_load_func(std::mem_fn(&BufferHandler::load_file), path);
+ _run_load_func(std::mem_fn(&ParseHandler::load_file), path);
return *this;
}
@@ -159,38 +155,34 @@ Parser<Encoding>& Parser<Encoding>::load_from_file(const std::filesystem::path&
}
template<EncodingType Encoding>
-constexpr Parser<Encoding>& Parser<Encoding>::load_from_file(const detail::Has_c_str auto& path) {
- return load_from_file(path.c_str());
-}
-
-template<EncodingType Encoding>
bool Parser<Encoding>::parse_csv(bool handle_strings) {
- if (!_buffer_handler->is_valid()) {
+ if (!_parse_handler->is_valid()) {
return false;
}
- std::optional<std::vector<ParseError>> errors;
- auto report_error = ovdl::detail::ReporError.path(_file_path).to(detail::OStreamOutputIterator { _error_stream });
+ std::optional<Parser<Encoding>::error_range> errors;
+ // auto report_error = ovdl::detail::ReporError.path(_file_path).to(detail::OStreamOutputIterator { _error_stream });
if constexpr (Encoding == EncodingType::Windows1252) {
if (handle_strings)
- errors = _buffer_handler->template parse<csv::grammar::windows1252::strings::SemiColonFile>(report_error);
+ errors = _parse_handler->template parse<csv::grammar::windows1252::strings::SemiColonFile>();
else
- errors = _buffer_handler->template parse<csv::grammar::windows1252::SemiColonFile>(report_error);
+ errors = _parse_handler->template parse<csv::grammar::windows1252::SemiColonFile>();
} else {
if (handle_strings)
- errors = _buffer_handler->template parse<csv::grammar::utf8::strings::SemiColonFile>(report_error);
+ errors = _parse_handler->template parse<csv::grammar::utf8::strings::SemiColonFile>();
else
- errors = _buffer_handler->template parse<csv::grammar::utf8::SemiColonFile>(report_error);
+ errors = _parse_handler->template parse<csv::grammar::utf8::SemiColonFile>();
}
- if (errors) {
- _errors.reserve(errors->size());
- for (auto& err : errors.value()) {
- _has_fatal_error |= err.type == ParseError::Type::Fatal;
- _errors.push_back(err);
+ _has_error = _parse_handler->parse_state().logger().errored();
+ _has_warning = _parse_handler->parse_state().logger().warned();
+ if (!errors->empty()) {
+ _has_fatal_error = true;
+ if (&_error_stream.get() != &detail::cnull) {
+ print_errors_to(_error_stream);
}
return false;
}
- _lines = std::move(_buffer_handler->get_lines());
+ _lines = std::move(_parse_handler->get_lines());
return true;
}
@@ -199,5 +191,60 @@ const std::vector<csv::LineObject>& Parser<Encoding>::get_lines() const {
return _lines;
}
+template<EncodingType Encoding>
+typename Parser<Encoding>::error_range Parser<Encoding>::get_errors() const {
+ return _parse_handler->parse_state().logger().get_errors();
+}
+
+template<EncodingType Encoding>
+const FilePosition Parser<Encoding>::get_error_position(const error::Error* error) const {
+ if (!error || !error->is_linked_in_tree()) {
+ return {};
+ }
+ auto err_location = _parse_handler->parse_state().logger().location_of(error);
+ if (err_location.is_synthesized()) {
+ return {};
+ }
+
+ auto loc_begin = lexy::get_input_location(_parse_handler->buffer(), err_location.begin());
+ FilePosition result { loc_begin.line_nr(), loc_begin.line_nr(), loc_begin.column_nr(), loc_begin.column_nr() };
+ if (err_location.begin() < err_location.end()) {
+ auto loc_end = lexy::get_input_location(_parse_handler->buffer(), err_location.end(), loc_begin.anchor());
+ result.end_line = loc_end.line_nr();
+ result.end_column = loc_end.column_nr();
+ }
+ return result;
+}
+
+template<EncodingType Encoding>
+void Parser<Encoding>::print_errors_to(std::basic_ostream<char>& stream) const {
+ auto errors = get_errors();
+ if (errors.empty()) return;
+ for (const auto error : errors) {
+ dryad::visit_tree(
+ error,
+ [&](const error::BufferError* buffer_error) {
+ stream << buffer_error->message() << '\n';
+ },
+ [&](const error::ParseError* parse_error) {
+ stream << parse_error->message() << '\n';
+ },
+ [&](dryad::child_visitor<error::ErrorKind> visitor, const error::Semantic* semantic) {
+ stream << semantic->message() << '\n';
+ auto annotations = semantic->annotations();
+ if (annotations.empty()) return;
+ for (auto annotation : annotations) {
+ visitor(annotation);
+ }
+ },
+ [&](const error::PrimaryAnnotation* primary) {
+ stream << primary->message() << '\n';
+ },
+ [&](const error::SecondaryAnnotation* secondary) {
+ stream << secondary->message() << '\n';
+ });
+ }
+}
+
template class ovdl::csv::Parser<EncodingType::Windows1252>;
template class ovdl::csv::Parser<EncodingType::Utf8>; \ No newline at end of file
diff --git a/src/openvic-dataloader/detail/BasicBufferHandler.hpp b/src/openvic-dataloader/detail/BasicBufferHandler.hpp
deleted file mode 100644
index f26544b..0000000
--- a/src/openvic-dataloader/detail/BasicBufferHandler.hpp
+++ /dev/null
@@ -1,51 +0,0 @@
-#pragma once
-
-#include <optional>
-
-#include <openvic-dataloader/ParseError.hpp>
-#include <openvic-dataloader/detail/OptionalConstexpr.hpp>
-
-#include <lexy/encoding.hpp>
-#include <lexy/input/buffer.hpp>
-#include <lexy/input/file.hpp>
-
-#include "detail/Errors.hpp"
-
-namespace ovdl::detail {
- template<typename Encoding = lexy::default_encoding, typename MemoryResource = void>
- class BasicBufferHandler {
- public:
- using encoding_type = Encoding;
-
- OVDL_OPTIONAL_CONSTEXPR bool is_valid() const {
- return _buffer.data() != nullptr;
- }
-
- OVDL_OPTIONAL_CONSTEXPR std::optional<ovdl::ParseError> load_buffer_size(const char* data, std::size_t size) {
- _buffer = lexy::buffer<Encoding, MemoryResource>(data, size);
- return std::nullopt;
- }
-
- OVDL_OPTIONAL_CONSTEXPR std::optional<ovdl::ParseError> load_buffer(const char* start, const char* end) {
- _buffer = lexy::buffer<Encoding, MemoryResource>(start, end);
- return std::nullopt;
- }
-
- std::optional<ovdl::ParseError> load_file(const char* path) {
- auto file = lexy::read_file<Encoding, lexy::encoding_endianness::bom, MemoryResource>(path);
- if (!file) {
- return ovdl::errors::make_no_file_error(path);
- }
-
- _buffer = file.buffer();
- return std::nullopt;
- }
-
- const auto& get_buffer() const {
- return _buffer;
- }
-
- protected:
- lexy::buffer<Encoding, MemoryResource> _buffer;
- };
-} \ No newline at end of file
diff --git a/src/openvic-dataloader/detail/BufferError.hpp b/src/openvic-dataloader/detail/BufferError.hpp
new file mode 100644
index 0000000..1fbb0f4
--- /dev/null
+++ b/src/openvic-dataloader/detail/BufferError.hpp
@@ -0,0 +1,17 @@
+#pragma once
+
+#include <cstdint>
+
+namespace ovdl::detail {
+ enum class buffer_error : std::uint8_t {
+ success,
+ /// An internal OS error, such as failure to read from the file.
+ os_error,
+ /// The file was not found.
+ file_not_found,
+ /// The file cannot be opened.
+ permission_denied,
+ /// The buffer failed to handle the data
+ buffer_is_null
+ };
+} \ No newline at end of file
diff --git a/src/openvic-dataloader/detail/DetectUtf8.hpp b/src/openvic-dataloader/detail/DetectUtf8.hpp
index 2045b3c..e9d0350 100644
--- a/src/openvic-dataloader/detail/DetectUtf8.hpp
+++ b/src/openvic-dataloader/detail/DetectUtf8.hpp
@@ -3,7 +3,7 @@
#include <lexy/action/match.hpp>
#include <lexy/dsl.hpp>
-#include "detail/LexyLitRange.hpp"
+#include "detail/dsl.hpp"
namespace ovdl::detail {
namespace detect_utf8 {
@@ -18,15 +18,15 @@ namespace ovdl::detail {
constexpr auto is_not_ascii_flag = lexy::dsl::context_flag<DetectUtf8>;
// & 0b10000000 == 0b00000000
- constexpr auto ascii_values = lexydsl::make_range<0b00000000, 0b01111111>();
+ constexpr auto ascii_values = dsl::make_range<0b00000000, 0b01111111>();
// & 0b11100000 == 0b11000000
- constexpr auto two_byte = lexydsl::make_range<0b11000000, 0b11011111>();
+ constexpr auto two_byte = dsl::make_range<0b11000000, 0b11011111>();
// & 0b11110000 == 0b11100000
- constexpr auto three_byte = lexydsl::make_range<0b11100000, 0b11101111>();
+ constexpr auto three_byte = dsl::make_range<0b11100000, 0b11101111>();
// & 0b11111000 == 0b11110000
- constexpr auto four_byte = lexydsl::make_range<0b11110000, 0b11110111>();
+ constexpr auto four_byte = dsl::make_range<0b11110000, 0b11110111>();
// & 0b11000000 == 0b10000000
- constexpr auto check_bytes = lexydsl::make_range<0b10000000, 0b10111111>();
+ constexpr auto check_bytes = dsl::make_range<0b10000000, 0b10111111>();
constexpr auto utf8_check =
((four_byte >> lexy::dsl::times<3>(check_bytes)) |
diff --git a/src/openvic-dataloader/detail/LexyLitRange.hpp b/src/openvic-dataloader/detail/LexyLitRange.hpp
deleted file mode 100644
index a6761a8..0000000
--- a/src/openvic-dataloader/detail/LexyLitRange.hpp
+++ /dev/null
@@ -1,16 +0,0 @@
-#pragma once
-
-#include <lexy/dsl/literal.hpp>
-
-namespace ovdl::detail::lexydsl {
- template<unsigned char LOW, unsigned char HIGH>
- consteval auto make_range() {
- if constexpr (LOW == HIGH) {
- return lexy::dsl::lit_c<LOW>;
- } else if constexpr (LOW == (HIGH - 1)) {
- return lexy::dsl::lit_c<LOW> / lexy::dsl::lit_c<HIGH>;
- } else {
- return lexy::dsl::lit_c<LOW> / make_range<LOW + 1, HIGH>();
- }
- }
-} \ No newline at end of file
diff --git a/src/openvic-dataloader/detail/NullBuff.hpp b/src/openvic-dataloader/detail/NullBuff.hpp
index baf9e1b..e5c6f4a 100644
--- a/src/openvic-dataloader/detail/NullBuff.hpp
+++ b/src/openvic-dataloader/detail/NullBuff.hpp
@@ -22,9 +22,9 @@ namespace ovdl::detail {
basic_nullbuf<cT, traits> m_sbuf;
};
- typedef basic_onullstream<char> onullstream;
- typedef basic_onullstream<wchar_t> wonullstream;
+ using onullstream = basic_onullstream<char>;
+ using wonullstream = basic_onullstream<wchar_t>;
- inline onullstream cnull;
- inline onullstream wcnull;
+ static inline onullstream cnull;
+ static inline onullstream wcnull;
} \ No newline at end of file
diff --git a/src/openvic-dataloader/detail/ParseHandler.hpp b/src/openvic-dataloader/detail/ParseHandler.hpp
new file mode 100644
index 0000000..fbec0d7
--- /dev/null
+++ b/src/openvic-dataloader/detail/ParseHandler.hpp
@@ -0,0 +1,145 @@
+#pragma once
+
+#include <utility>
+
+#include <openvic-dataloader/ParseState.hpp>
+#include <openvic-dataloader/detail/utility/Concepts.hpp>
+
+#include <lexy/encoding.hpp>
+#include <lexy/input/buffer.hpp>
+#include <lexy/input/file.hpp>
+
+#include "detail/BufferError.hpp"
+
+namespace ovdl::detail {
+ template<typename Derived>
+ struct ParseHandler {
+ std::string make_error_from(buffer_error error) {
+ switch (error) {
+ using enum ovdl::detail::buffer_error;
+ case buffer_is_null:
+ return "Buffer could not be loaded.";
+ case os_error:
+ return "OS file error.";
+ case file_not_found:
+ return "File not found.";
+ case permission_denied:
+ return "Read Permission denied.";
+ default:
+ return "";
+ }
+ }
+
+ template<typename... Args>
+ constexpr void _run_load_func(detail::LoadCallback<Derived, Args...> auto func, Args... args);
+ };
+
+ template<IsFileParseState ParseState, typename MemoryResource = void>
+ struct BasicFileParseHandler : ParseHandler<BasicFileParseHandler<ParseState, MemoryResource>> {
+ using parse_state_type = ParseState;
+ using encoding_type = typename parse_state_type::file_type::encoding_type;
+
+ constexpr bool is_valid() const {
+ if (!_parse_state) return false;
+ return buffer().data() != nullptr;
+ }
+
+ constexpr buffer_error load_buffer_size(const char* data, std::size_t size) {
+ lexy::buffer<encoding_type, MemoryResource> buffer(data, size);
+ if (buffer.data() == nullptr) return buffer_error::buffer_is_null;
+ _parse_state.reset(new parse_state_type { std::move(buffer) });
+ return is_valid() ? buffer_error::success : buffer_error::buffer_is_null;
+ }
+
+ constexpr buffer_error load_buffer(const char* start, const char* end) {
+ lexy::buffer<encoding_type, MemoryResource> buffer(start, end);
+ if (buffer.data() == nullptr) return buffer_error::buffer_is_null;
+ _parse_state.reset(new parse_state_type { std::move(buffer) });
+ return is_valid() ? buffer_error::success : buffer_error::buffer_is_null;
+ }
+
+ buffer_error load_file(const char* path) {
+ lexy::read_file_result file = lexy::read_file<encoding_type, lexy::encoding_endianness::bom, MemoryResource>(path);
+ if (!file) {
+ _parse_state.reset(new parse_state_type { path, lexy::buffer<typename parse_state_type::file_type::encoding_type>() });
+ return ovdl::detail::from_underlying<buffer_error>(ovdl::detail::to_underlying(file.error()));
+ }
+ _parse_state.reset(new parse_state_type { path, std::move(file).buffer() });
+ return is_valid() ? buffer_error::success : buffer_error::buffer_is_null;
+ }
+
+ const char* path() const {
+ if (!_parse_state) return "";
+ return _parse_state->file().path();
+ }
+
+ parse_state_type& parse_state() {
+ return *_parse_state;
+ }
+
+ const parse_state_type& parse_state() const {
+ return *_parse_state;
+ }
+
+ constexpr const auto& buffer() const {
+ return _parse_state->file().buffer();
+ }
+
+ protected:
+ std::unique_ptr<parse_state_type> _parse_state;
+ };
+
+ template<IsParseState ParseState, typename MemoryResource = void>
+ struct BasicStateParseHandler : ParseHandler<BasicStateParseHandler<ParseState, MemoryResource>> {
+ using parse_state_type = ParseState;
+ using encoding_type = typename parse_state_type::ast_type::file_type::encoding_type;
+
+ constexpr bool is_valid() const {
+ if (!_parse_state) return false;
+ return buffer().data() != nullptr;
+ }
+
+ constexpr buffer_error load_buffer_size(const char* data, std::size_t size) {
+ lexy::buffer<encoding_type, MemoryResource> buffer(data, size);
+ _parse_state.reset(new parse_state_type { std::move(buffer) });
+ return is_valid() ? buffer_error::success : buffer_error::buffer_is_null;
+ }
+
+ constexpr buffer_error load_buffer(const char* start, const char* end) {
+ lexy::buffer<encoding_type, MemoryResource> buffer(start, end);
+ _parse_state.reset(new parse_state_type { std::move(buffer) });
+ return is_valid() ? buffer_error::success : buffer_error::buffer_is_null;
+ }
+
+ buffer_error load_file(const char* path) {
+ lexy::read_file_result file = lexy::read_file<encoding_type, lexy::encoding_endianness::bom, MemoryResource>(path);
+ if (!file) {
+ _parse_state.reset(new parse_state_type { path, lexy::buffer<typename parse_state_type::ast_type::file_type::encoding_type>() });
+ return ovdl::detail::from_underlying<buffer_error>(ovdl::detail::to_underlying(file.error()));
+ }
+
+ _parse_state.reset(new parse_state_type { path, std::move(file).buffer() });
+ return is_valid() ? buffer_error::success : buffer_error::buffer_is_null;
+ }
+
+ const char* path() const {
+ if (!_parse_state) return "";
+ return _parse_state->ast().file().path();
+ }
+
+ parse_state_type& parse_state() {
+ return *_parse_state;
+ }
+
+ const parse_state_type& parse_state() const {
+ return *_parse_state;
+ }
+
+ constexpr const auto& buffer() const {
+ return _parse_state->ast().file().buffer();
+ }
+
+ protected:
+ std::unique_ptr<parse_state_type> _parse_state;
+ };
+} \ No newline at end of file
diff --git a/src/openvic-dataloader/detail/BasicParser.cpp b/src/openvic-dataloader/detail/Parser.cpp
index 212bf00..fd87687 100644
--- a/src/openvic-dataloader/detail/BasicParser.cpp
+++ b/src/openvic-dataloader/detail/Parser.cpp
@@ -1,7 +1,7 @@
#include <iostream>
#include <ostream>
-#include <openvic-dataloader/detail/BasicParser.hpp>
+#include <openvic-dataloader/Parser.hpp>
#include "detail/NullBuff.hpp"
@@ -27,7 +27,7 @@ void BasicParser::set_error_log_to(std::basic_ostream<char>& stream) {
}
bool BasicParser::has_error() const {
- return !_errors.empty();
+ return _has_error;
}
bool BasicParser::has_fatal_error() const {
@@ -35,15 +35,7 @@ bool BasicParser::has_fatal_error() const {
}
bool BasicParser::has_warning() const {
- return !_warnings.empty();
-}
-
-const std::vector<ovdl::ParseError>& BasicParser::get_errors() const {
- return _errors;
-}
-
-const std::vector<ovdl::ParseWarning>& BasicParser::get_warnings() const {
- return _warnings;
+ return _has_warning;
}
std::string_view BasicParser::get_file_path() const {
diff --git a/src/openvic-dataloader/detail/StringLiteral.hpp b/src/openvic-dataloader/detail/StringLiteral.hpp
new file mode 100644
index 0000000..985b087
--- /dev/null
+++ b/src/openvic-dataloader/detail/StringLiteral.hpp
@@ -0,0 +1,232 @@
+#pragma once
+
+#include <algorithm>
+#include <array>
+#include <cstddef>
+#include <string>
+#include <string_view>
+#include <type_traits>
+
+#include <lexy/_detail/config.hpp>
+#include <lexy/_detail/integer_sequence.hpp>
+#include <lexy/dsl/identifier.hpp>
+
+namespace ovdl::detail {
+
+ template<std::size_t N, typename CharT>
+ struct string_literal;
+
+ struct _string_literal {
+ protected:
+ static constexpr auto _to_string(const auto& input) { return string_literal(input); }
+ static constexpr auto _concat(const auto&... input) { return string_literal(_to_string(input)...); }
+ };
+
+ template<std::size_t N, typename CharT = char>
+ struct string_literal : _string_literal {
+ using value_type = CharT;
+ using pointer = value_type*;
+ using const_pointer = const value_type*;
+ using reference = value_type&;
+ using const_reference = const value_type&;
+ using size_type = std::size_t;
+ using difference_type = std::ptrdiff_t;
+ using traits_type = std::char_traits<value_type>;
+
+ static constexpr size_type npos = size_type(-1);
+
+ static constexpr auto size = std::integral_constant<std::size_t, N - 1> {};
+ static constexpr auto length = size;
+
+ value_type _data[N];
+
+ constexpr string_literal() noexcept = default;
+
+ constexpr string_literal(const value_type (&literal)[N]) noexcept {
+ for (auto i = 0u; i != N; i++)
+ _data[i] = literal[i];
+ }
+
+ constexpr string_literal(value_type c) noexcept : _data {} {
+ _data[0] = c;
+ }
+
+ constexpr auto begin() noexcept { return std::begin(_data); }
+ constexpr auto end() noexcept { return std::end(_data); }
+ constexpr auto cbegin() const noexcept { return std::cbegin(_data); }
+ constexpr auto cend() const noexcept { return std::cend(_data); }
+ constexpr auto rbegin() noexcept { return std::rbegin(_data); }
+ constexpr auto rend() noexcept { return std::rend(_data); }
+ constexpr auto crbegin() const noexcept { return std::crbegin(_data); }
+ constexpr auto crend() const noexcept { return std::crend(_data); }
+
+ constexpr auto front() const noexcept { return as_string_view().front(); }
+ constexpr auto back() const noexcept { return as_string_view().back(); }
+ constexpr auto at(size_type pos) const { return as_string_view().at(pos); }
+
+ constexpr auto operator[](size_type pos) const noexcept { return as_string_view()[pos]; }
+
+ constexpr bool empty() const { return as_string_view().empty(); }
+
+ template<size_type N2>
+ constexpr bool operator==(const string_literal<N2, value_type>& other) const {
+ return as_string_view() == other.as_string_view();
+ }
+
+ constexpr bool starts_with(std::basic_string_view<value_type> sv) const noexcept { return as_string_view().starts_with(sv); }
+ constexpr bool starts_with(value_type ch) const noexcept { return as_string_view().starts_with(ch); }
+ constexpr bool starts_with(const value_type* s) const { return as_string_view().starts_with(s); }
+
+ template<size_type N2>
+ constexpr bool starts_with(const string_literal<N2, value_type>& other) const {
+ return starts_with(other.as_string_view());
+ }
+
+ constexpr bool ends_with(std::basic_string_view<value_type> sv) const noexcept { return as_string_view().ends_with(sv); }
+ constexpr bool ends_with(value_type ch) const noexcept { return as_string_view().ends_with(ch); }
+ constexpr bool ends_with(const value_type* s) const { return as_string_view().ends_with(s); }
+
+ template<size_type N2>
+ constexpr bool ends_with(const string_literal<N2, value_type>& other) const {
+ return ends_with(other.as_string_view());
+ }
+
+ constexpr auto clear() const noexcept {
+ return string_literal<0, value_type> {};
+ }
+
+ constexpr auto push_back(value_type c) const noexcept {
+ return *this + string_literal { c };
+ }
+
+ constexpr auto pop_back() const noexcept {
+ string_literal<N - 1, value_type> result {};
+ for (auto i = 0u; i != N - 2; i++)
+ result._data[i] = _data[i];
+ return result;
+ }
+
+ template<size_type count>
+ constexpr auto append(value_type ch) const noexcept {
+ string_literal<N + count, value_type> result {};
+ for (auto i = 0u; i != N; i++)
+ result._data[i] = _data[i];
+
+ for (auto i = N; i != N + count; i++)
+ result._data[i] = ch;
+
+ return result;
+ }
+
+ template<size_type N2>
+ constexpr auto append(string_literal<N2, value_type> str) const noexcept {
+ return *this + str;
+ }
+
+ template<size_type N2>
+ constexpr auto append(const value_type (&literal)[N2]) const noexcept {
+ return *this + literal;
+ }
+
+ template<size_type pos = 0, size_type count = npos>
+ constexpr auto substr() const noexcept {
+ static_assert(pos <= N, "pos must be less than or equal to N");
+ constexpr size_type result_size = std::min(count - pos, N - pos);
+
+ string_literal<result_size, value_type> result {};
+ for (size_type i = 0u, i2 = pos; i != result_size; i++, i2++)
+ result._data[i] = _data[i2];
+ return result;
+ }
+
+ constexpr auto substr() const noexcept {
+ return substr<>();
+ }
+
+ constexpr std::string_view substr(size_type pos, size_type count = npos) const noexcept {
+ return as_string_view().substr(pos, count);
+ }
+
+ constexpr size_type find(std::string_view str, size_type pos = 0) const noexcept {
+ return as_string_view().find(str, pos);
+ }
+
+ template<size_type N2>
+ constexpr size_type find(const value_type (&literal)[N2], size_type pos = 0) const noexcept {
+ return as_string_view().find(literal, pos, N2 - 2);
+ }
+
+ constexpr size_type rfind(std::string_view str, size_type pos = 0) const noexcept {
+ return as_string_view().rfind(str, pos);
+ }
+
+ template<size_type N2>
+ constexpr size_type rfind(const value_type (&literal)[N2], size_type pos = 0) const noexcept {
+ return as_string_view().find(literal, pos, N2 - 2);
+ }
+
+ constexpr int compare(std::string_view str) const noexcept {
+ return as_string_view().compare(str);
+ }
+
+ template<size_type N2>
+ constexpr int compare(const value_type (&literal)[N2]) const noexcept {
+ return as_string_view().compare(0, N, literal, N2 - 2);
+ }
+
+ constexpr operator std::basic_string_view<value_type>() const& { return as_string_view(); }
+ constexpr operator std::basic_string_view<value_type>() const&& = delete;
+
+ constexpr std::basic_string_view<value_type> as_string_view() const& { return std::basic_string_view<value_type>(_data, size() - 1); }
+ constexpr std::basic_string_view<value_type> as_string_view() const&& = delete;
+
+ constexpr operator const value_type*() const& { return c_str(); }
+ constexpr operator const value_type*() const&& = delete;
+
+ constexpr const value_type* c_str() const& { return _data; }
+ constexpr const value_type* c_str() const&& = delete;
+
+ constexpr const value_type* data() const& { return _data; }
+ constexpr const value_type* data() const&& = delete;
+
+ template<size_type N2>
+ constexpr auto operator+(const string_literal<N2, value_type>& other) const noexcept {
+ string_literal<N + N2 - 1, value_type> result {};
+ for (size_type i = 0u; i != N; i++)
+ result._data[i] = _data[i];
+
+ for (size_type i = N - 1, i2 = 0; i2 != N2; i++, i2++)
+ result._data[i] = other._data[i2];
+ return result;
+ }
+
+ template<size_type N2>
+ constexpr auto operator+(const value_type (&rhs)[N2]) const noexcept {
+ return *this + _to_string(rhs);
+ }
+
+ template<size_type N2>
+ friend constexpr auto operator+(const value_type (&lhs)[N2], string_literal<N, value_type> rhs) noexcept {
+ return _to_string(lhs) + rhs;
+ }
+ };
+ template<std::size_t N, typename CharT = char>
+ string_literal(const CharT (&)[N]) -> string_literal<N, CharT>;
+
+ template<typename CharT = char>
+ string_literal(CharT) -> string_literal<1, CharT>;
+
+ template<template<typename C, C... Cs> typename T, string_literal Str, std::size_t... Idx>
+ auto _to_type_string(lexy::_detail::index_sequence<Idx...>) {
+ return T<typename decltype(Str)::value_type, Str._data[Idx]...> {};
+ }
+ template<template<typename C, C... Cs> typename T, string_literal Str>
+ using to_type_string = decltype(ovdl::detail::_to_type_string<T, Str>(lexy::_detail::make_index_sequence<decltype(Str)::size()> {}));
+}
+
+namespace ovdl::dsl {
+ template<ovdl::detail::string_literal Str, typename L, typename T, typename... R>
+ constexpr auto keyword(lexyd::_id<L, T, R...>) {
+ return ovdl::detail::to_type_string<lexyd::_keyword<lexyd::_id<L, T>>::template get, Str> {};
+ }
+} \ No newline at end of file
diff --git a/src/openvic-dataloader/detail/Warnings.hpp b/src/openvic-dataloader/detail/Warnings.hpp
index 8fc09bd..ab718bc 100644
--- a/src/openvic-dataloader/detail/Warnings.hpp
+++ b/src/openvic-dataloader/detail/Warnings.hpp
@@ -5,7 +5,7 @@
#include <openvic-dataloader/ParseWarning.hpp>
namespace ovdl::v2script::warnings {
- inline const ParseWarning make_utf8_warning(std::string_view file_path) {
+ inline const std::string make_utf8_warning(std::string_view file_path) {
constexpr std::string_view message_suffix = "This may cause problems. Prefer Windows-1252 encoding.";
std::string message;
@@ -15,7 +15,7 @@ namespace ovdl::v2script::warnings {
message = "File '" + std::string(file_path) + "' is a UTF-8 encoded file. " + std::string(message_suffix);
}
- return ParseWarning { message, 1 };
+ return message;
}
}
diff --git a/src/openvic-dataloader/detail/dsl.hpp b/src/openvic-dataloader/detail/dsl.hpp
new file mode 100644
index 0000000..9b544bc
--- /dev/null
+++ b/src/openvic-dataloader/detail/dsl.hpp
@@ -0,0 +1,150 @@
+#pragma once
+
+#include <type_traits>
+
+#include <openvic-dataloader/NodeLocation.hpp>
+#include <openvic-dataloader/ParseState.hpp>
+
+#include <lexy/callback/adapter.hpp>
+#include <lexy/callback/bind.hpp>
+#include <lexy/callback/container.hpp>
+#include <lexy/callback/fold.hpp>
+#include <lexy/dsl.hpp>
+
+#include "detail/StringLiteral.hpp"
+
+namespace ovdl::dsl {
+ template<typename ReturnType, typename... Callback>
+ constexpr auto callback(Callback... cb) {
+ return lexy::bind(lexy::callback<ReturnType>(cb...), lexy::parse_state, lexy::values);
+ }
+
+ template<typename Sink>
+ constexpr auto sink(Sink sink) {
+ return lexy::bind_sink(sink, lexy::parse_state);
+ }
+
+ template<typename Container, typename Callback>
+ constexpr auto collect(Callback callback) {
+ return sink(lexy::collect<Container>(callback));
+ }
+
+ template<typename Callback>
+ constexpr auto collect(Callback callback) {
+ return sink(lexy::collect(callback));
+ }
+
+ template<IsParseState StateType, typename T>
+ constexpr auto construct = callback<T*>(
+ [](StateType& state, ovdl::NodeLocation loc, auto&& arg) {
+ if constexpr (std::is_same_v<std::decay_t<decltype(arg)>, lexy::nullopt>)
+ return state.ast().template create<T>(loc);
+ else
+ return state.ast().template create<T>(loc, DRYAD_FWD(arg));
+ },
+ [](StateType& state, ovdl::NodeLocation loc, auto&&... args) {
+ return state.ast().template create<T>(loc, DRYAD_FWD(args)...);
+ });
+
+ template<IsParseState StateType, typename T, typename ListType, bool DisableEmpty = false>
+ constexpr auto construct_list = callback<T*>(
+ [](StateType& state, const char* begin, ListType&& arg, const char* end) {
+ return state.ast().template create<T>(NodeLocation::make_from(begin, end), DRYAD_FWD(arg));
+ },
+ [](StateType& state, const char* begin, lexy::nullopt, const char* end) {
+ return state.ast().template create<T>(NodeLocation::make_from(begin, end));
+ },
+ [](StateType& state, const char* begin, const char* end) {
+ return state.ast().template create<T>(NodeLocation::make_from(begin, end));
+ });
+
+ template<IsParseState StateType, typename T, typename ListType>
+ constexpr auto construct_list<StateType, T, ListType, true> = callback<T*>(
+ [](StateType& state, const char* begin, ListType&& arg, const char* end) {
+ return state.ast().template create<T>(NodeLocation::make_from(begin, end), DRYAD_FWD(arg));
+ },
+ [](StateType& state, const char* begin, lexy::nullopt, const char* end) {
+ return state.ast().template create<T>(NodeLocation::make_from(begin, end));
+ });
+
+ template<unsigned char LOW, unsigned char HIGH>
+ consteval auto make_range() {
+ if constexpr (LOW == HIGH) {
+ return ::lexy::dsl::lit_c<LOW>;
+ } else if constexpr (LOW == (HIGH - 1)) {
+ return ::lexy::dsl::lit_c<LOW> / ::lexy::dsl::lit_c<HIGH>;
+ } else {
+ return ::lexy::dsl::lit_c<LOW> / make_range<LOW + 1, HIGH>();
+ }
+ }
+
+ template<auto Open, auto Close>
+ constexpr auto position_brackets = lexy::dsl::brackets(lexy::dsl::position(lexy::dsl::lit_c<Open>), lexy::dsl::position(lexy::dsl::lit_c<Close>));
+
+ constexpr auto round_bracketed = position_brackets<'(', ')'>;
+ constexpr auto square_bracketed = position_brackets<'[', ']'>;
+ constexpr auto curly_bracketed = position_brackets<'{', '}'>;
+ constexpr auto angle_bracketed = position_brackets<'<', '>'>;
+
+ template<typename Production>
+ constexpr auto p = lexy::dsl::position(lexy::dsl::p<Production>);
+
+ template<IsParseState ParseType, typename ReturnType, ovdl::detail::string_literal Keyword>
+ static constexpr auto default_kw_value = dsl::callback<ReturnType*>(
+ [](ParseType& state, NodeLocation loc) {
+ return state.ast().template create<ReturnType>(loc, state.ast().intern(Keyword.data(), Keyword.size()));
+ });
+
+ template<
+ IsParseState ParseType,
+ typename Identifier,
+ typename RuleValue,
+ ovdl::detail::string_literal Keyword,
+ auto Production,
+ auto Value>
+ struct keyword_rule {
+ struct rule_t {
+ static constexpr auto keyword = ovdl::dsl::keyword<Keyword>(lexy::dsl::inline_<Identifier>);
+ static constexpr auto rule = lexy::dsl::position(keyword) >> lexy::dsl::equal_sign;
+ static constexpr auto value = Value;
+ };
+ static constexpr auto rule = dsl::p<rule_t> >> Production;
+ static constexpr auto value = construct<ParseType, RuleValue>;
+ };
+
+ template<
+ IsParseState ParseType,
+ typename Identifier,
+ typename RuleValue,
+ ovdl::detail::string_literal Keyword,
+ auto Production,
+ auto Value>
+ struct fkeyword_rule : keyword_rule<ParseType, Identifier, RuleValue, Keyword, Production, Value> {
+ using base_type = keyword_rule<ParseType, Identifier, RuleValue, Keyword, Production, Value>;
+ struct context_t;
+ struct rule_t : base_type::rule_t {
+ static constexpr auto flag = lexy::dsl::context_flag<context_t>;
+ struct too_many_error {
+ static constexpr auto name = "expected event " + Keyword + " to only be found once";
+ };
+ static constexpr auto must = lexy::dsl::must(rule_t::flag.is_reset())
+ .
+// See https://stackoverflow.com/questions/77144003/use-of-template-keyword-before-dependent-template-name
+// THANKS FOR NOTHING MICROSOFT, CAN'T EVEN GET THE STANDARD RIGHT
+#if !defined(_MSC_VER) || defined(__clang__)
+ template
+#endif
+ error<too_many_error>;
+ };
+ static constexpr auto make_flag = rule_t::flag.create();
+
+ static constexpr auto rule = dsl::p<rule_t> >> (rule_t::must >> rule_t::flag.set()) >> Production;
+ static constexpr auto value = construct<ParseType, RuleValue>;
+ };
+
+ template<typename... Args>
+ struct rule_helper {
+ static constexpr auto flags = (Args::make_flag + ...);
+ static constexpr auto p = (lexy::dsl::p<Args> | ...);
+ };
+} \ No newline at end of file
diff --git a/src/openvic-dataloader/v2script/AbstractSyntaxTree.cpp b/src/openvic-dataloader/v2script/AbstractSyntaxTree.cpp
index 182d559..4754d8e 100644
--- a/src/openvic-dataloader/v2script/AbstractSyntaxTree.cpp
+++ b/src/openvic-dataloader/v2script/AbstractSyntaxTree.cpp
@@ -1,9 +1,3 @@
-#include <iomanip>
-#include <sstream>
-#include <string>
-#include <utility>
-#include <vector>
-
#include <stddef.h>
#include <openvic-dataloader/v2script/AbstractSyntaxTree.hpp>
@@ -11,281 +5,146 @@
#include <lexy/dsl/option.hpp>
#include <lexy/input_location.hpp>
-using namespace ovdl::v2script::ast;
-
-static void _handle_string_characters(std::string& string, bool allow_newline) {
- size_t position = 0;
- for (auto& c : string) {
- switch (c) {
- case '\r':
- case '\n':
- if (allow_newline) goto END_LOOP;
- c = ' ';
- break;
- default: break;
- }
- END_LOOP:
- position++;
- }
-}
-
-void ovdl::v2script::ast::copy_into_node_ptr_vector(const std::vector<NodePtr>& source, std::vector<NodeUPtr>& dest) {
- dest.clear();
- dest.reserve(source.size());
- for (auto&& p : source) {
- dest.push_back(NodeUPtr { p });
- }
-}
-
-AbstractStringNode::AbstractStringNode() : Node({}) {}
-AbstractStringNode::AbstractStringNode(NodeLocation location, std::string&& name, bool allow_newline) : Node(location),
- _name(std::move(name)) {
- _handle_string_characters(_name, allow_newline);
-}
-AbstractStringNode::AbstractStringNode(NodeLocation location) : Node(location) {}
-AbstractStringNode::AbstractStringNode(std::string&& name, bool allow_newline) : AbstractStringNode({}, std::move(name), allow_newline) {}
-
-std::ostream& AbstractStringNode::print(std::ostream& stream, size_t indent) const {
- return stream << _name;
-}
-
-#define OVDL_AST_STRING_NODE_DEF(NAME, ...) \
- NAME::NAME() : AbstractStringNode() {} \
- NAME::NAME(std::string&& name, bool allow_newline) : AbstractStringNode(std::move(name), allow_newline) {} \
- NAME::NAME(lexy::nullopt) : AbstractStringNode() {} \
- NAME::NAME(NodeLocation location) : AbstractStringNode(location) {} \
- NAME::NAME(NodeLocation location, std::string&& name, bool allow_newline) : AbstractStringNode(location, std::move(name), allow_newline) {} \
- NAME::NAME(NodeLocation location, lexy::nullopt) : AbstractStringNode(location, {}, true) {} \
- std::ostream& NAME::print(std::ostream& stream, size_t indent) const __VA_ARGS__
-
-OVDL_AST_STRING_NODE_DEF(IdentifierNode, {
- return stream << _name;
-});
-
-OVDL_AST_STRING_NODE_DEF(StringNode, {
- return stream << '"' << _name << '"';
-});
-
-OVDL_AST_STRING_NODE_DEF(FactorNode, {
- return stream << "factor = " << _name;
-});
-
-OVDL_AST_STRING_NODE_DEF(MonthNode, {
- return stream << "months = " << _name;
-});
-
-OVDL_AST_STRING_NODE_DEF(NameNode, {
- return stream << "name = " << _name;
-});
-
-OVDL_AST_STRING_NODE_DEF(FireOnlyNode, {
- return stream << "fire_only_once = " << _name;
-});
-
-OVDL_AST_STRING_NODE_DEF(IdNode, {
- return stream << "id = " << _name;
-});
-
-OVDL_AST_STRING_NODE_DEF(TitleNode, {
- return stream << "title = " << _name;
-});
-
-OVDL_AST_STRING_NODE_DEF(DescNode, {
- return stream << "desc = " << _name;
-});
-
-OVDL_AST_STRING_NODE_DEF(PictureNode, {
- return stream << "picture = " << _name;
-});
-
-OVDL_AST_STRING_NODE_DEF(IsTriggeredNode, {
- return stream << "is_triggered_only = " << _name;
-});
-
-#undef OVDL_AST_STRING_NODE_DEF
-
-AssignNode::AssignNode(NodeLocation location, NodeCPtr name, NodePtr init)
- : Node(location),
- _initializer(std::move(init)) {
- if (name->is_type<IdentifierNode>()) {
- _name = cast_node_cptr<IdentifierNode>(name)._name;
- }
-}
-
-std::ostream& Node::print_ptr(std::ostream& stream, NodeCPtr node, size_t indent) {
- return node != nullptr ? node->print(stream, indent) : stream << "<NULL>";
-}
-
-static std::ostream& print_newline_indent(std::ostream& stream, size_t indent) {
- return stream << "\n"
- << std::setw(indent) << std::setfill('\t') << "";
-}
-
-/* Starts with a newline and ends at the end of a line, and so
- * should be followed by a call to print_newline_indent.
- */
-static std::ostream& print_nodeuptr_vector(const std::vector<NodeUPtr>& nodes,
- std::ostream& stream, size_t indent) {
- for (NodeUPtr const& node : nodes) {
- print_newline_indent(stream, indent);
- Node::print_ptr(stream, node.get(), indent);
- }
- return stream;
-}
-
-AbstractListNode::AbstractListNode(NodeLocation location, const std::vector<NodePtr>& statements) : Node(location) {
- copy_into_node_ptr_vector(statements, _statements);
-}
-AbstractListNode::AbstractListNode(const std::vector<NodePtr>& statements) : AbstractListNode({}, statements) {}
-std::ostream& AbstractListNode::print(std::ostream& stream, size_t indent) const {
- stream << '{';
- if (!_statements.empty()) {
- print_nodeuptr_vector(_statements, stream, indent + 1);
- print_newline_indent(stream, indent);
- }
- return stream << "}";
-}
-
-#define OVDL_AST_LIST_NODE_DEF(NAME, ...) \
- NAME::NAME(const std::vector<NodePtr>& statements) : AbstractListNode(statements) {} \
- NAME::NAME(lexy::nullopt) : AbstractListNode() {} \
- NAME::NAME(NodeLocation location, const std::vector<NodePtr>& statements) : AbstractListNode(location, statements) {} \
- NAME::NAME(NodeLocation location, lexy::nullopt) : AbstractListNode(location, {}) {} \
- std::ostream& NAME::print(std::ostream& stream, size_t indent) const __VA_ARGS__
-
-OVDL_AST_LIST_NODE_DEF(FileNode, {
- print_nodeuptr_vector(_statements, stream, indent);
- return print_newline_indent(stream, indent);
-});
+#include <dryad/node.hpp>
+#include <dryad/tree.hpp>
-OVDL_AST_LIST_NODE_DEF(ListNode, {
- stream << '{';
- if (!_statements.empty()) {
- print_nodeuptr_vector(_statements, stream, indent + 1);
- print_newline_indent(stream, indent);
- }
- return stream << "}";
-});
-
-OVDL_AST_LIST_NODE_DEF(ModifierNode, {
- stream << "modifier = {";
- if (!_statements.empty()) {
- print_nodeuptr_vector(_statements, stream, indent + 1);
- print_newline_indent(stream, indent);
- }
- return stream << '}';
-});
-
-OVDL_AST_LIST_NODE_DEF(MtthNode, {
- stream << "mean_time_to_happen = {";
- if (!_statements.empty()) {
- print_nodeuptr_vector(_statements, stream, indent + 1);
- print_newline_indent(stream, indent);
- }
- return stream << '}';
-});
+#include <range/v3/view/drop.hpp>
-OVDL_AST_LIST_NODE_DEF(EventOptionNode, {
- stream << "option = {";
- if (!_statements.empty()) {
- print_nodeuptr_vector(_statements, stream, indent + 1);
- print_newline_indent(stream, indent);
- }
- return stream << '}';
-});
-
-OVDL_AST_LIST_NODE_DEF(BehaviorListNode, {
- stream << "ai_chance = {"; // may be ai_chance or ai_will_do
- if (!_statements.empty()) {
- print_nodeuptr_vector(_statements, stream, indent + 1);
- print_newline_indent(stream, indent);
- }
- return stream << '}';
-});
-
-OVDL_AST_LIST_NODE_DEF(DecisionListNode, {
- stream << "political_decisions = {";
- if (!_statements.empty()) {
- print_nodeuptr_vector(_statements, stream, indent + 1);
- print_newline_indent(stream, indent);
- }
- return stream << '}';
-});
-
-#undef OVDL_AST_LIST_NODE_DEF
-
-EventNode::EventNode(NodeLocation location, Type type, const std::vector<NodePtr>& statements) : AbstractListNode(location),
- _type(type) {
- copy_into_node_ptr_vector(statements, _statements);
-}
-EventNode::EventNode(Type type, const std::vector<NodePtr>& statements) : EventNode({}, type, statements) {}
-std::ostream& EventNode::print(std::ostream& stream, size_t indent) const {
- switch (_type) {
- case Type::Country: stream << "country_event = "; break;
- case Type::Province: stream << "province_event = "; break;
- }
- stream << '{';
- if (!_statements.empty()) {
- print_nodeuptr_vector(_statements, stream, indent + 1);
- print_newline_indent(stream, indent);
- }
- return stream << '}';
-}
-
-DecisionNode::DecisionNode(NodeLocation location, NodePtr name, const std::vector<NodePtr>& statements) : AbstractListNode(location),
- _name(std::move(name)) {
- copy_into_node_ptr_vector(statements, _statements);
-}
-DecisionNode::DecisionNode(NodePtr name, const std::vector<NodePtr>& statements) : DecisionNode({}, name, statements) {}
-std::ostream& DecisionNode::print(std::ostream& stream, size_t indent) const {
- print_ptr(stream, _name.get(), indent) << " = {";
- if (!_statements.empty()) {
- print_nodeuptr_vector(_statements, stream, indent + 1);
- print_newline_indent(stream, indent);
- }
- return stream << '}';
-}
-
-ExecutionNode::ExecutionNode(NodeLocation location, Type type, NodePtr name, NodePtr init) : Node(location),
- _type(type),
- _name(std::move(name)),
- _initializer(std::move(init)) {
-}
-ExecutionNode::ExecutionNode(Type type, NodePtr name, NodePtr init) : ExecutionNode({}, type, name, init) {}
-std::ostream& ExecutionNode::print(std::ostream& stream, size_t indent) const {
- print_ptr(stream, _name.get(), indent) << " = ";
- if (_initializer) {
- Node::print_ptr(stream, _initializer.get(), indent + 1);
- }
- return stream;
-}
-
-ExecutionListNode::ExecutionListNode(NodeLocation location, ExecutionNode::Type type, const std::vector<NodePtr>& statements) : AbstractListNode(location),
- _type(type) {
- copy_into_node_ptr_vector(statements, _statements);
-}
-ExecutionListNode::ExecutionListNode(ExecutionNode::Type type, const std::vector<NodePtr>& statements) : ExecutionListNode({}, type, statements) {}
-std::ostream& ExecutionListNode::print(std::ostream& stream, size_t indent) const {
- // Only way to make a valid declared parsable file
- stream << "{ ";
- switch (_type) {
- case ExecutionNode::Type::Effect: stream << "effect = {"; break;
- case ExecutionNode::Type::Trigger: stream << "trigger = {"; break;
- }
- if (!_statements.empty()) {
- print_nodeuptr_vector(_statements, stream, indent + 1);
- print_newline_indent(stream, indent);
- }
- return stream << "}}";
-}
+using namespace ovdl::v2script::ast;
-Node::operator std::string() const {
- std::stringstream ss;
- ss << *this;
- return ss.str();
-}
+ListValue::ListValue(dryad::node_ctor ctor, StatementList statements)
+ : node_base(ctor) {
+ insert_child_list_after(nullptr, statements);
+ if (statements.empty()) {
+ _last_statement = nullptr;
+ } else {
+ _last_statement = statements.back();
+ }
+}
+
+FileTree::FileTree(dryad::node_ctor ctor, StatementList statements) : node_base(ctor) {
+ insert_child_list_after(nullptr, statements);
+ if (statements.empty()) {
+ _last_node = nullptr;
+ } else {
+ _last_node = statements.back();
+ }
+}
+
+// static void _handle_string_characters(std::string& string, bool allow_newline) {
+// size_t position = 0;
+// for (auto& c : string) {
+// switch (c) {
+// case '\r':
+// case '\n':
+// if (allow_newline) goto END_LOOP;
+// c = ' ';
+// break;
+// default: break;
+// }
+// END_LOOP:
+// position++;
+// }
+// }
+
+std::string AbstractSyntaxTree::make_list_visualizer() const {
+ const int INDENT_SIZE = 2;
+
+ std::string result;
+ unsigned int level = 0;
+
+ for (auto [event, node] : dryad::traverse(_tree)) {
+ if (event == dryad::traverse_event::exit) {
+ --level;
+ continue;
+ }
-std::ostream& AssignNode::print(std::ostream& stream, size_t indent) const {
- stream << _name << " = ";
- return Node::print_ptr(stream, _initializer.get(), indent);
+ result.append(INDENT_SIZE * level, ' ');
+ result.append(fmt::format("- {}: ", get_kind_name(node->kind())));
+
+ dryad::visit_node(
+ node,
+ [&](const FlatValue* value) {
+ result.append(value->value(_symbol_interner));
+ },
+ [&](const ListValue* value) {
+ },
+ [&](const NullValue* value) {
+ },
+ [&](const EventStatement* statement) {
+ result.append(statement->is_province_event() ? "province_event" : "country_event");
+ },
+ [&](const AssignStatement* statement) {
+ },
+ [&](const FileTree* tree) {
+ });
+
+ result.append(1, '\n');
+
+ if (event == dryad::traverse_event::enter)
+ ++level;
+ }
+
+ return result;
+}
+
+std::string AbstractSyntaxTree::make_native_visualizer() const {
+ constexpr int INDENT_SIZE = 2;
+
+ std::string result;
+ unsigned int level = 0;
+
+ dryad::visit_tree(
+ _tree,
+ [&](const IdentifierValue* value) {
+ result.append(value->value(_symbol_interner));
+ },
+ [&](const StringValue* value) {
+ result.append(1, '"').append(value->value(_symbol_interner)).append(1, '"');
+ },
+ [&](dryad::child_visitor<NodeKind> visitor, const ValueStatement* statement) {
+ visitor(statement->value());
+ },
+ [&](dryad::child_visitor<NodeKind> visitor, const AssignStatement* statement) {
+ visitor(statement->left());
+ if (statement->right()->kind() != NodeKind::NullValue) {
+ result.append(" = ");
+ visitor(statement->right());
+ }
+ },
+ [&](dryad::child_visitor<NodeKind> visitor, const ListValue* value) {
+ result.append(1, '{');
+ level++;
+ for (const auto& statement : value->statements()) {
+ result
+ .append(1, '\n')
+ .append(INDENT_SIZE * level, ' ');
+ visitor(statement);
+ }
+ level--;
+ result
+ .append(1, '\n')
+ .append(INDENT_SIZE * level, ' ')
+ .append(1, '}');
+ },
+ [&](dryad::child_visitor<NodeKind> visitor, const EventStatement* statement) {
+ result.append(statement->is_province_event() ? "province_event" : "country_event");
+ if (statement->right()->kind() != NodeKind::NullValue) {
+ result.append(" = ");
+ visitor(statement->right());
+ }
+ },
+ [&](dryad::child_visitor<NodeKind> visitor, const FileTree* value) {
+ auto statements = value->statements();
+ visitor(*statements.begin());
+
+ for (const auto& statement : statements | ranges::views::drop(1)) {
+ result
+ .append(1, '\n')
+ .append(INDENT_SIZE * level, ' ');
+ visitor(statement);
+ }
+ });
+
+ return result;
} \ No newline at end of file
diff --git a/src/openvic-dataloader/v2script/AiBehaviorGrammar.hpp b/src/openvic-dataloader/v2script/AiBehaviorGrammar.hpp
index e04f447..7fcd13d 100644
--- a/src/openvic-dataloader/v2script/AiBehaviorGrammar.hpp
+++ b/src/openvic-dataloader/v2script/AiBehaviorGrammar.hpp
@@ -2,6 +2,7 @@
#include <openvic-dataloader/v2script/AbstractSyntaxTree.hpp>
+#include <lexy/callback/forward.hpp>
#include <lexy/dsl.hpp>
#include "ModifierGrammar.hpp"
@@ -10,23 +11,12 @@ namespace ovdl::v2script::grammar {
struct AiBehaviorList {
static constexpr auto rule = lexy::dsl::list(lexy::dsl::p<FactorStatement> | lexy::dsl::p<ModifierStatement>);
- static constexpr auto value =
- lexy::as_list<std::vector<ast::NodePtr>> >>
- lexy::callback<ast::NodePtr>(
- [](auto&& list) {
- return ast::make_node_ptr<ast::BehaviorListNode>(LEXY_MOV(list));
- });
+ static constexpr auto value = lexy::as_list<ast::AssignStatementList>;
};
struct AiBehaviorBlock {
- static constexpr auto rule = lexy::dsl::curly_bracketed.opt(lexy::dsl::p<AiBehaviorList>);
+ static constexpr auto rule = dsl::curly_bracketed.opt(lexy::dsl::p<AiBehaviorList>);
- static constexpr auto value = lexy::callback<ast::NodePtr>(
- [](auto&& list) {
- return LEXY_MOV(list);
- },
- [](lexy::nullopt = {}) {
- return lexy::nullopt {};
- });
+ static constexpr auto value = construct_list<ast::ListValue>;
};
} \ No newline at end of file
diff --git a/src/openvic-dataloader/v2script/DecisionGrammar.hpp b/src/openvic-dataloader/v2script/DecisionGrammar.hpp
index 3bd5cba..05cb8cc 100644
--- a/src/openvic-dataloader/v2script/DecisionGrammar.hpp
+++ b/src/openvic-dataloader/v2script/DecisionGrammar.hpp
@@ -1,109 +1,49 @@
#pragma once
-#include <vector>
-
#include <openvic-dataloader/v2script/AbstractSyntaxTree.hpp>
#include <lexy/callback.hpp>
#include <lexy/callback/adapter.hpp>
+#include <lexy/callback/constant.hpp>
#include <lexy/callback/container.hpp>
#include <lexy/dsl.hpp>
+#include <lexy/dsl/brackets.hpp>
#include <lexy/dsl/option.hpp>
+#include <lexy/dsl/position.hpp>
+#include <lexy/dsl/production.hpp>
-#include "AiBehaviorGrammar.hpp"
-#include "SimpleGrammar.hpp"
-#include "TriggerGrammar.hpp"
+#include "v2script/AiBehaviorGrammar.hpp"
+#include "v2script/TriggerGrammar.hpp"
// Decision Grammar Definitions //
namespace ovdl::v2script::grammar {
- //////////////////
- // Macros
- //////////////////
-// Produces <KW_NAME>_rule and <KW_NAME>_p
-#define OVDL_GRAMMAR_KEYWORD_DEFINE(KW_NAME) \
- struct KW_NAME##_rule { \
- static constexpr auto keyword = LEXY_KEYWORD(#KW_NAME, lexy::dsl::inline_<Identifier<StringEscapeOption>>); \
- static constexpr auto rule = keyword >> lexy::dsl::equal_sign; \
- static constexpr auto value = lexy::noop; \
- }; \
- static constexpr auto KW_NAME##_p = lexy::dsl::p<KW_NAME##_rule>
-
-// Produces <KW_NAME>_rule and <KW_NAME>_p and <KW_NAME>_rule::flag and <KW_NAME>_rule::too_many_error
-#define OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(KW_NAME) \
- struct KW_NAME##_rule { \
- static constexpr auto keyword = LEXY_KEYWORD(#KW_NAME, lexy::dsl::inline_<Identifier<StringEscapeOption>>); \
- static constexpr auto rule = keyword >> lexy::dsl::equal_sign; \
- static constexpr auto value = lexy::noop; \
- static constexpr auto flag = lexy::dsl::context_flag<struct KW_NAME##_context>; \
- struct too_many_error { \
- static constexpr auto name = "expected left side " #KW_NAME " to be found once"; \
- }; \
- }; \
- static constexpr auto KW_NAME##_p = lexy::dsl::p<KW_NAME##_rule> >> (lexy::dsl::must(KW_NAME##_rule::flag.is_reset()).error<KW_NAME##_rule::too_many_error> + KW_NAME##_rule::flag.set())
- //////////////////
- // Macros
- //////////////////
struct DecisionStatement {
- template<auto Production, typename AstNode>
- struct _StringStatement {
- static constexpr auto rule = Production >> (lexy::dsl::p<StringExpression<StringEscapeOption>> | lexy::dsl::p<Identifier<StringEscapeOption>>);
- static constexpr auto value = lexy::forward<ast::NodePtr>;
- };
- template<auto Production, typename AstNode>
- static constexpr auto StringStatement = lexy::dsl::p<_StringStatement<Production, AstNode>>;
+ using potential = fkeyword_rule<"potential", lexy::dsl::p<TriggerBlock>>;
+ using allow = fkeyword_rule<"allow", lexy::dsl::p<TriggerBlock>>;
+ using effect = fkeyword_rule<"effect", lexy::dsl::p<TriggerBlock>>;
+ using ai_will_do = fkeyword_rule<"ai_will_do", lexy::dsl::p<AiBehaviorBlock>>;
- OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(potential);
- OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(allow);
- OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(effect);
- OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(ai_will_do);
+ using helper = dsl::rule_helper<potential, allow, effect, ai_will_do>;
- static constexpr auto rule = [] {
- constexpr auto create_flags =
- potential_rule::flag.create() +
- allow_rule::flag.create() +
- effect_rule::flag.create() +
- ai_will_do_rule::flag.create();
+ struct List {
+ static constexpr auto rule = dsl::curly_bracketed.opt_list(helper::p | lexy::dsl::p<SAssignStatement<StringEscapeOption>>);
- constexpr auto potential_statement = potential_p >> lexy::dsl::p<TriggerBlock>;
- constexpr auto allow_statement = allow_p >> lexy::dsl::p<TriggerBlock>;
- constexpr auto effect_statement = effect_p >> lexy::dsl::p<TriggerBlock>;
- constexpr auto ai_will_do_statement = ai_will_do_p >> lexy::dsl::p<AiBehaviorBlock>;
+ static constexpr auto value = lexy::as_list<ast::AssignStatementList> >> construct_list<ast::ListValue>;
+ };
- return lexy::dsl::p<Identifier<StringEscapeOption>> >>
- (create_flags + lexy::dsl::equal_sign +
- lexy::dsl::curly_bracketed.list(
- potential_statement |
- allow_statement |
- effect_statement |
- ai_will_do_statement |
- lexy::dsl::p<SimpleAssignmentStatement<StringEscapeOption>>));
- }();
+ static constexpr auto rule =
+ dsl::p<Identifier<StringEscapeOption>> >>
+ (helper::flags + lexy::dsl::equal_sign + lexy::dsl::p<List>);
- static constexpr auto value =
- lexy::as_list<std::vector<ast::NodePtr>> >>
- lexy::callback<ast::NodePtr>(
- [](auto&& name, auto&& list) {
- return ast::make_node_ptr<ast::DecisionNode>(LEXY_MOV(name), LEXY_MOV(list));
- },
- [](auto&& name, lexy::nullopt = {}) {
- return ast::make_node_ptr<ast::DecisionNode>(LEXY_MOV(name));
- });
+ static constexpr auto value = construct<ast::AssignStatement>;
};
struct DecisionList {
static constexpr auto rule =
- LEXY_KEYWORD("political_decisions", lexy::dsl::inline_<Identifier<StringEscapeOption>>) >>
- (lexy::dsl::equal_sign + lexy::dsl::curly_bracketed.opt_list(lexy::dsl::p<DecisionStatement>));
+ ovdl::dsl::keyword<"political_decisions">(lexy::dsl::inline_<Identifier<StringEscapeOption>>) >>
+ (lexy::dsl::equal_sign >> lexy::dsl::curly_bracketed.opt_list(lexy::dsl::p<DecisionStatement>));
- static constexpr auto value =
- lexy::as_list<std::vector<ast::NodePtr>> >>
- lexy::callback<ast::NodePtr>(
- [](auto&& list) {
- return ast::make_node_ptr<ast::DecisionListNode>(LEXY_MOV(list));
- },
- [](lexy::nullopt = {}) {
- return lexy::nullopt {};
- });
+ static constexpr auto value = lexy::as_list<ast::AssignStatementList>;
};
struct DecisionFile {
@@ -111,15 +51,8 @@ namespace ovdl::v2script::grammar {
static constexpr auto whitespace = whitespace_specifier | comment_specifier;
static constexpr auto rule =
- lexy::dsl::terminator(lexy::dsl::eof).list( //
- lexy::dsl::p<DecisionList> | //
- lexy::dsl::p<SimpleAssignmentStatement<StringEscapeOption>>);
+ lexy::dsl::position + lexy::dsl::terminator(lexy::dsl::eof).opt_list(lexy::dsl::p<DecisionList>);
- static constexpr auto value = lexy::as_list<std::vector<ast::NodePtr>> >> lexy::new_<ast::FileNode, ast::NodePtr>;
+ static constexpr auto value = lexy::concat<ast::AssignStatementList> >> construct<ast::FileTree>;
};
-
-#undef OVDL_GRAMMAR_KEYWORD_DEFINE
-#undef OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE
-#undef OVDL_GRAMMAR_KEYWORD_STATEMENT
-#undef OVDL_GRAMMAR_KEYWORD_FLAG_STATEMENT
} \ No newline at end of file
diff --git a/src/openvic-dataloader/v2script/EffectGrammar.hpp b/src/openvic-dataloader/v2script/EffectGrammar.hpp
index 1b85382..10f8348 100644
--- a/src/openvic-dataloader/v2script/EffectGrammar.hpp
+++ b/src/openvic-dataloader/v2script/EffectGrammar.hpp
@@ -6,37 +6,24 @@
#include <lexy/dsl.hpp>
#include "SimpleGrammar.hpp"
+#include "detail/dsl.hpp"
namespace ovdl::v2script::grammar {
struct EffectStatement {
- static constexpr auto rule = lexy::dsl::inline_<SimpleAssignmentStatement<StringEscapeOption>>;
+ static constexpr auto rule = lexy::dsl::p<SAssignStatement<StringEscapeOption>>;
- static constexpr auto value = lexy::callback<ast::NodePtr>(
- [](auto name, auto&& initalizer) {
- return ast::make_node_ptr<ast::ExecutionNode>(ast::ExecutionNode::Type::Effect, LEXY_MOV(name), LEXY_MOV(initalizer));
- });
+ static constexpr auto value = lexy::forward<ast::AssignStatement*>;
};
struct EffectList {
- static constexpr auto rule = lexy::dsl::list(lexy::dsl::p<SimpleAssignmentStatement<StringEscapeOption>>);
-
- static constexpr auto value =
- lexy::as_list<std::vector<ast::NodePtr>> >>
- lexy::callback<ast::NodePtr>(
- [](auto&& list) {
- return ast::make_node_ptr<ast::ExecutionListNode>(ast::ExecutionNode::Type::Effect, LEXY_MOV(list));
- });
+ static constexpr auto rule = lexy::dsl::list(lexy::dsl::p<EffectStatement>);
+
+ static constexpr auto value = lexy::as_list<ast::AssignStatementList>;
};
struct EffectBlock {
- static constexpr auto rule = lexy::dsl::curly_bracketed.opt(lexy::dsl::p<EffectList>);
-
- static constexpr auto value = lexy::callback<ast::NodePtr>(
- [](auto&& list) {
- return LEXY_MOV(list);
- },
- [](lexy::nullopt = {}) {
- return lexy::nullopt {};
- });
+ static constexpr auto rule = dsl::curly_bracketed.opt(lexy::dsl::p<EffectList>);
+
+ static constexpr auto value = construct_list<ast::ListValue>;
};
} \ No newline at end of file
diff --git a/src/openvic-dataloader/v2script/EventGrammar.hpp b/src/openvic-dataloader/v2script/EventGrammar.hpp
index 57cd170..c81a173 100644
--- a/src/openvic-dataloader/v2script/EventGrammar.hpp
+++ b/src/openvic-dataloader/v2script/EventGrammar.hpp
@@ -1,168 +1,109 @@
#pragma once
-#include <string>
-#include <vector>
+#include <cctype>
+#include <cstdlib>
#include <openvic-dataloader/v2script/AbstractSyntaxTree.hpp>
#include <lexy/callback.hpp>
#include <lexy/dsl.hpp>
+#include <lexy/grammar.hpp>
+
+#include "openvic-dataloader/NodeLocation.hpp"
-#include "AiBehaviorGrammar.hpp"
-#include "EffectGrammar.hpp"
-#include "ModifierGrammar.hpp"
#include "SimpleGrammar.hpp"
-#include "TriggerGrammar.hpp"
+#include "detail/dsl.hpp"
+#include "v2script/AiBehaviorGrammar.hpp"
+#include "v2script/EffectGrammar.hpp"
+#include "v2script/ModifierGrammar.hpp"
// Event Grammar Definitions //
namespace ovdl::v2script::grammar {
- //////////////////
- // Macros
- //////////////////
-// Produces <KW_NAME>_rule and <KW_NAME>_p
-#define OVDL_GRAMMAR_KEYWORD_DEFINE(KW_NAME) \
- struct KW_NAME##_rule { \
- static constexpr auto keyword = LEXY_KEYWORD(#KW_NAME, lexy::dsl::inline_<Identifier<StringEscapeOption>>); \
- static constexpr auto rule = keyword >> lexy::dsl::equal_sign; \
- static constexpr auto value = lexy::noop; \
- }; \
- static constexpr auto KW_NAME##_p = lexy::dsl::p<KW_NAME##_rule>
-
-// Produces <KW_NAME>_rule and <KW_NAME>_p and <KW_NAME>_rule::flag and <KW_NAME>_rule::too_many_error
-#define OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(KW_NAME) \
- struct KW_NAME##_rule { \
- static constexpr auto keyword = LEXY_KEYWORD(#KW_NAME, lexy::dsl::inline_<Identifier<StringEscapeOption>>); \
- static constexpr auto rule = keyword >> lexy::dsl::equal_sign; \
- static constexpr auto value = lexy::noop; \
- static constexpr auto flag = lexy::dsl::context_flag<struct KW_NAME##_context>; \
- struct too_many_error { \
- static constexpr auto name = "expected left side " #KW_NAME " to be found once"; \
- }; \
- }; \
- static constexpr auto KW_NAME##_p = lexy::dsl::p<KW_NAME##_rule> >> (lexy::dsl::must(KW_NAME##_rule::flag.is_reset()).error<KW_NAME##_rule::too_many_error> + KW_NAME##_rule::flag.set())
- //////////////////
- // Macros
- //////////////////
- static constexpr auto event_symbols = lexy::symbol_table<ast::EventNode::Type> //
- .map<LEXY_SYMBOL("country_event")>(ast::EventNode::Type::Country)
- .map<LEXY_SYMBOL("province_event")>(ast::EventNode::Type::Province);
+ static constexpr auto event_symbols = lexy::symbol_table<bool> //
+ .map<LEXY_SYMBOL("country_event")>(false)
+ .map<LEXY_SYMBOL("province_event")>(true);
struct EventMtthStatement {
- OVDL_GRAMMAR_KEYWORD_DEFINE(months);
-
struct MonthValue {
- static constexpr auto rule = lexy::dsl::inline_<Identifier<StringEscapeOption>>;
- static constexpr auto value = lexy::as_string<std::string> | lexy::new_<ast::MonthNode, ast::NodePtr>;
+ static constexpr auto rule = lexy::dsl::p<Identifier<StringEscapeOption>>;
+ static constexpr auto value = dsl::callback<ast::IdentifierValue*>(
+ [](ast::ParseState& state, ast::IdentifierValue* value) {
+ bool is_number = true;
+ for (auto* current = value->value(state.ast().symbol_interner()); *current; current++) {
+ is_number = is_number && std::isdigit(*current);
+ if (!is_number) break;
+ }
+ if (!is_number) {
+ state.logger().warning("month is not an integer") //
+ .primary(state.ast().location_of(value), "here")
+ .finish();
+ }
+ return value;
+ });
};
- static constexpr auto rule = lexy::dsl::list(
- (months_p >> lexy::dsl::p<MonthValue>) |
- lexy::dsl::p<ModifierStatement>);
+ using months = keyword_rule<"months", lexy::dsl::p<MonthValue>>;
- static constexpr auto value =
- lexy::as_list<std::vector<ast::NodePtr>> >>
- lexy::callback<ast::NodePtr>(
- [](auto&& list) {
- return ast::make_node_ptr<ast::MtthNode>(LEXY_MOV(list));
- });
- };
+ static constexpr auto rule = dsl::curly_bracketed(lexy::dsl::p<months> | lexy::dsl::p<ModifierStatement>);
- template<auto Production, typename AstNode>
- struct _StringStatement {
- static constexpr auto rule = Production >> (lexy::dsl::p<StringExpression<StringEscapeOption>> | lexy::dsl::p<Identifier<StringEscapeOption>>);
- static constexpr auto value =
- lexy::callback<ast::NodePtr>(
- [](auto&& value) {
- auto result = ast::make_node_ptr<AstNode>(std::move(static_cast<ast::AbstractStringNode*>(value)->_name));
- delete value;
- return result;
- });
+ static constexpr auto value = lexy::as_list<ast::AssignStatementList> >> construct_list<ast::ListValue, true>;
};
- template<auto Production, typename AstNode>
- static constexpr auto StringStatement = lexy::dsl::p<_StringStatement<Production, AstNode>>;
+
+ static constexpr auto str_or_id = lexy::dsl::p<SimpleGrammar<StringEscapeOption>::ValueExpression>;
struct EventOptionList {
- OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(name);
- OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(ai_chance);
+ using name = fkeyword_rule<"name", str_or_id>;
+ using ai_chance = fkeyword_rule<"ai_chance", lexy::dsl::p<AiBehaviorBlock>>;
static constexpr auto rule = [] {
- constexpr auto create_flags = name_rule::flag.create() + ai_chance_rule::flag.create();
-
- constexpr auto name_statement = StringStatement<name_p, ast::NameNode>;
- constexpr auto ai_chance_statement = ai_chance_p >> lexy::dsl::curly_bracketed(lexy::dsl::p<AiBehaviorList>);
+ using helper = dsl::rule_helper<name, ai_chance>;
- return create_flags + lexy::dsl::list(name_statement | ai_chance_statement | lexy::dsl::p<EffectList>);
+ return dsl::curly_bracketed(helper::flags + lexy::dsl::list(helper::p | lexy::dsl::p<EffectStatement>));
}();
- static constexpr auto value =
- lexy::as_list<std::vector<ast::NodePtr>> >>
- lexy::callback<ast::NodePtr>(
- [](auto&& list) {
- return ast::make_node_ptr<ast::EventOptionNode>(LEXY_MOV(list));
- });
+ static constexpr auto value = lexy::as_list<ast::AssignStatementList> >> construct_list<ast::ListValue, true>;
};
struct EventStatement {
- OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(id);
- OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(title);
- OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(desc);
- OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(picture);
- OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(is_triggered_only);
- OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(fire_only_once);
- OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(immediate);
- OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE(mean_time_to_happen);
- OVDL_GRAMMAR_KEYWORD_DEFINE(trigger);
- OVDL_GRAMMAR_KEYWORD_DEFINE(option);
+ using id = fkeyword_rule<"id", str_or_id>;
+ using title = fkeyword_rule<"title", str_or_id>;
+ using desc = fkeyword_rule<"desc", str_or_id>;
+ using picture = fkeyword_rule<"picture", str_or_id>;
+ using is_triggered_only = fkeyword_rule<"is_triggered_only", str_or_id>;
+ using fire_only_once = fkeyword_rule<"fire_only_once", str_or_id>;
+ using immediate = fkeyword_rule<"immediate", lexy::dsl::p<EffectBlock>>;
+ using mean_time_to_happen = fkeyword_rule<"mean_time_to_happen", lexy::dsl::p<EventMtthStatement>>;
+ using trigger = keyword_rule<"trigger", lexy::dsl::p<TriggerBlock>>;
+ using option = keyword_rule<"option", lexy::dsl::p<EventOptionList>>;
+
+ struct EventList {
+ static constexpr auto rule = [] {
+ using helper = dsl::rule_helper<id, title, desc, picture, is_triggered_only, fire_only_once, immediate, mean_time_to_happen>;
+
+ return helper::flags +
+ dsl::curly_bracketed.opt_list(
+ helper::p | lexy::dsl::p<trigger> | lexy::dsl::p<option> |
+ lexy::dsl::p<SAssignStatement<StringEscapeOption>>);
+ }();
+
+ static constexpr auto value = lexy::as_list<ast::AssignStatementList> >> construct_list<ast::ListValue, true>;
+ };
- static constexpr auto rule = [] {
- constexpr auto symbol_value = lexy::dsl::symbol<event_symbols>(lexy::dsl::inline_<Identifier<StringEscapeOption>>);
-
- constexpr auto create_flags =
- id_rule::flag.create() +
- title_rule::flag.create() +
- desc_rule::flag.create() +
- picture_rule::flag.create() +
- is_triggered_only_rule::flag.create() +
- fire_only_once_rule::flag.create() +
- immediate_rule::flag.create() +
- mean_time_to_happen_rule::flag.create();
-
- constexpr auto id_statement = StringStatement<id_p, ast::IdNode>;
- constexpr auto title_statement = StringStatement<title_p, ast::TitleNode>;
- constexpr auto desc_statement = StringStatement<desc_p, ast::DescNode>;
- constexpr auto picture_statement = StringStatement<picture_p, ast::PictureNode>;
- constexpr auto is_triggered_only_statement = StringStatement<is_triggered_only_p, ast::IsTriggeredNode>;
- constexpr auto fire_only_once_statement = StringStatement<fire_only_once_p, ast::FireOnlyNode>;
- constexpr auto immediate_statement = immediate_p >> lexy::dsl::p<EffectBlock>;
- constexpr auto mean_time_to_happen_statement = mean_time_to_happen_p >> lexy::dsl::curly_bracketed(lexy::dsl::p<EventMtthStatement>);
-
- constexpr auto trigger_statement = trigger_p >> lexy::dsl::curly_bracketed.opt(lexy::dsl::p<TriggerList>);
- constexpr auto option_statement = option_p >> lexy::dsl::curly_bracketed(lexy::dsl::p<EventOptionList>);
-
- return symbol_value >>
- (create_flags + lexy::dsl::equal_sign +
- lexy::dsl::curly_bracketed.opt_list(
- id_statement |
- title_statement |
- desc_statement |
- picture_statement |
- is_triggered_only_statement |
- fire_only_once_statement |
- immediate_statement |
- mean_time_to_happen_statement |
- trigger_statement |
- option_statement |
- lexy::dsl::p<SimpleAssignmentStatement<StringEscapeOption>>));
- }();
+ static constexpr auto rule = dsl::p<Identifier<StringEscapeOption>> >> lexy::dsl::equal_sign >> lexy::dsl::p<EventList>;
static constexpr auto value =
- lexy::as_list<std::vector<ast::NodePtr>> >>
- lexy::callback<ast::NodePtr>(
- [](auto& type, auto&& list) {
- return ast::make_node_ptr<ast::EventNode>(type, LEXY_MOV(list));
- },
- [](auto& type, lexy::nullopt = {}) {
- return ast::make_node_ptr<ast::EventNode>(type);
+ dsl::callback<ast::EventStatement*>(
+ [](ast::ParseState& state, NodeLocation loc, ast::IdentifierValue* name, ast::ListValue* list) {
+ static auto country_decl = state.ast().intern_cstr("country_event");
+ static auto province_decl = state.ast().intern_cstr("province_event");
+
+ if (name->value(state.ast().symbol_interner()) != country_decl || name->value(state.ast().symbol_interner()) != province_decl) {
+ state.logger().warning("event declarator \"{}\" is not {} or {}", name->value(state.ast().symbol_interner()), country_decl, province_decl) //
+ .primary(loc, "here")
+ .finish();
+ }
+
+ return state.ast().create<ast::EventStatement>(loc, name->value(state.ast().symbol_interner()) == province_decl, list);
});
};
@@ -170,13 +111,8 @@ namespace ovdl::v2script::grammar {
// Allow arbitrary spaces between individual tokens.
static constexpr auto whitespace = whitespace_specifier | comment_specifier;
- static constexpr auto rule = lexy::dsl::terminator(lexy::dsl::eof).list(lexy::dsl::p<EventStatement> | lexy::dsl::p<SimpleAssignmentStatement<StringEscapeOption>>);
+ static constexpr auto rule = lexy::dsl::position + lexy::dsl::terminator(lexy::dsl::eof).list(lexy::dsl::p<EventStatement> | lexy::dsl::p<SAssignStatement<StringEscapeOption>>);
- static constexpr auto value = lexy::as_list<std::vector<ast::NodePtr>> >> lexy::new_<ast::FileNode, ast::NodePtr>;
+ static constexpr auto value = lexy::as_list<ast::StatementList> >> construct<ast::FileTree>;
};
-
-#undef OVDL_GRAMMAR_KEYWORD_DEFINE
-#undef OVDL_GRAMMAR_KEYWORD_FLAG_DEFINE
-#undef OVDL_GRAMMAR_KEYWORD_STATEMENT
-#undef OVDL_GRAMMAR_KEYWORD_FLAG_STATEMENT
} \ No newline at end of file
diff --git a/src/openvic-dataloader/v2script/LuaDefinesGrammar.hpp b/src/openvic-dataloader/v2script/LuaDefinesGrammar.hpp
index b64d0f9..4d27d3e 100644
--- a/src/openvic-dataloader/v2script/LuaDefinesGrammar.hpp
+++ b/src/openvic-dataloader/v2script/LuaDefinesGrammar.hpp
@@ -1,11 +1,25 @@
#pragma once
+#include <lexy/_detail/config.hpp>
#include <lexy/dsl.hpp>
+#include "openvic-dataloader/v2script/AbstractSyntaxTree.hpp"
+
#include "SimpleGrammar.hpp"
-#include "detail/LexyLitRange.hpp"
+#include "detail/dsl.hpp"
namespace ovdl::v2script::lua::grammar {
+ template<typename ReturnType, typename... Callback>
+ constexpr auto callback(Callback... cb) {
+ return dsl::callback<ReturnType>(cb...);
+ }
+
+ template<typename T>
+ constexpr auto construct = v2script::grammar::construct<T>;
+
+ template<typename T>
+ constexpr auto construct_list = v2script::grammar::construct_list<T>;
+
struct ParseOptions {
};
@@ -17,20 +31,20 @@ namespace ovdl::v2script::lua::grammar {
template<ParseOptions Options>
struct Identifier {
static constexpr auto rule = lexy::dsl::identifier(lexy::dsl::ascii::alpha_underscore, lexy::dsl::ascii::alpha_digit_underscore);
- static constexpr auto value = lexy::callback<ast::NodePtr>(
- [](auto lexeme) {
- std::string str(lexeme.data(), lexeme.size());
- return ast::make_node_ptr<ast::IdentifierNode>(ast::NodeLocation { lexeme.begin(), lexeme.end() }, LEXY_MOV(str));
+ static constexpr auto value = callback<ast::IdentifierValue*>(
+ [](ast::ParseState& state, auto lexeme) {
+ auto value = state.ast().intern(lexeme.data(), lexeme.size());
+ return state.ast().create<ast::IdentifierValue>(lexeme.begin(), lexeme.end(), value);
});
};
template<ParseOptions Options>
struct Value {
static constexpr auto rule = lexy::dsl::identifier(lexy::dsl::ascii::digit / lexy::dsl::lit_c<'.'> / lexy::dsl::lit_c<'-'>);
- static constexpr auto value = lexy::callback<ast::NodePtr>(
- [](auto lexeme) {
- std::string str(lexeme.data(), lexeme.size());
- return ast::make_node_ptr<ast::IdentifierNode>(ast::NodeLocation { lexeme.begin(), lexeme.end() }, LEXY_MOV(str));
+ static constexpr auto value = callback<ast::IdentifierValue*>(
+ [](ast::ParseState& state, auto lexeme) {
+ auto value = state.ast().intern(lexeme.data(), lexeme.size());
+ return state.ast().create<ast::IdentifierValue>(lexeme.begin(), lexeme.end(), value);
});
};
@@ -38,66 +52,50 @@ namespace ovdl::v2script::lua::grammar {
struct String {
static constexpr auto rule = [] {
// Arbitrary code points that aren't control characters.
- auto c = ovdl::detail::lexydsl::make_range<0x20, 0xFF>() - lexy::dsl::ascii::control;
+ auto c = dsl::make_range<0x20, 0xFF>() - lexy::dsl::ascii::control;
return lexy::dsl::delimited(lexy::dsl::position(lexy::dsl::lit_b<'"'>))(c) | lexy::dsl::delimited(lexy::dsl::position(lexy::dsl::lit_b<'\''>))(c);
}();
static constexpr auto value =
lexy::as_string<std::string> >>
- lexy::callback<ast::NodePtr>(
- [](const char* begin, auto&& str, const char* end) {
- return ast::make_node_ptr<ast::StringNode>(ast::NodeLocation::make_from(begin, end), LEXY_MOV(str));
+ callback<ast::StringValue*>(
+ [](ast::ParseState& state, const char* begin, const std::string& str, const char* end) {
+ auto value = state.ast().intern(str.data(), str.length());
+ return state.ast().create<ast::StringValue>(begin, end, value);
});
};
template<ParseOptions Options>
struct Expression {
static constexpr auto rule = lexy::dsl::p<Value<Options>> | lexy::dsl::p<String<Options>>;
- static constexpr auto value = lexy::forward<ast::NodePtr>;
+ static constexpr auto value = lexy::forward<ast::Value*>;
};
template<ParseOptions Options>
struct AssignmentStatement {
static constexpr auto rule =
- lexy::dsl::position(lexy::dsl::p<Identifier<Options>>) >>
+ dsl::p<Identifier<Options>> >>
lexy::dsl::equal_sign >>
(lexy::dsl::p<Expression<Options>> | lexy::dsl::recurse_branch<StatementListBlock<Options>>);
- static constexpr auto value = lexy::callback<ast::NodePtr>(
- [](const char* pos, auto name, lexy::nullopt = {}) {
- return LEXY_MOV(name);
- },
- [](auto name, lexy::nullopt = {}) {
- return LEXY_MOV(name);
- },
- [](const char* pos, auto name, auto&& initalizer) {
- return ast::make_node_ptr<ast::AssignNode>(pos, LEXY_MOV(name), LEXY_MOV(initalizer));
+ static constexpr auto value = callback<ast::AssignStatement*>(
+ [](ast::ParseState& state, const char* pos, ast::IdentifierValue* name, ast::Value* initializer) {
+ return state.ast().create<ast::AssignStatement>(pos, name, initializer);
});
};
template<ParseOptions Options>
struct StatementListBlock {
static constexpr auto rule =
- lexy::dsl::position(lexy::dsl::curly_bracketed.open()) >>
- lexy::dsl::opt(
- lexy::dsl::list(
- lexy::dsl::recurse_branch<AssignmentStatement<Options>>,
- lexy::dsl::trailing_sep(lexy::dsl::lit_c<','>))) >>
- lexy::dsl::position(lexy::dsl::curly_bracketed.close());
+ dsl::curly_bracketed(
+ lexy::dsl::opt(
+ lexy::dsl::list(
+ lexy::dsl::recurse_branch<AssignmentStatement<Options>>,
+ lexy::dsl::trailing_sep(lexy::dsl::lit_c<','>))));
static constexpr auto value =
- lexy::as_list<std::vector<ast::NodePtr>> >>
- lexy::callback<ast::NodePtr>(
- [](const char* begin, lexy::nullopt, const char* end) {
- return ast::make_node_ptr<ast::ListNode>(ast::NodeLocation::make_from(begin, end));
- },
- [](const char* begin, auto&& list, const char* end) {
- return ast::make_node_ptr<ast::ListNode>(ast::NodeLocation::make_from(begin, end), LEXY_MOV(list));
- },
- [](const char* begin, auto& list, const char* end) {
- return ast::make_node_ptr<ast::ListNode>(ast::NodeLocation::make_from(begin, end), list);
- });
+ lexy::as_list<ast::AssignStatementList> >> construct_list<ast::ListValue>;
};
template<ParseOptions Options = ParseOptions {}>
@@ -107,6 +105,6 @@ namespace ovdl::v2script::lua::grammar {
static constexpr auto rule = lexy::dsl::position + lexy::dsl::terminator(lexy::dsl::eof).opt_list(lexy::dsl::p<AssignmentStatement<Options>>);
- static constexpr auto value = lexy::as_list<std::vector<ast::NodePtr>> >> lexy::new_<ast::FileNode, ast::NodePtr>;
+ static constexpr auto value = lexy::as_list<ast::AssignStatementList> >> construct<ast::FileTree>;
};
} \ No newline at end of file
diff --git a/src/openvic-dataloader/v2script/ModifierGrammar.hpp b/src/openvic-dataloader/v2script/ModifierGrammar.hpp
index 96e928c..5b937d5 100644
--- a/src/openvic-dataloader/v2script/ModifierGrammar.hpp
+++ b/src/openvic-dataloader/v2script/ModifierGrammar.hpp
@@ -2,32 +2,55 @@
#include <openvic-dataloader/v2script/AbstractSyntaxTree.hpp>
+#include <lexy/callback/container.hpp>
#include <lexy/dsl.hpp>
+#include <dryad/node.hpp>
+#include <dryad/tree.hpp>
+
+#include "openvic-dataloader/NodeLocation.hpp"
+
#include "SimpleGrammar.hpp"
#include "TriggerGrammar.hpp"
+#include "detail/dsl.hpp"
namespace ovdl::v2script::grammar {
constexpr auto modifier_keyword = LEXY_KEYWORD("modifier", lexy::dsl::inline_<Identifier<StringEscapeOption>>);
constexpr auto factor_keyword = LEXY_KEYWORD("factor", lexy::dsl::inline_<Identifier<StringEscapeOption>>);
struct FactorStatement {
- static constexpr auto rule = factor_keyword >> lexy::dsl::equal_sign + lexy::dsl::inline_<Identifier<StringEscapeOption>>;
- static constexpr auto value = lexy::as_string<std::string> | lexy::new_<ast::FactorNode, ast::NodePtr>;
+ static constexpr auto rule = lexy::dsl::position(factor_keyword) >> (lexy::dsl::equal_sign + lexy::dsl::p<Identifier<StringEscapeOption>>);
+ static constexpr auto value = dsl::callback<ast::AssignStatement*>(
+ [](ast::ParseState& state, NodeLocation loc, ast::IdentifierValue* value) {
+ auto* factor = state.ast().create<ast::IdentifierValue>(loc, state.ast().intern("factor"));
+ return state.ast().create<ast::AssignStatement>(loc, factor, value);
+ });
+ };
+
+ struct ModifierList {
+ struct expected_factor {
+ static constexpr auto name = "expected factor in modifier";
+ };
+
+ static constexpr auto rule = [] {
+ auto factor_flag = lexy::dsl::context_flag<ModifierList>;
+
+ auto element = (lexy::dsl::p<FactorStatement> >> factor_flag.set()) | lexy::dsl::p<TriggerStatement>;
+
+ return dsl::curly_bracketed.list(factor_flag.create() + element) >> lexy::dsl::must(factor_flag.is_reset()).error<expected_factor>;
+ }();
+
+ static constexpr auto value = lexy::as_list<ast::AssignStatementList> >> construct_list<ast::ListValue>;
};
struct ModifierStatement {
static constexpr auto rule =
- modifier_keyword >>
- lexy::dsl::curly_bracketed.list(
- lexy::dsl::p<FactorStatement> |
- lexy::dsl::p<TriggerList>);
-
- static constexpr auto value =
- lexy::as_list<std::vector<ast::NodePtr>> >>
- lexy::callback<ast::NodePtr>(
- [](auto&& list) {
- return ast::make_node_ptr<ast::ModifierNode>(LEXY_MOV(list));
- });
+ lexy::dsl::position(modifier_keyword) >> lexy::dsl::equal_sign >> lexy::dsl::p<ModifierList>;
+
+ static constexpr auto value = dsl::callback<ast::AssignStatement*>(
+ [](ast::ParseState& state, NodeLocation loc, ast::ListValue* list) {
+ auto* factor = state.ast().create<ast::IdentifierValue>(loc, state.ast().intern("modifier"));
+ return state.ast().create<ast::AssignStatement>(loc, factor, list);
+ });
};
} \ No newline at end of file
diff --git a/src/openvic-dataloader/v2script/Parser.cpp b/src/openvic-dataloader/v2script/Parser.cpp
index 3141550..29e9e80 100644
--- a/src/openvic-dataloader/v2script/Parser.cpp
+++ b/src/openvic-dataloader/v2script/Parser.cpp
@@ -1,29 +1,38 @@
#include "openvic-dataloader/v2script/Parser.hpp"
-#include <functional>
-#include <memory>
+#include <iostream>
#include <optional>
#include <string>
#include <utility>
-#include <vector>
+#include <openvic-dataloader/DiagnosticLogger.hpp>
+#include <openvic-dataloader/NodeLocation.hpp>
#include <openvic-dataloader/ParseError.hpp>
#include <openvic-dataloader/ParseWarning.hpp>
-#include <openvic-dataloader/detail/Concepts.hpp>
+#include <openvic-dataloader/detail/LexyReportError.hpp>
+#include <openvic-dataloader/detail/OStreamOutputIterator.hpp>
+#include <openvic-dataloader/detail/utility/Concepts.hpp>
+#include <openvic-dataloader/detail/utility/Utility.hpp>
#include <openvic-dataloader/v2script/AbstractSyntaxTree.hpp>
-#include <openvic-dataloader/v2script/NodeLocationMap.hpp>
#include <lexy/action/parse.hpp>
#include <lexy/encoding.hpp>
#include <lexy/input/buffer.hpp>
#include <lexy/input/file.hpp>
+#include <lexy/input_location.hpp>
#include <lexy/lexeme.hpp>
#include <lexy/visualize.hpp>
-#include "detail/BasicBufferHandler.hpp"
+#include <dryad/node.hpp>
+#include <dryad/tree.hpp>
+
+#include <fmt/core.h>
+
+#include "openvic-dataloader/Error.hpp"
+
#include "detail/DetectUtf8.hpp"
-#include "detail/LexyReportError.hpp"
-#include "detail/OStreamOutputIterator.hpp"
+#include "detail/NullBuff.hpp"
+#include "detail/ParseHandler.hpp"
#include "detail/Warnings.hpp"
#include "v2script/DecisionGrammar.hpp"
#include "v2script/EventGrammar.hpp"
@@ -35,42 +44,36 @@ using namespace ovdl::v2script;
/// BufferHandler ///
-class Parser::BufferHandler final : public detail::BasicBufferHandler<> {
-public:
+struct Parser::ParseHandler final : detail::BasicStateParseHandler<v2script::ast::ParseState> {
constexpr bool is_exclusive_utf8() const {
- return detail::is_utf8_no_ascii(_buffer);
+ return detail::is_utf8_no_ascii(buffer());
}
- template<typename Node, typename ErrorCallback>
- std::optional<std::vector<ParseError>> parse(const ErrorCallback& callback) {
- auto result = lexy::parse<Node>(_buffer, callback);
+ template<typename Node>
+ std::optional<DiagnosticLogger::error_range> parse() {
+ auto result = lexy::parse<Node>(buffer(), *_parse_state, _parse_state->logger().error_callback());
if (!result) {
- return result.errors();
+ return _parse_state->logger().get_errors();
}
- // This is mighty frustrating
- _root = std::unique_ptr<ast::Node>(result.value());
+ _parse_state->ast().set_root(result.value());
return std::nullopt;
}
- std::unique_ptr<ast::Node>& get_root() {
- return _root;
+ ast::FileTree* root() {
+ return _parse_state->ast().root();
}
-
- ast::NodeLocationMap<decltype(_buffer)>& get_location_map() {
- return _location_map;
- }
-
-private:
- friend class ::ovdl::v2script::ast::Node;
- std::unique_ptr<ast::Node> _root;
- ast::NodeLocationMap<decltype(_buffer)> _location_map;
};
/// BufferHandler ///
Parser::Parser()
- : _buffer_handler(std::make_unique<BufferHandler>()) {
- set_error_log_to_stderr();
+ : _parse_handler(std::make_unique<ParseHandler>()) {
+ set_error_log_to_null();
+}
+
+Parser::Parser(std::basic_ostream<char>& error_stream)
+ : _parse_handler(std::make_unique<ParseHandler>()) {
+ set_error_log_to(error_stream);
}
Parser::Parser(Parser&&) = default;
@@ -116,26 +119,29 @@ Parser Parser::from_file(const std::filesystem::path& path) {
/// @param args
///
template<typename... Args>
-constexpr void Parser::_run_load_func(detail::LoadCallback<BufferHandler, Args...> auto func, Args... args) {
- _warnings.clear();
- _errors.clear();
+constexpr void Parser::_run_load_func(detail::LoadCallback<Parser::ParseHandler*, Args...> auto func, Args... args) {
_has_fatal_error = false;
- if (auto error = func(_buffer_handler.get(), std::forward<Args>(args)...); error) {
- _has_fatal_error = error.value().type == ParseError::Type::Fatal;
- _errors.push_back(error.value());
- _error_stream.get() << "Error: " << _errors.back().message << '\n';
+ auto error = func(_parse_handler.get(), std::forward<Args>(args)...);
+ auto error_message = _parse_handler->make_error_from(error);
+ if (!error_message.empty()) {
+ _has_error = true;
+ _has_fatal_error = true;
+ _parse_handler->parse_state().logger().create_log<error::BufferError>(DiagnosticLogger::DiagnosticKind::error, fmt::runtime(error_message));
+ }
+ if (has_error() && &_error_stream.get() != &detail::cnull) {
+ print_errors_to(_error_stream.get());
}
}
constexpr Parser& Parser::load_from_buffer(const char* data, std::size_t size) {
// Type can't be deduced?
- _run_load_func(std::mem_fn(&BufferHandler::load_buffer_size), data, size);
+ _run_load_func(std::mem_fn(&ParseHandler::load_buffer_size), data, size);
return *this;
}
constexpr Parser& Parser::load_from_buffer(const char* start, const char* end) {
// Type can't be deduced?
- _run_load_func(std::mem_fn(&BufferHandler::load_buffer), start, end);
+ _run_load_func(std::mem_fn(&ParseHandler::load_buffer), start, end);
return *this;
}
@@ -146,7 +152,7 @@ constexpr Parser& Parser::load_from_string(const std::string_view string) {
constexpr Parser& Parser::load_from_file(const char* path) {
_file_path = path;
// Type can be deduced??
- _run_load_func(std::mem_fn(&BufferHandler::load_file), path);
+ _run_load_func(std::mem_fn(&ParseHandler::load_file), path);
return *this;
}
@@ -154,10 +160,6 @@ Parser& Parser::load_from_file(const std::filesystem::path& path) {
return load_from_file(path.string().c_str());
}
-constexpr Parser& Parser::load_from_file(const detail::Has_c_str auto& path) {
- return load_from_file(path.c_str());
-}
-
/* REQUIREMENTS:
* DAT-23
* DAT-26
@@ -165,149 +167,175 @@ constexpr Parser& Parser::load_from_file(const detail::Has_c_str auto& path) {
* DAT-29
*/
bool Parser::simple_parse() {
- if (!_buffer_handler->is_valid()) {
+ if (!_parse_handler->is_valid()) {
return false;
}
- if (_buffer_handler->is_exclusive_utf8()) {
- _warnings.push_back(warnings::make_utf8_warning(_file_path));
+ if (_parse_handler->is_exclusive_utf8()) {
+ _parse_handler->parse_state().logger().warning(warnings::make_utf8_warning(_file_path));
}
- auto errors = _buffer_handler->parse<grammar::File<grammar::NoStringEscapeOption>>(ovdl::detail::ReporError.path(_file_path).to(detail::OStreamOutputIterator { _error_stream }));
- if (errors) {
- _errors.reserve(errors->size());
- for (auto& err : errors.value()) {
- _has_fatal_error |= err.type == ParseError::Type::Fatal;
- _errors.push_back(err);
+ auto errors = _parse_handler->parse<grammar::File<grammar::NoStringEscapeOption>>();
+ _has_error = _parse_handler->parse_state().logger().errored();
+ _has_warning = _parse_handler->parse_state().logger().warned();
+ if (!_parse_handler->root()) {
+ _has_fatal_error = true;
+ if (&_error_stream.get() != &detail::cnull) {
+ print_errors_to(_error_stream);
}
return false;
}
- _file_node.reset(static_cast<ast::FileNode*>(_buffer_handler->get_root().release()));
return true;
}
bool Parser::event_parse() {
- if (!_buffer_handler->is_valid()) {
+ if (!_parse_handler->is_valid()) {
return false;
}
- if (_buffer_handler->is_exclusive_utf8()) {
- _warnings.push_back(warnings::make_utf8_warning(_file_path));
+ if (_parse_handler->is_exclusive_utf8()) {
+ _parse_handler->parse_state().logger().warning(warnings::make_utf8_warning(_file_path));
}
- auto errors = _buffer_handler->parse<grammar::EventFile>(ovdl::detail::ReporError.path(_file_path).to(detail::OStreamOutputIterator { _error_stream }));
- if (errors) {
- _errors.reserve(errors->size());
- for (auto& err : errors.value()) {
- _has_fatal_error |= err.type == ParseError::Type::Fatal;
- _errors.push_back(err);
+ auto errors = _parse_handler->parse<grammar::EventFile>();
+ _has_error = _parse_handler->parse_state().logger().errored();
+ _has_warning = _parse_handler->parse_state().logger().warned();
+ if (!_parse_handler->root()) {
+ _has_fatal_error = true;
+ if (&_error_stream.get() != &detail::cnull) {
+ print_errors_to(_error_stream);
}
return false;
}
- _file_node.reset(static_cast<ast::FileNode*>(_buffer_handler->get_root().release()));
return true;
}
bool Parser::decision_parse() {
- if (!_buffer_handler->is_valid()) {
+ if (!_parse_handler->is_valid()) {
return false;
}
- if (_buffer_handler->is_exclusive_utf8()) {
- _warnings.push_back(warnings::make_utf8_warning(_file_path));
+ if (_parse_handler->is_exclusive_utf8()) {
+ _parse_handler->parse_state().logger().warning(warnings::make_utf8_warning(_file_path));
}
- auto errors = _buffer_handler->parse<grammar::DecisionFile>(ovdl::detail::ReporError.path(_file_path).to(detail::OStreamOutputIterator { _error_stream }));
- if (errors) {
- _errors.reserve(errors->size());
- for (auto& err : errors.value()) {
- _has_fatal_error |= err.type == ParseError::Type::Fatal;
- _errors.push_back(err);
+ auto errors = _parse_handler->parse<grammar::DecisionFile>();
+ _has_error = _parse_handler->parse_state().logger().errored();
+ _has_warning = _parse_handler->parse_state().logger().warned();
+ if (!_parse_handler->root()) {
+ _has_fatal_error = true;
+ if (&_error_stream.get() != &detail::cnull) {
+ print_errors_to(_error_stream);
}
return false;
}
- _file_node.reset(static_cast<ast::FileNode*>(_buffer_handler->get_root().release()));
return true;
}
bool Parser::lua_defines_parse() {
- if (!_buffer_handler->is_valid()) {
+ if (!_parse_handler->is_valid()) {
return false;
}
- if (_buffer_handler->is_exclusive_utf8()) {
- _warnings.push_back(warnings::make_utf8_warning(_file_path));
+ if (_parse_handler->is_exclusive_utf8()) {
+ _parse_handler->parse_state().logger().warning(warnings::make_utf8_warning(_file_path));
}
- auto errors = _buffer_handler->parse<lua::grammar::File<>>(ovdl::detail::ReporError.path(_file_path).to(detail::OStreamOutputIterator { _error_stream }));
- if (errors) {
- _errors.reserve(errors->size());
- for (auto& err : errors.value()) {
- _has_fatal_error |= err.type == ParseError::Type::Fatal;
- _errors.push_back(err);
+ auto errors = _parse_handler->parse<lua::grammar::File<>>();
+ _has_error = _parse_handler->parse_state().logger().errored();
+ _has_warning = _parse_handler->parse_state().logger().warned();
+ if (!_parse_handler->root()) {
+ _has_fatal_error = true;
+ if (&_error_stream.get() != &detail::cnull) {
+ print_errors_to(_error_stream);
}
return false;
}
- _file_node.reset(static_cast<ast::FileNode*>(_buffer_handler->get_root().release()));
return true;
}
-const FileNode* Parser::get_file_node() const {
- return _file_node.get();
+const FileTree* Parser::get_file_node() const {
+ return _parse_handler->root();
}
-void Parser::generate_node_location_map() {
- _buffer_handler->get_location_map().clear();
- _buffer_handler->get_location_map().generate_location_map(_buffer_handler->get_buffer(), get_file_node());
+std::string_view Parser::value(const ovdl::v2script::ast::FlatValue& node) const {
+ return node.value(_parse_handler->parse_state().ast().symbol_interner());
}
-const ast::Node::line_col Parser::get_node_begin(const ast::NodeCPtr node) const {
- if (!node) return { 0, 0 };
- return node->get_begin_line_col(*this);
+std::string Parser::make_native_string() const {
+ return _parse_handler->parse_state().ast().make_native_visualizer();
}
-const ast::Node::line_col Parser::get_node_end(const ast::NodeCPtr node) const {
- if (!node) return { 0, 0 };
- return node->get_end_line_col(*this);
+std::string Parser::make_list_string() const {
+ return _parse_handler->parse_state().ast().make_list_visualizer();
}
-const ast::Node::line_col ast::Node::get_begin_line_col(const Parser& parser) const {
- if (!parser._buffer_handler->is_valid() || parser._buffer_handler->_location_map.empty()) return {};
- line_col result {};
- auto [itr, range_end] = parser._buffer_handler->_location_map.equal_range(this);
- if (itr != range_end) {
- result.line = itr->second.line_nr();
- result.column = itr->second.column_nr();
+const FilePosition Parser::get_position(const ast::Node* node) const {
+ if (!node || !node->is_linked_in_tree()) {
+ return {};
}
- // Standard doesn't really guarantee the direction of the range's sequence, but only GCC goes backwards
- // TODO: DON'T USE STANDARD UNORDERED_MULTIMAP
-#if defined(__GNUC__) && !defined(__clang__)
- itr++;
- if (itr != range_end) {
- result.line = itr->second.line_nr();
- result.column = itr->second.column_nr();
+ auto node_location = _parse_handler->parse_state().ast().location_of(node);
+ if (node_location.is_synthesized()) {
+ return {};
+ }
+
+ auto loc_begin = lexy::get_input_location(_parse_handler->buffer(), node_location.begin());
+ FilePosition result { loc_begin.line_nr(), loc_begin.line_nr(), loc_begin.column_nr(), loc_begin.column_nr() };
+ if (node_location.begin() < node_location.end()) {
+ auto loc_end = lexy::get_input_location(_parse_handler->buffer(), node_location.end(), loc_begin.anchor());
+ result.end_line = loc_end.line_nr();
+ result.end_column = loc_end.column_nr();
}
-#endif
return result;
}
-const ast::Node::line_col ast::Node::get_end_line_col(const Parser& parser) const {
- if (!parser._buffer_handler->is_valid() || parser._buffer_handler->_location_map.empty()) return {};
- line_col result {};
- auto [itr, range_end] = parser._buffer_handler->_location_map.equal_range(this);
- if (itr != range_end) {
- result.line = itr->second.line_nr();
- result.column = itr->second.column_nr();
+Parser::error_range Parser::get_errors() const {
+ return _parse_handler->parse_state().logger().get_errors();
+}
+
+const FilePosition Parser::get_error_position(const error::Error* error) const {
+ if (!error || !error->is_linked_in_tree()) {
+ return {};
}
- // Standard doesn't really guarantee the direction of the range's sequence, but only GCC goes backwards
- // TODO: DON'T USE STANDARD UNORDERED_MULTIMAP
-#if defined(__GNUC__) && !defined(__clang__)
- return result;
-#endif
- itr++;
- if (itr != range_end) {
- result.line = itr->second.line_nr();
- result.column = itr->second.column_nr();
+ auto err_location = _parse_handler->parse_state().logger().location_of(error);
+ if (err_location.is_synthesized()) {
+ return {};
+ }
+
+ auto loc_begin = lexy::get_input_location(_parse_handler->buffer(), err_location.begin());
+ FilePosition result { loc_begin.line_nr(), loc_begin.line_nr(), loc_begin.column_nr(), loc_begin.column_nr() };
+ if (err_location.begin() < err_location.end()) {
+ auto loc_end = lexy::get_input_location(_parse_handler->buffer(), err_location.end(), loc_begin.anchor());
+ result.end_line = loc_end.line_nr();
+ result.end_column = loc_end.column_nr();
}
return result;
+}
+
+void Parser::print_errors_to(std::basic_ostream<char>& stream) const {
+ auto errors = get_errors();
+ if (errors.empty()) return;
+ for (const auto error : errors) {
+ dryad::visit_tree(
+ error,
+ [&](const error::BufferError* buffer_error) {
+ stream << buffer_error->message() << '\n';
+ },
+ [&](const error::ParseError* parse_error) {
+ stream << parse_error->message() << '\n';
+ },
+ [&](dryad::child_visitor<error::ErrorKind> visitor, const error::Semantic* semantic) {
+ stream << semantic->message() << '\n';
+ auto annotations = semantic->annotations();
+ for (auto annotation : annotations) {
+ visitor(annotation);
+ }
+ },
+ [&](const error::PrimaryAnnotation* primary) {
+ stream << primary->message() << '\n';
+ },
+ [&](const error::SecondaryAnnotation* secondary) {
+ stream << secondary->message() << '\n';
+ });
+ }
} \ No newline at end of file
diff --git a/src/openvic-dataloader/v2script/SimpleGrammar.hpp b/src/openvic-dataloader/v2script/SimpleGrammar.hpp
index 7a59123..bd4adaa 100644
--- a/src/openvic-dataloader/v2script/SimpleGrammar.hpp
+++ b/src/openvic-dataloader/v2script/SimpleGrammar.hpp
@@ -1,14 +1,12 @@
#pragma once
-#include <string>
-#include <vector>
-
+#include <openvic-dataloader/NodeLocation.hpp>
#include <openvic-dataloader/v2script/AbstractSyntaxTree.hpp>
#include <lexy/callback.hpp>
#include <lexy/dsl.hpp>
-#include "detail/LexyLitRange.hpp"
+#include "detail/dsl.hpp"
// Grammar Definitions //
/* REQUIREMENTS:
@@ -21,6 +19,11 @@
* DAT-643
*/
namespace ovdl::v2script::grammar {
+ template<typename T>
+ constexpr auto construct = dsl::construct<ast::ParseState, T>;
+ template<typename T, bool DisableEmpty = false, typename ListType = ast::AssignStatementList>
+ constexpr auto construct_list = dsl::construct_list<ast::ParseState, T, ListType, DisableEmpty>;
+
struct ParseOptions {
/// @brief Makes string parsing avoid string escapes
bool NoStringEscape;
@@ -29,11 +32,6 @@ namespace ovdl::v2script::grammar {
static constexpr ParseOptions NoStringEscapeOption = ParseOptions { true };
static constexpr ParseOptions StringEscapeOption = ParseOptions { false };
- template<ParseOptions Options>
- struct StatementListBlock;
- template<ParseOptions Options>
- struct AssignmentStatement;
-
/* REQUIREMENTS: DAT-630 */
static constexpr auto whitespace_specifier = lexy::dsl::ascii::blank / lexy::dsl::ascii::newline;
/* REQUIREMENTS: DAT-631 */
@@ -47,18 +45,18 @@ namespace ovdl::v2script::grammar {
lexy::dsl::ascii::alpha_digit_underscore / LEXY_ASCII_ONE_OF("+:@%&'-.") /
lexy::dsl::lit_b<0x8A> / lexy::dsl::lit_b<0x8C> / lexy::dsl::lit_b<0x8E> /
lexy::dsl::lit_b<0x92> / lexy::dsl::lit_b<0x97> / lexy::dsl::lit_b<0x9A> / lexy::dsl::lit_b<0x9C> /
- detail::lexydsl::make_range<0x9E, 0x9F>() /
- detail::lexydsl::make_range<0xC0, 0xD6>() /
- detail::lexydsl::make_range<0xD8, 0xF6>() /
- detail::lexydsl::make_range<0xF8, 0xFF>();
+ dsl::make_range<0x9E, 0x9F>() /
+ dsl::make_range<0xC0, 0xD6>() /
+ dsl::make_range<0xD8, 0xF6>() /
+ dsl::make_range<0xF8, 0xFF>();
static constexpr auto windows_1251_data_specifier_additions =
- detail::lexydsl::make_range<0x80, 0x81>() / lexy::dsl::lit_b<0x83> / lexy::dsl::lit_b<0x8D> / lexy::dsl::lit_b<0x8F> /
+ dsl::make_range<0x80, 0x81>() / lexy::dsl::lit_b<0x83> / lexy::dsl::lit_b<0x8D> / lexy::dsl::lit_b<0x8F> /
lexy::dsl::lit_b<0x90> / lexy::dsl::lit_b<0x9D> / lexy::dsl::lit_b<0x9F> /
- detail::lexydsl::make_range<0xA1, 0xA3>() / lexy::dsl::lit_b<0xA5> / lexy::dsl::lit_b<0xA8> / lexy::dsl::lit_b<0xAA> /
+ dsl::make_range<0xA1, 0xA3>() / lexy::dsl::lit_b<0xA5> / lexy::dsl::lit_b<0xA8> / lexy::dsl::lit_b<0xAA> /
lexy::dsl::lit_b<0xAF> /
- detail::lexydsl::make_range<0xB2, 0xB4>() / lexy::dsl::lit_b<0xB8> / lexy::dsl::lit_b<0xBA> /
- detail::lexydsl::make_range<0xBC, 0xBF>() /
+ dsl::make_range<0xB2, 0xB4>() / lexy::dsl::lit_b<0xB8> / lexy::dsl::lit_b<0xBA> /
+ dsl::make_range<0xBC, 0xBF>() /
lexy::dsl::lit_b<0xD7> / lexy::dsl::lit_b<0xF7>;
static constexpr auto data_specifier = windows_1252_data_specifier / windows_1251_data_specifier_additions;
@@ -77,125 +75,145 @@ namespace ovdl::v2script::grammar {
.map<'t'>('\t');
template<ParseOptions Options>
- struct Identifier {
- static constexpr auto rule = lexy::dsl::identifier(data_char_class);
- static constexpr auto value = lexy::callback<ast::NodePtr>(
- [](auto lexeme) {
- std::string str(lexeme.data(), lexeme.size());
- return ast::make_node_ptr<ast::IdentifierNode>(ast::NodeLocation { lexeme.begin(), lexeme.end() }, LEXY_MOV(str));
- });
- };
-
- /* REQUIREMENTS:
- * DAT-633
- * DAT-634
- */
- template<ParseOptions Options>
- struct StringExpression {
- static constexpr auto rule = [] {
- if constexpr (Options.NoStringEscape) {
- auto c = ovdl::detail::lexydsl::make_range<0x20, 0xFF>() / lexy::dsl::lit_b<0x07> / lexy::dsl::lit_b<0x09> / lexy::dsl::lit_b<0x0A> / lexy::dsl::lit_b<0x0D>;
- return lexy::dsl::delimited(lexy::dsl::position(lexy::dsl::lit_b<'"'>))(c);
- } else {
- // Arbitrary code points that aren't control characters.
- auto c = ovdl::detail::lexydsl::make_range<0x20, 0xFF>() - lexy::dsl::ascii::control;
-
- // Escape sequences start with a backlash.
- // They either map one of the symbols,
- // or a Unicode code point of the form uXXXX.
- auto escape = lexy::dsl::backslash_escape //
- .symbol<escaped_symbols>();
- return lexy::dsl::delimited(lexy::dsl::position(lexy::dsl::lit_b<'"'>))(c, escape);
- }
- }();
-
- static constexpr auto value =
- lexy::as_string<std::string> >>
- lexy::callback<ast::NodePtr>(
- [](const char* begin, auto&& str, const char* end) {
- return ast::make_node_ptr<ast::StringNode>(ast::NodeLocation::make_from(begin, end), LEXY_MOV(str), Options.NoStringEscape);
+ struct SimpleGrammar {
+ struct StatementListBlock;
+
+ struct Identifier {
+ static constexpr auto rule = lexy::dsl::identifier(data_char_class);
+ static constexpr auto value = dsl::callback<ast::IdentifierValue*>(
+ [](ast::ParseState& state, auto lexeme) {
+ auto value = state.ast().intern(lexeme.data(), lexeme.size());
+ return state.ast().create<ast::IdentifierValue>(ovdl::NodeLocation::make_from(lexeme.begin(), lexeme.end()), value);
});
- };
-
- /* REQUIREMENTS: DAT-638 */
- template<ParseOptions Options>
- struct ValueExpression {
- static constexpr auto rule = lexy::dsl::p<Identifier<Options>> | lexy::dsl::p<StringExpression<Options>>;
- static constexpr auto value = lexy::forward<ast::NodePtr>;
+ };
+
+ /* REQUIREMENTS:
+ * DAT-633
+ * DAT-634
+ */
+ struct StringExpression {
+ static constexpr auto rule = [] {
+ if constexpr (Options.NoStringEscape) {
+ auto c = dsl::make_range<0x20, 0xFF>() / lexy::dsl::lit_b<0x07> / lexy::dsl::lit_b<0x09> / lexy::dsl::lit_b<0x0A> / lexy::dsl::lit_b<0x0D>;
+ return lexy::dsl::delimited(lexy::dsl::position(lexy::dsl::lit_b<'"'>))(c);
+ } else {
+ // Arbitrary code points that aren't control characters.
+ auto c = dsl::make_range<0x20, 0xFF>() - lexy::dsl::ascii::control;
+
+ // Escape sequences start with a backlash.
+ // They either map one of the symbols,
+ // or a Unicode code point of the form uXXXX.
+ auto escape = lexy::dsl::backslash_escape //
+ .symbol<escaped_symbols>();
+ return lexy::dsl::delimited(lexy::dsl::position(lexy::dsl::lit_b<'"'>))(c, escape);
+ }
+ }();
+
+ static constexpr auto value =
+ lexy::as_string<std::string> >>
+ dsl::callback<ast::StringValue*>(
+ [](ast::ParseState& state, const char* begin, auto&& str, const char* end) {
+ auto value = state.ast().intern(str.data(), str.length());
+ return state.ast().create<ast::StringValue>(ovdl::NodeLocation::make_from(begin, end), value);
+ });
+ };
+
+ /* REQUIREMENTS: DAT-638 */
+ struct ValueExpression {
+ static constexpr auto rule = lexy::dsl::p<Identifier> | lexy::dsl::p<StringExpression>;
+ static constexpr auto value = lexy::forward<ast::Value*>;
+ };
+
+ struct SimpleAssignmentStatement {
+ static constexpr auto rule =
+ dsl::p<Identifier> >>
+ (lexy::dsl::equal_sign >>
+ (lexy::dsl::p<ValueExpression> | lexy::dsl::recurse_branch<StatementListBlock>));
+
+ static constexpr auto value = construct<ast::AssignStatement>;
+ };
+
+ /* REQUIREMENTS: DAT-639 */
+ struct AssignmentStatement {
+ static constexpr auto rule =
+ dsl::p<Identifier> >>
+ (lexy::dsl::equal_sign >>
+ (lexy::dsl::p<ValueExpression> | lexy::dsl::recurse_branch<StatementListBlock>) |
+ lexy::dsl::else_ >> lexy::dsl::return_) |
+ dsl::p<StringExpression> |
+ lexy::dsl::recurse_branch<StatementListBlock>;
+
+ static constexpr auto value = dsl::callback<ast::Statement*>(
+ [](ast::ParseState& state, const char* pos, ast::IdentifierValue* name, ast::Value* initializer) {
+ return state.ast().create<ast::AssignStatement>(pos, name, initializer);
+ },
+ [](ast::ParseState& state, const char* pos, ast::Value* left, lexy::nullopt = {}) {
+ return state.ast().create<ast::ValueStatement>(pos, left);
+ },
+ [](ast::ParseState& state, ast::Value* left) {
+ return state.ast().create<ast::ValueStatement>(state.ast().location_of(left), left);
+ });
+ };
+
+ /* REQUIREMENTS: DAT-640 */
+ struct StatementListBlock {
+ static constexpr auto rule =
+ dsl::curly_bracketed(
+ (lexy::dsl::opt(lexy::dsl::list(lexy::dsl::recurse_branch<AssignmentStatement>)) +
+ lexy::dsl::opt(lexy::dsl::semicolon)));
+
+ static constexpr auto value =
+ lexy::as_list<ast::StatementList> >>
+ dsl::callback<ast::ListValue*>(
+ [](ast::ParseState& state, const char* begin, auto&& list, const char* end) {
+ if constexpr (std::is_same_v<std::decay_t<decltype(list)>, lexy::nullopt>) {
+ return state.ast().create<ast::ListValue>(ovdl::NodeLocation::make_from(begin, end));
+ } else {
+ return state.ast().create<ast::ListValue>(ovdl::NodeLocation::make_from(begin, end), LEXY_MOV(list));
+ }
+ },
+ [](ast::ParseState& state, const char* begin, auto&& list, auto&& semicolon, const char* end) {
+ if constexpr (std::is_same_v<std::decay_t<decltype(list)>, lexy::nullopt>) {
+ return state.ast().create<ast::ListValue>(ovdl::NodeLocation::make_from(begin, end));
+ } else {
+ return state.ast().create<ast::ListValue>(ovdl::NodeLocation::make_from(begin, end), LEXY_MOV(list));
+ }
+ });
+ };
};
template<ParseOptions Options>
- struct SimpleAssignmentStatement {
- static constexpr auto rule =
- lexy::dsl::position(lexy::dsl::p<Identifier<Options>>) >>
- (lexy::dsl::equal_sign +
- (lexy::dsl::p<ValueExpression<Options>> | lexy::dsl::recurse_branch<StatementListBlock<Options>>));
-
- static constexpr auto value = lexy::callback<ast::NodePtr>(
- [](const char* pos, auto name, auto&& initalizer) {
- return ast::make_node_ptr<ast::AssignNode>(pos, LEXY_MOV(name), LEXY_MOV(initalizer));
- });
- };
+ using StringExpression = typename SimpleGrammar<Options>::StringExpression;
- /* REQUIREMENTS: DAT-639 */
template<ParseOptions Options>
- struct AssignmentStatement {
- static constexpr auto rule =
- lexy::dsl::position(lexy::dsl::p<Identifier<Options>>) >>
- (lexy::dsl::equal_sign >>
- (lexy::dsl::p<ValueExpression<Options>> | lexy::dsl::recurse_branch<StatementListBlock<Options>>) |
- lexy::dsl::else_ >> lexy::dsl::return_) |
- lexy::dsl::p<StringExpression<Options>> |
- lexy::dsl::recurse_branch<StatementListBlock<Options>>;
-
- static constexpr auto value = lexy::callback<ast::NodePtr>(
- [](const char* pos, auto name, lexy::nullopt = {}) {
- return LEXY_MOV(name);
- },
- [](auto name, lexy::nullopt = {}) {
- return LEXY_MOV(name);
- },
- [](const char* pos, auto name, auto&& initalizer) {
- return ast::make_node_ptr<ast::AssignNode>(pos, LEXY_MOV(name), LEXY_MOV(initalizer));
- });
- };
+ using Identifier = typename SimpleGrammar<Options>::Identifier;
- /* REQUIREMENTS: DAT-640 */
template<ParseOptions Options>
- struct StatementListBlock {
- static constexpr auto rule =
- lexy::dsl::position(lexy::dsl::curly_bracketed.open()) >>
- (lexy::dsl::opt(lexy::dsl::list(lexy::dsl::recurse_branch<AssignmentStatement<Options>>)) +
- lexy::dsl::opt(lexy::dsl::semicolon)) >>
- lexy::dsl::position(lexy::dsl::curly_bracketed.close());
-
- static constexpr auto value =
- lexy::as_list<std::vector<ast::NodePtr>> >>
- lexy::callback<ast::NodePtr>(
- [](const char* begin, lexy::nullopt, const char* end) {
- return ast::make_node_ptr<ast::ListNode>(ast::NodeLocation::make_from(begin, end));
- },
- [](const char* begin, auto&& list, const char* end) {
- return ast::make_node_ptr<ast::ListNode>(ast::NodeLocation::make_from(begin, end), LEXY_MOV(list));
- },
- [](const char* begin, lexy::nullopt, lexy::nullopt, const char* end) {
- return ast::make_node_ptr<ast::ListNode>(ast::NodeLocation::make_from(begin, end));
- },
- [](const char* begin, auto&& list, lexy::nullopt, const char* end) {
- return ast::make_node_ptr<ast::ListNode>(ast::NodeLocation::make_from(begin, end), LEXY_MOV(list));
- },
- [](const char* begin, auto& list, const char* end) {
- return ast::make_node_ptr<ast::ListNode>(ast::NodeLocation::make_from(begin, end), list);
- });
- };
+ using SAssignStatement = typename SimpleGrammar<Options>::SimpleAssignmentStatement;
+
+ template<ovdl::detail::string_literal Keyword, auto Production, auto Value = dsl::default_kw_value<ast::ParseState, ast::IdentifierValue, Keyword>>
+ using keyword_rule = dsl::keyword_rule<
+ ast::ParseState,
+ Identifier<StringEscapeOption>,
+ ast::AssignStatement,
+ Keyword, Production, Value>;
+
+ template<ovdl::detail::string_literal Keyword, auto Production, auto Value = dsl::default_kw_value<ast::ParseState, ast::IdentifierValue, Keyword>>
+ using fkeyword_rule = dsl::fkeyword_rule<
+ ast::ParseState,
+ Identifier<StringEscapeOption>,
+ ast::AssignStatement,
+ Keyword, Production, Value>;
template<ParseOptions Options>
struct File {
// Allow arbitrary spaces between individual tokens.
static constexpr auto whitespace = whitespace_specifier | comment_specifier;
- static constexpr auto rule = lexy::dsl::position + lexy::dsl::terminator(lexy::dsl::eof).opt_list(lexy::dsl::p<AssignmentStatement<Options>>);
+ static constexpr auto rule = lexy::dsl::position(
+ lexy::dsl::terminator(lexy::dsl::eof)
+ .opt_list(lexy::dsl::p<typename SimpleGrammar<Options>::AssignmentStatement>));
- static constexpr auto value = lexy::as_list<std::vector<ast::NodePtr>> >> lexy::new_<ast::FileNode, ast::NodePtr>;
+ static constexpr auto value = lexy::as_list<ast::StatementList> >> construct<ast::FileTree>;
};
}
diff --git a/src/openvic-dataloader/v2script/TriggerGrammar.hpp b/src/openvic-dataloader/v2script/TriggerGrammar.hpp
index 3849b12..095d115 100644
--- a/src/openvic-dataloader/v2script/TriggerGrammar.hpp
+++ b/src/openvic-dataloader/v2script/TriggerGrammar.hpp
@@ -6,37 +6,24 @@
#include <lexy/dsl.hpp>
#include "SimpleGrammar.hpp"
+#include "detail/dsl.hpp"
namespace ovdl::v2script::grammar {
struct TriggerStatement {
- static constexpr auto rule = lexy::dsl::inline_<SimpleAssignmentStatement<StringEscapeOption>>;
+ static constexpr auto rule = lexy::dsl::p<SAssignStatement<StringEscapeOption>>;
- static constexpr auto value = lexy::callback<ast::NodePtr>(
- [](auto name, auto&& initalizer) {
- return ast::make_node_ptr<ast::ExecutionNode>({}, ast::ExecutionNode::Type::Trigger, LEXY_MOV(name), LEXY_MOV(initalizer));
- });
+ static constexpr auto value = lexy::forward<ast::AssignStatement*>;
};
struct TriggerList {
- static constexpr auto rule = lexy::dsl::list(lexy::dsl::p<SimpleAssignmentStatement<StringEscapeOption>>);
-
- static constexpr auto value =
- lexy::as_list<std::vector<ast::NodePtr>> >>
- lexy::callback<ast::NodePtr>(
- [](auto&& list) {
- return ast::make_node_ptr<ast::ExecutionListNode>(ast::ExecutionNode::Type::Trigger, LEXY_MOV(list));
- });
+ static constexpr auto rule = lexy::dsl::list(lexy::dsl::p<TriggerStatement>);
+
+ static constexpr auto value = lexy::as_list<ast::AssignStatementList>;
};
struct TriggerBlock {
- static constexpr auto rule = lexy::dsl::curly_bracketed.opt(lexy::dsl::p<TriggerList>);
-
- static constexpr auto value = lexy::callback<ast::NodePtr>(
- [](auto&& list) {
- return LEXY_MOV(list);
- },
- [](lexy::nullopt = {}) {
- return lexy::nullopt {};
- });
+ static constexpr auto rule = dsl::curly_bracketed.opt(lexy::dsl::p<TriggerList>);
+
+ static constexpr auto value = construct_list<ast::ListValue>;
};
} \ No newline at end of file