aboutsummaryrefslogtreecommitdiff
path: root/src/openvic-dataloader/v2script
diff options
context:
space:
mode:
author Spartan322 <Megacake1234@gmail.com>2023-11-28 11:09:26 +0100
committer Spartan322 <Megacake1234@gmail.com>2024-05-09 22:11:26 +0200
commit757114a3c5b748567b42f273c7b78ca039ae983c (patch)
treee07390b682052129c91f4b157068bcdd84ceecb4 /src/openvic-dataloader/v2script
parent7211a228e68c8a6b1ad1c1c5ec68c8d720b6d2ba (diff)
Add `deps/dryad` -> https://github.com/Spartan322/dryadadd/dryad
Add `deps/fmt` -> https://github.com/fmtlib/fmt Add `deps/range-v3` -> https://github.com/ericniebler/range-v3 Improve parser error and warning support Update .clang-format Update `deps/SCsub`
Diffstat (limited to 'src/openvic-dataloader/v2script')
-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
10 files changed, 629 insertions, 870 deletions
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