Skip to content

Commit 23c8367

Browse files
authored
feat: statement parameters parsing (#90)
1 parent cc1ffce commit 23c8367

File tree

5 files changed

+356
-3
lines changed

5 files changed

+356
-3
lines changed

ecsact/detail/grammar.hh

Lines changed: 125 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include <string_view>
44
#include <optional>
5+
#include <vector>
56
#include <lexy/dsl.hpp>
67
#include <lexy/callback.hpp>
78
#include "ecsact/parse/status.h"
@@ -65,6 +66,106 @@ struct whitespace {
6566
lexy::dsl::inline_<line_comment> | lexy::dsl::inline_<block_comment>;
6667
};
6768

69+
struct parameter_name {
70+
static constexpr auto rule = lexy::dsl::
71+
identifier(lexy::dsl::ascii::alpha, lexy::dsl::ascii::alnum / lexy::dsl::lit_c<'_'>);
72+
73+
static constexpr auto value = lexy::as_string<std::string_view>;
74+
};
75+
76+
struct parameter_value {
77+
struct invalid_value_syntax {
78+
static constexpr auto name = "Invalid parameter value syntax";
79+
};
80+
81+
struct number {
82+
static constexpr auto rule = [] {
83+
using namespace lexy;
84+
auto digits = dsl::digits<>.sep(dsl::digit_sep_tick).no_leading_zero();
85+
return dsl::integer<int32_t>(digits);
86+
}();
87+
88+
static constexpr auto value = lexy::as_integer<int32_t>;
89+
};
90+
91+
struct boolean {
92+
struct true_keyword : lexy::transparent_production {
93+
static constexpr auto rule = LEXY_LIT("true");
94+
static constexpr auto value = lexy::constant(true);
95+
};
96+
97+
struct false_keyword : lexy::transparent_production {
98+
static constexpr auto rule = LEXY_LIT("false");
99+
static constexpr auto value = lexy::constant(false);
100+
};
101+
102+
static constexpr auto rule = lexy::dsl::p<true_keyword> |
103+
lexy::dsl::p<false_keyword>;
104+
105+
static constexpr auto value = lexy::forward<bool>;
106+
};
107+
108+
static constexpr auto rule = lexy::dsl::p<number> | lexy::dsl::p<boolean>;
109+
110+
using value_variant = std::variant<bool, int32_t>;
111+
112+
static constexpr auto value = lexy::callback<value_variant>(
113+
[](auto&& value) -> value_variant { return value_variant{value}; }
114+
);
115+
};
116+
117+
struct parameter {
118+
using value_variant = typename parameter_value::value_variant;
119+
120+
static void _set_value(ecsact_statement_parameter& param, int32_t value) {
121+
param.value.type = ECSACT_STATEMENT_PARAM_VALUE_TYPE_INTEGER;
122+
param.value.data.integer_value = value;
123+
}
124+
125+
static void _set_value(ecsact_statement_parameter& param, bool value) {
126+
param.value.type = ECSACT_STATEMENT_PARAM_VALUE_TYPE_BOOL;
127+
param.value.data.bool_value = value;
128+
}
129+
130+
static constexpr auto rule = lexy::dsl::p<parameter_name> >>
131+
lexy::dsl::opt(lexy::dsl::lit_c<':'> >> lexy::dsl::p<parameter_value>);
132+
133+
static constexpr auto value = lexy::callback<ecsact_statement_parameter>(
134+
[](std::string_view param_name, std::optional<value_variant> param_value) {
135+
auto result = ecsact_statement_parameter{};
136+
result.name = ecsact_statement_sv{
137+
.data = param_name.data(),
138+
.length = static_cast<int32_t>(param_name.size()),
139+
};
140+
141+
if(param_value) {
142+
std::visit(
143+
[&](auto&& param_value) {
144+
parameter::_set_value(result, param_value);
145+
},
146+
*param_value
147+
);
148+
} else {
149+
parameter::_set_value(result, true);
150+
}
151+
152+
return result;
153+
}
154+
);
155+
};
156+
157+
struct parameters {
158+
static constexpr auto rule = [] {
159+
return lexy::dsl::parenthesized.list(
160+
lexy::dsl::p<parameter>,
161+
lexy::dsl::sep(lexy::dsl::comma)
162+
);
163+
}();
164+
165+
static constexpr auto value =
166+
lexy::as_list<std::vector<ecsact_statement_parameter>>;
167+
};
168+
68169
/**
69170
* Lookupable type name
70171
*/
@@ -690,6 +791,26 @@ struct control {
690791
struct statement_value {
691792
ecsact_statement statement;
692793
ecsact_parse_status_code status;
794+
795+
/**
796+
* Temporary parameters that will be added to `statement`.
797+
* SEE: collect_parameters
798+
*/
799+
std::optional<std::vector<ecsact_statement_parameter>> _parameters;
800+
801+
auto collect_parameters() {
802+
if(_parameters) {
803+
auto parameters = *_parameters;
804+
statement.parameters_length = static_cast<int32_t>(parameters.size());
805+
for(int i = 0; statement.parameters_length > i; ++i) {
806+
statement.parameters[i] = parameters[i];
807+
}
808+
809+
_parameters = std::nullopt;
810+
} else {
811+
statement.parameters_length = 0;
812+
}
813+
}
693814
};
694815

695816
template<
@@ -716,10 +837,13 @@ struct statement {
716837

717838
auto statement =
718839
(lexyd::member<& statement_value::statement> = statement_p);
840+
auto statement_params =
841+
(lexyd::member<& statement_value::_parameters> =
842+
lexy::dsl::opt(lexyd::p<parameters>));
719843
auto status =
720844
(lexyd::member<& statement_value::status> = lexyd::p<parse_end>);
721845

722-
return statement + status;
846+
return statement + statement_params + status;
723847
}();
724848

725849
static constexpr auto value = lexy::as_aggregate<statement_value>;

ecsact/ecsact_parse_statement.cc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,10 @@ int ecsact_parse_statement(
8383
});
8484

8585
if(result) {
86-
*out_statement = result.value().statement;
87-
out_status->code = result.value().status;
86+
auto statement_value = result.value();
87+
statement_value.collect_parameters();
88+
*out_statement = statement_value.statement;
89+
out_status->code = statement_value.status;
8890
}
8991

9092
out_statement->id = ++last_id;

ecsact/parse/statements.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,30 @@ typedef struct {
9393
ecsact_statement_sv constraint_component_name;
9494
} ecsact_entity_constraint_statement;
9595

96+
typedef enum {
97+
ECSACT_STATEMENT_PARAM_VALUE_TYPE_BOOL,
98+
ECSACT_STATEMENT_PARAM_VALUE_TYPE_INTEGER,
99+
ECSACT_STATEMENT_PARAM_VALUE_TYPE_FLOAT,
100+
ECSACT_STATEMENT_PARAM_VALUE_TYPE_STRING,
101+
} ecsact_statement_parameter_value_type;
102+
103+
typedef union {
104+
bool bool_value;
105+
int32_t integer_value;
106+
float float_value;
107+
ecsact_statement_sv string_value;
108+
} ecsact_statement_parameter_value_data;
109+
110+
typedef struct {
111+
ecsact_statement_parameter_value_type type;
112+
ecsact_statement_parameter_value_data data;
113+
} ecsact_statement_parameter_value;
114+
115+
typedef struct {
116+
ecsact_statement_sv name;
117+
ecsact_statement_parameter_value value;
118+
} ecsact_statement_parameter;
119+
96120
typedef union {
97121
ecsact_package_statement package_statement;
98122
ecsact_import_statement import_statement;
@@ -124,6 +148,16 @@ typedef struct ecsact_statement {
124148
* Valid union member determined by `type`
125149
*/
126150
ecsact_statement_data data;
151+
152+
/**
153+
* Length of parameters. Max length is 16
154+
*/
155+
int32_t parameters_length;
156+
157+
/**
158+
* List of parameters for this statement. Max length is 16
159+
*/
160+
ecsact_statement_parameter parameters[16];
127161
} ecsact_statement;
128162

129163
#endif // ECSACT_PARSE_STATEMENTS_H

test/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ _TESTS = [
1010
"import_statement",
1111
"none_statement",
1212
"package_statement",
13+
"parameter",
1314
"sequential_statements",
1415
"system_component_statement",
1516
"system_generates_statement",

0 commit comments

Comments
 (0)