aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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/LexyReportError.hpp106
-rw-r--r--src/openvic-dataloader/detail/NullBuff.hpp8
-rw-r--r--src/openvic-dataloader/detail/OStreamOutputIterator.hpp21
-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
30 files changed, 1554 insertions, 1301 deletions
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/LexyReportError.hpp b/src/openvic-dataloader/detail/LexyReportError.hpp
deleted file mode 100644
index 213090b..0000000
--- a/src/openvic-dataloader/detail/LexyReportError.hpp
+++ /dev/null
@@ -1,106 +0,0 @@
-#pragma once
-
-#include <cstddef>
-#include <sstream>
-#include <utility>
-#include <vector>
-
-#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 <lexy_ext/report_error.hpp>
-
-namespace ovdl::detail {
- template<typename OutputIterator>
- struct _ReportError {
- OutputIterator _iter;
- lexy::visualization_options _opts;
- const char* _path;
-
- struct _sink {
- OutputIterator _iter;
- lexy::visualization_options _opts;
- const char* _path;
- std::size_t _count;
- std::vector<ParseError> _errors;
-
- using return_type = std::vector<ParseError>;
-
- template<typename Input, typename Reader, typename Tag>
- void operator()(const lexy::error_context<Input>& context, const lexy::error<Reader, Tag>& error) {
- _iter = lexy_ext::_detail::write_error(_iter, context, error, _opts, _path);
- ++_count;
-
- // Convert the context location and error location into line/column information.
- auto context_location = lexy::get_input_location(context.input(), context.position());
- auto location = lexy::get_input_location(context.input(), error.position(), context_location.anchor());
-
- std::basic_stringstream<typename Reader::encoding::char_type> message;
-
- // Write the main annotation.
- if constexpr (std::is_same_v<Tag, lexy::expected_literal>) {
- auto string = lexy::_detail::make_literal_lexeme<typename Reader::encoding>(error.string(), error.length());
-
- message << "expected '" << string.data() << '\'';
- } 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());
-
- message << "expected keyword '" << string.data() << '\'';
- } else if constexpr (std::is_same_v<Tag, lexy::expected_char_class>) {
- message << "expected " << error.name();
- } else {
- message << error.message();
- }
-
- _errors.push_back(
- ParseError {
- ParseError::Type::Fatal, // TODO: distinguish recoverable errors from fatal errors
- std::move(message.str()),
- 0, // TODO: implement proper error codes
- ParseData {
- context.production(),
- context_location.line_nr(),
- context_location.column_nr(),
- },
- location.line_nr(),
- location.column_nr(),
- });
- }
-
- return_type finish() && {
- if (_count != 0)
- *_iter++ = '\n';
- return _errors;
- }
- };
- constexpr auto sink() const {
- return _sink { _iter, _opts, _path, 0 };
- }
-
- /// Specifies a path that will be printed alongside the diagnostic.
- constexpr _ReportError path(const char* path) const {
- return { _iter, _opts, path };
- }
-
- constexpr _ReportError path(const detail::Has_c_str auto& path_object) const {
- return path(path_object.c_str());
- }
-
- /// Specifies an output iterator where the errors are written to.
- template<typename OI>
- constexpr _ReportError<OI> to(OI out) const {
- return { out, _opts, _path };
- }
-
- /// Overrides visualization options.
- constexpr _ReportError opts(lexy::visualization_options opts) const {
- return { _iter, opts, _path };
- }
- };
-
- constexpr auto ReporError = _ReportError<lexy::stderr_output_iterator> {};
-} \ 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/OStreamOutputIterator.hpp b/src/openvic-dataloader/detail/OStreamOutputIterator.hpp
deleted file mode 100644
index 81f6c89..0000000
--- a/src/openvic-dataloader/detail/OStreamOutputIterator.hpp
+++ /dev/null
@@ -1,21 +0,0 @@
-#pragma once
-
-#include <ostream>
-
-namespace ovdl::detail {
- struct OStreamOutputIterator {
- std::reference_wrapper<std::ostream> _stream;
-
- auto operator*() const noexcept {
- return *this;
- }
- auto operator++(int) const noexcept {
- return *this;
- }
-
- OStreamOutputIterator& operator=(char c) {
- _stream.get().put(c);
- return *this;
- }
- };
-} \ 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