aboutsummaryrefslogtreecommitdiff
path: root/src/openvic-dataloader/v2script/LuaDefinesGrammar.hpp
blob: 885413c3c58960484ed52bb833b0d3896475cbfa (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#pragma once

#include <openvic-dataloader/v2script/AbstractSyntaxTree.hpp>

#include <lexy/_detail/config.hpp>
#include <lexy/dsl.hpp>
#include <lexy/dsl/delimited.hpp>
#include <lexy/dsl/recover.hpp>
#include <lexy/dsl/unicode.hpp>

#include "SimpleGrammar.hpp"
#include "detail/InternalConcepts.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 StatementListBlock;

   static constexpr auto comment_specifier = LEXY_LIT("--") >> lexy::dsl::until(lexy::dsl::newline).or_eof();

   struct Identifier {
      static constexpr auto rule = lexy::dsl::identifier(lexy::dsl::ascii::alpha_underscore, lexy::dsl::ascii::alpha_digit_underscore);
      static constexpr auto value =
         callback<ast::IdentifierValue*>(
            [](detail::IsParseState auto& state, auto lexeme) {
               auto value = state.ast().intern(lexeme.data(), lexeme.size());
               return state.ast().template create<ast::IdentifierValue>(lexeme.begin(), lexeme.end(), value);
            });
   };

   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 =
         callback<ast::IdentifierValue*>(
            [](detail::IsParseState auto& state, auto lexeme) {
               auto value = state.ast().intern(lexeme.data(), lexeme.size());
               return state.ast().template create<ast::IdentifierValue>(lexeme.begin(), lexeme.end(), value);
            });
   };

   struct String : lexy::scan_production<ast::StringValue*>,
               lexy::token_production {
      template<typename Context, typename Reader>
      static constexpr scan_result scan(lexy::rule_scanner<Context, Reader>& scanner, detail::IsParseState auto& state) {
         using encoding = typename Reader::encoding;

         constexpr auto c = [] {
            if constexpr (std::same_as<encoding, lexy::default_encoding> || std::same_as<encoding, lexy::byte_encoding>) {
               // Arbitrary code points that aren't control characters.
               return dsl::lit_b_range<0x20, 0xFF> - lexy::dsl::ascii::control;
            } else {
               return -lexy::dsl::unicode::control;
            }
         }();
         auto rule = lexy::dsl::quoted(c) | lexy::dsl::single_quoted(c);
         auto begin = scanner.position();
         lexy::scan_result<std::string> str_result;
         scanner.parse(str_result, rule);
         if (!scanner || !str_result)
            return lexy::scan_failed;
         auto end = scanner.position();
         auto str = str_result.value();
         auto value = state.ast().intern(str.data(), str.size());
         return state.ast().template create<ast::StringValue>(begin, end, value);
      }

      static constexpr auto rule = lexy::dsl::peek(lexy::dsl::quoted.open() | lexy::dsl::single_quoted.open()) >> lexy::dsl::scan;
      static constexpr auto value = ovdl::v2script::grammar::convert_as_string<std::string> >> lexy::forward<ast::StringValue*>;
   };

   struct Expression {
      static constexpr auto rule = lexy::dsl::p<Value> | lexy::dsl::p<String>;
      static constexpr auto value = lexy::forward<ast::Value*>;
   };

   struct AssignmentStatement {
      static constexpr auto rule = [] {
         auto right_brace = lexy::dsl::lit_c<'}'>;

         auto expression = lexy::dsl::p<Expression>;
         auto statement_list = lexy::dsl::recurse_branch<StatementListBlock>;

         auto rhs_recover = lexy::dsl::recover(expression, statement_list).limit(right_brace);
         auto rhs_try = lexy::dsl::try_(expression | statement_list, rhs_recover);

         auto identifier = dsl::p<Identifier> >> lexy::dsl::equal_sign + rhs_try;

         auto recover = lexy::dsl::recover(identifier).limit(right_brace);
         return lexy::dsl::try_(identifier, recover);
      }();

      static constexpr auto value = callback<ast::AssignStatement*>(
         [](detail::IsParseState auto& state, const char* pos, ast::IdentifierValue* name, ast::Value* initializer) -> ast::AssignStatement* {
            if (initializer == nullptr) return nullptr;
            return state.ast().template create<ast::AssignStatement>(pos, name, initializer);
         },
         [](detail::IsParseState auto& state, ast::Value*) {
            return nullptr;
         },
         [](detail::IsParseState auto& state) {
            return nullptr;
         });
   };

   struct StatementListBlock {
      static constexpr auto rule = [] {
         auto right_brace = lexy::dsl::lit_c<'}'>;
         auto comma = lexy::dsl::lit_c<','>;

         auto assign_statement = lexy::dsl::recurse_branch<AssignmentStatement>;
         auto assign_try = lexy::dsl::try_(assign_statement);

         auto curly_bracket = dsl::curly_bracketed.opt_list(
            assign_try,
            lexy::dsl::trailing_sep(comma));

         return lexy::dsl::try_(curly_bracket, lexy::dsl::find(right_brace));
      }();

      static constexpr auto value =
         lexy::as_list<ast::AssignStatementList> >> construct_list<ast::ListValue>;
   };

   struct File {
      // Allow arbitrary spaces between individual tokens.
      static constexpr auto whitespace = ovdl::v2script::grammar::whitespace_specifier | comment_specifier;

      static constexpr auto rule = lexy::dsl::position + lexy::dsl::terminator(lexy::dsl::eof).opt_list(lexy::dsl::p<AssignmentStatement>);

      static constexpr auto value = lexy::as_list<ast::AssignStatementList> >> construct<ast::FileTree>;
   };
}