Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
A
Actor Framework
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
cpp-libs
Actor Framework
Commits
03dfce58
Unverified
Commit
03dfce58
authored
Jan 06, 2020
by
Joseph Noir
Committed by
GitHub
Jan 06, 2020
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #999
Enable compact list notation in config files
parents
f983dd0c
ef580c37
Changes
9
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
284 additions
and
38 deletions
+284
-38
libcaf_core/caf/detail/parser/chars.hpp
libcaf_core/caf/detail/parser/chars.hpp
+5
-1
libcaf_core/caf/detail/parser/fsm.hpp
libcaf_core/caf/detail/parser/fsm.hpp
+28
-2
libcaf_core/caf/detail/parser/read_floating_point.hpp
libcaf_core/caf/detail/parser/read_floating_point.hpp
+2
-1
libcaf_core/caf/detail/parser/read_ini.hpp
libcaf_core/caf/detail/parser/read_ini.hpp
+8
-6
libcaf_core/caf/detail/parser/read_number.hpp
libcaf_core/caf/detail/parser/read_number.hpp
+121
-18
libcaf_core/caf/detail/parser/read_number_or_timespan.hpp
libcaf_core/caf/detail/parser/read_number_or_timespan.hpp
+20
-4
libcaf_core/caf/pec.hpp
libcaf_core/caf/pec.hpp
+3
-1
libcaf_core/test/detail/parser/read_ini.cpp
libcaf_core/test/detail/parser/read_ini.cpp
+7
-1
libcaf_core/test/detail/parser/read_number.cpp
libcaf_core/test/detail/parser/read_number.cpp
+90
-4
No files found.
libcaf_core/caf/detail/parser/chars.hpp
View file @
03dfce58
...
...
@@ -38,7 +38,11 @@ constexpr bool in_whitelist(char whitelist, char ch) {
}
inline
bool
in_whitelist
(
const
char
*
whitelist
,
char
ch
)
{
return
strchr
(
whitelist
,
ch
)
!=
nullptr
;
// Note: using strchr breaks if `ch == '\0'`.
for
(
char
c
=
*
whitelist
++
;
c
!=
'\0'
;
c
=
*
whitelist
++
)
if
(
c
==
ch
)
return
true
;
return
false
;
}
inline
bool
in_whitelist
(
bool
(
*
filter
)(
char
),
char
ch
)
{
...
...
libcaf_core/caf/detail/parser/fsm.hpp
View file @
03dfce58
...
...
@@ -273,18 +273,30 @@
#endif // CAF_MSVC
///
Mak
es a transition into another state if the `statement` is true.
///
Enabl
es a transition into another state if the `statement` is true.
#define transition_if(statement, ...) \
if (statement) { \
transition(__VA_ARGS__) \
}
/// Makes an epsiolon transition into another state if the `statement` is true.
/// Enables a transition if the constexpr `statement` is true.
#define transition_static_if(statement, ...) \
if constexpr (statement) { \
transition(__VA_ARGS__) \
}
/// Enables an epsiolon transition if the `statement` is true.
#define epsilon_if(statement, ...) \
if (statement) { \
epsilon(__VA_ARGS__) \
}
/// Enables an epsiolon transition if the constexpr `statement` is true.
#define epsilon_static_if(statement, ...) \
if constexpr (statement) { \
epsilon(__VA_ARGS__) \
}
/// Makes an transition transition into another FSM if `statement` is true,
/// resuming at state `target`.
#define fsm_transition_if(statement, ...) \
...
...
@@ -292,9 +304,23 @@
fsm_transition(__VA_ARGS__) \
}
/// Makes an transition transition into another FSM if `statement` is true,
/// resuming at state `target`.
#define fsm_transition_static_if(statement, ...) \
if constexpr (statement) { \
fsm_transition(__VA_ARGS__) \
}
/// Makes an epsilon transition into another FSM if `statement` is true,
/// resuming at state `target`.
#define fsm_epsilon_if(statement, ...) \
if (statement) { \
fsm_epsilon(__VA_ARGS__) \
}
/// Makes an epsilon transition into another FSM if `statement` is true,
/// resuming at state `target`.
#define fsm_epsilon_static_if(statement, ...) \
if constexpr (statement) { \
fsm_epsilon(__VA_ARGS__) \
}
libcaf_core/caf/detail/parser/read_floating_point.hpp
View file @
03dfce58
...
...
@@ -112,7 +112,8 @@ void read_floating_point(State& ps, Consumer&& consumer,
start
();
unstable_state
(
init
)
{
epsilon_if
(
start_value
==
none
,
regular_init
)
epsilon
(
after_dec
)
epsilon
(
after_dec
,
"eE."
)
epsilon
(
after_dot
,
any_char
)
}
state
(
regular_init
)
{
transition
(
regular_init
,
"
\t
"
)
...
...
libcaf_core/caf/detail/parser/read_ini.hpp
View file @
03dfce58
...
...
@@ -71,8 +71,9 @@ void read_ini_comment(State& ps, Consumer&&) {
// clang-format on
}
template
<
class
State
,
class
Consumer
>
void
read_ini_value
(
State
&
ps
,
Consumer
&&
consumer
);
template
<
class
State
,
class
Consumer
,
class
InsideList
=
std
::
false_type
>
void
read_ini_value
(
State
&
ps
,
Consumer
&&
consumer
,
InsideList
inside_list
=
{});
template
<
class
State
,
class
Consumer
>
void
read_ini_list
(
State
&
ps
,
Consumer
&&
consumer
)
{
...
...
@@ -85,7 +86,7 @@ void read_ini_list(State& ps, Consumer&& consumer) {
transition
(
before_value
,
"
\t\n
"
)
transition
(
done
,
']'
,
consumer
.
end_list
())
fsm_epsilon
(
read_ini_comment
(
ps
,
consumer
),
before_value
,
';'
)
fsm_epsilon
(
read_ini_value
(
ps
,
consumer
),
after_value
)
fsm_epsilon
(
read_ini_value
(
ps
,
consumer
,
std
::
true_type
{}
),
after_value
)
}
state
(
after_value
)
{
transition
(
after_value
,
"
\t\n
"
)
...
...
@@ -183,8 +184,8 @@ void read_ini_uri(State& ps, Consumer&& consumer) {
// clang-format on
}
template
<
class
State
,
class
Consumer
>
void
read_ini_value
(
State
&
ps
,
Consumer
&&
consumer
)
{
template
<
class
State
,
class
Consumer
,
class
InsideList
>
void
read_ini_value
(
State
&
ps
,
Consumer
&&
consumer
,
InsideList
inside_list
)
{
// clang-format off
start
();
state
(
init
)
{
...
...
@@ -192,7 +193,8 @@ void read_ini_value(State& ps, Consumer&& consumer) {
fsm_epsilon
(
read_atom
(
ps
,
consumer
),
done
,
'\''
)
fsm_epsilon
(
read_number
(
ps
,
consumer
),
done
,
'.'
)
fsm_epsilon
(
read_bool
(
ps
,
consumer
),
done
,
"ft"
)
fsm_epsilon
(
read_number_or_timespan
(
ps
,
consumer
),
done
,
"0123456789+-"
)
fsm_epsilon
(
read_number_or_timespan
(
ps
,
consumer
,
inside_list
),
done
,
"0123456789+-"
)
fsm_epsilon
(
read_ini_uri
(
ps
,
consumer
),
done
,
'<'
)
fsm_transition
(
read_ini_list
(
ps
,
consumer
.
begin_list
()),
done
,
'['
)
fsm_transition
(
read_ini_map
(
ps
,
consumer
.
begin_map
()),
done
,
'{'
)
...
...
libcaf_core/caf/detail/parser/read_number.hpp
View file @
03dfce58
...
...
@@ -19,8 +19,10 @@
#pragma once
#include <cstdint>
#include <type_traits>
#include "caf/config.hpp"
#include "caf/detail/consumer.hpp"
#include "caf/detail/parser/add_ascii.hpp"
#include "caf/detail/parser/chars.hpp"
#include "caf/detail/parser/is_char.hpp"
...
...
@@ -36,10 +38,25 @@ CAF_PUSH_UNUSED_LABEL_WARNING
namespace
caf
::
detail
::
parser
{
/// Reads the second half of 'n..m' range statement.
///
/// Expect the current position to point at the number *after* the dots:
///
/// ~~~
/// foo = [1..2]
/// ~~~^
/// ~~~
template
<
class
State
,
class
Consumer
>
void
read_number_range
(
State
&
ps
,
Consumer
&
consumer
,
int64_t
begin
);
/// Reads a number, i.e., on success produces either an `int64_t` or a
/// `double`.
template
<
class
State
,
class
Consumer
>
void
read_number
(
State
&
ps
,
Consumer
&
consumer
)
{
template
<
class
State
,
class
Consumer
,
class
EnableFloat
=
std
::
true_type
,
class
EnableRange
=
std
::
false_type
>
void
read_number
(
State
&
ps
,
Consumer
&
consumer
,
EnableFloat
=
{},
EnableRange
=
{})
{
static
constexpr
bool
enable_float
=
EnableFloat
::
value
;
static
constexpr
bool
enable_range
=
EnableRange
::
value
;
// Our result when reading an integer number.
int64_t
result
=
0
;
// Computes the result on success.
...
...
@@ -47,6 +64,7 @@ void read_number(State& ps, Consumer& consumer) {
if
(
ps
.
code
<=
pec
::
trailing_character
)
consumer
.
value
(
result
);
});
using
odbl
=
optional
<
double
>
;
// clang-format off
// Definition of our parser FSM.
start
();
...
...
@@ -54,17 +72,22 @@ void read_number(State& ps, Consumer& consumer) {
transition
(
init
,
"
\t
"
)
transition
(
has_plus
,
'+'
)
transition
(
has_minus
,
'-'
)
fsm_epsilon_static_if
(
enable_float
,
read_floating_point
(
ps
,
consumer
,
odbl
{
0.
}),
done
,
'.'
,
g
.
disable
())
epsilon
(
has_plus
)
}
// "+" or "-" alone aren't numbers.
state
(
has_plus
)
{
fsm_epsilon
(
read_floating_point
(
ps
,
consumer
,
optional
<
double
>
{
0.
}),
fsm_epsilon_static_if
(
enable_float
,
read_floating_point
(
ps
,
consumer
,
odbl
{
0.
}),
done
,
'.'
,
g
.
disable
())
transition
(
pos_zero
,
'0'
)
epsilon
(
pos_dec
)
}
state
(
has_minus
)
{
fsm_epsilon
(
read_floating_point
(
ps
,
consumer
,
optional
<
double
>
{
0.
},
true
),
fsm_epsilon_static_if
(
enable_float
,
read_floating_point
(
ps
,
consumer
,
odbl
{
0.
},
true
),
done
,
'.'
,
g
.
disable
())
transition
(
neg_zero
,
'0'
)
epsilon
(
neg_dec
)
...
...
@@ -73,15 +96,13 @@ void read_number(State& ps, Consumer& consumer) {
term_state
(
pos_zero
)
{
transition
(
start_pos_bin
,
"bB"
)
transition
(
start_pos_hex
,
"xX"
)
fsm_epsilon
(
read_floating_point
(
ps
,
consumer
,
optional
<
double
>
{
0.
}),
done
,
'.'
,
g
.
disable
())
transition_static_if
(
enable_float
||
enable_range
,
pos_dot
,
'.'
)
epsilon
(
pos_oct
)
}
term_state
(
neg_zero
)
{
transition
(
start_neg_bin
,
"bB"
)
transition
(
start_neg_hex
,
"xX"
)
fsm_epsilon
(
read_floating_point
(
ps
,
consumer
,
optional
<
double
>
{
0.
},
true
),
done
,
'.'
,
g
.
disable
())
transition_static_if
(
enable_float
||
enable_range
,
neg_dot
,
'.'
)
epsilon
(
neg_oct
)
}
// Binary integers.
...
...
@@ -131,19 +152,101 @@ void read_number(State& ps, Consumer& consumer) {
term_state
(
pos_dec
)
{
transition
(
pos_dec
,
decimal_chars
,
add_ascii
<
10
>
(
result
,
ch
),
pec
::
integer_overflow
)
fsm_epsilon
(
read_floating_point
(
ps
,
consumer
,
optional
<
double
>
{
result
}),
fsm_epsilon_static_if
(
enable_float
,
read_floating_point
(
ps
,
consumer
,
odbl
{
result
}),
done
,
"eE"
,
g
.
disable
())
fsm_epsilon
(
read_floating_point
(
ps
,
consumer
,
optional
<
double
>
{
result
}),
done
,
'.'
,
g
.
disable
())
transition_static_if
(
enable_float
||
enable_range
,
pos_dot
,
'.'
)
}
// Reads the integer part of the mantissa or a negative decimal integer.
term_state
(
neg_dec
)
{
transition
(
neg_dec
,
decimal_chars
,
sub_ascii
<
10
>
(
result
,
ch
),
pec
::
integer_underflow
)
fsm_epsilon
(
read_floating_point
(
ps
,
consumer
,
optional
<
double
>
{
result
},
true
),
fsm_epsilon_static_if
(
enable_float
,
read_floating_point
(
ps
,
consumer
,
odbl
{
result
},
true
),
done
,
"eE"
,
g
.
disable
())
fsm_epsilon
(
read_floating_point
(
ps
,
consumer
,
optional
<
double
>
{
result
},
true
),
transition_static_if
(
enable_float
||
enable_range
,
neg_dot
,
'.'
)
}
unstable_state
(
pos_dot
)
{
fsm_transition_static_if
(
enable_range
,
read_number_range
(
ps
,
consumer
,
result
),
done
,
'.'
,
g
.
disable
())
fsm_epsilon_static_if
(
enable_float
,
read_floating_point
(
ps
,
consumer
,
odbl
{
result
}),
done
,
any_char
,
g
.
disable
())
epsilon
(
done
)
}
unstable_state
(
neg_dot
)
{
fsm_transition_static_if
(
enable_range
,
read_number_range
(
ps
,
consumer
,
result
),
done
,
'.'
,
g
.
disable
())
fsm_epsilon_static_if
(
enable_float
,
read_floating_point
(
ps
,
consumer
,
odbl
{
result
},
true
),
done
,
any_char
,
g
.
disable
())
epsilon
(
done
)
}
term_state
(
done
)
{
// nop
}
fin
();
// clang-format on
}
template
<
class
State
,
class
Consumer
>
void
read_number_range
(
State
&
ps
,
Consumer
&
consumer
,
int64_t
begin
)
{
optional
<
int64_t
>
end
;
optional
<
int64_t
>
step
;
auto
end_consumer
=
make_consumer
(
end
);
auto
step_consumer
=
make_consumer
(
step
);
auto
generate_2
=
[
&
](
int64_t
n
,
int64_t
m
)
{
if
(
n
<=
m
)
while
(
n
<=
m
)
consumer
.
value
(
n
++
);
else
while
(
n
>=
m
)
consumer
.
value
(
n
--
);
};
auto
generate_3
=
[
&
](
int64_t
n
,
int64_t
m
,
int64_t
s
)
{
if
(
n
==
m
)
{
consumer
.
value
(
n
);
return
;
}
if
(
s
==
0
||
(
n
>
m
&&
s
>
0
)
||
(
n
<
m
&&
s
<
0
))
{
ps
.
code
=
pec
::
invalid_range_expression
;
return
;
}
if
(
n
<=
m
)
for
(
auto
i
=
n
;
i
<=
m
;
i
+=
s
)
consumer
.
value
(
i
);
else
for
(
auto
i
=
n
;
i
>=
m
;
i
+=
s
)
consumer
.
value
(
i
);
};
auto
g
=
caf
::
detail
::
make_scope_guard
([
&
]
{
if
(
ps
.
code
<=
pec
::
trailing_character
)
{
if
(
!
end
)
{
ps
.
code
=
pec
::
invalid_range_expression
;
}
else
if
(
!
step
)
{
generate_2
(
begin
,
*
end
);
}
else
{
generate_3
(
begin
,
*
end
,
*
step
);
}
}
});
static
constexpr
std
::
false_type
no_float
=
std
::
false_type
{};
// clang-format off
// Definition of our parser FSM.
start
();
state
(
init
)
{
fsm_epsilon
(
read_number
(
ps
,
end_consumer
,
no_float
),
after_end_num
)
}
term_state
(
after_end_num
)
{
transition
(
first_dot
,
'.'
)
}
state
(
first_dot
)
{
transition
(
second_dot
,
'.'
)
}
state
(
second_dot
)
{
fsm_epsilon
(
read_number
(
ps
,
step_consumer
,
no_float
),
done
)
}
term_state
(
done
)
{
// nop
...
...
libcaf_core/caf/detail/parser/read_number_or_timespan.hpp
View file @
03dfce58
...
...
@@ -42,19 +42,34 @@ namespace caf::detail::parser {
/// Reads a number or a duration, i.e., on success produces an `int64_t`, a
/// `double`, or a `timespan`.
template
<
class
State
,
class
Consumer
>
void
read_number_or_timespan
(
State
&
ps
,
Consumer
&
consumer
)
{
template
<
class
State
,
class
Consumer
,
class
EnableRange
=
std
::
false_type
>
void
read_number_or_timespan
(
State
&
ps
,
Consumer
&
consumer
,
EnableRange
enable_range
=
{})
{
using
namespace
std
::
chrono
;
struct
interim_consumer
{
size_t
invocations
=
0
;
Consumer
*
outer
=
nullptr
;
variant
<
none_t
,
int64_t
,
double
>
interim
;
void
value
(
int64_t
x
)
{
switch
(
++
invocations
)
{
case
1
:
interim
=
x
;
break
;
case
2
:
CAF_ASSERT
(
holds_alternative
<
int64_t
>
(
interim
));
outer
->
value
(
get
<
int64_t
>
(
interim
));
interim
=
none
;
[[
fallthrough
]];
default:
outer
->
value
(
x
);
}
}
void
value
(
double
x
)
{
interim
=
x
;
}
};
interim_consumer
ic
;
ic
.
outer
=
&
consumer
;
auto
has_int
=
[
&
]
{
return
holds_alternative
<
int64_t
>
(
ic
.
interim
);
};
auto
has_dbl
=
[
&
]
{
return
holds_alternative
<
double
>
(
ic
.
interim
);
};
auto
get_int
=
[
&
]
{
return
get
<
int64_t
>
(
ic
.
interim
);
};
...
...
@@ -66,10 +81,11 @@ void read_number_or_timespan(State& ps, Consumer& consumer) {
consumer
.
value
(
get_int
());
}
});
static
constexpr
std
::
true_type
enable_float
=
std
::
true_type
{};
// clang-format off
start
();
state
(
init
)
{
fsm_epsilon
(
read_number
(
ps
,
ic
),
has_number
)
fsm_epsilon
(
read_number
(
ps
,
ic
,
enable_float
,
enable_range
),
has_number
)
}
term_state
(
has_number
)
{
epsilon_if
(
has_int
(),
has_integer
)
...
...
libcaf_core/caf/pec.hpp
View file @
03dfce58
...
...
@@ -72,7 +72,9 @@ enum class pec : uint8_t {
repeated_field_name
,
/// Stopped while reading a user-defined type with one or more missing
/// mandatory fields.
missing_field
,
missing_field
=
20
,
/// Parsing a range statement ('n..m' or 'n..m..step') failed.
invalid_range_expression
,
};
/// @relates pec
...
...
libcaf_core/test/detail/parser/read_ini.cpp
View file @
03dfce58
...
...
@@ -126,8 +126,9 @@ some-other-bool=false
some-list=[
; here we have some list entries
123,
1..3,
23 ; twenty-three!
,
,
2..4..2,
"abc",
'def', ; some comment and a trailing comma
]
...
...
@@ -179,7 +180,12 @@ const auto ini0_log = make_log(
"key: some-list"
,
"["
,
"value (integer): 123"
,
"value (integer): 1"
,
"value (integer): 2"
,
"value (integer): 3"
,
"value (integer): 23"
,
"value (integer): 2"
,
"value (integer): 4"
,
"value (string):
\"
abc
\"
"
,
"value (atom): 'def'"
,
"]"
,
...
...
libcaf_core/test/detail/parser/read_number.cpp
View file @
03dfce58
...
...
@@ -36,16 +36,26 @@ using namespace caf;
namespace
{
struct
number
s_parser
_consumer
{
struct
number_consumer
{
variant
<
int64_t
,
double
>
x
;
inline
void
value
(
double
y
)
{
void
value
(
double
y
)
{
x
=
y
;
}
inline
void
value
(
int64_t
y
)
{
void
value
(
int64_t
y
)
{
x
=
y
;
}
};
struct
range_consumer
{
std
::
vector
<
int64_t
>
xs
;
void
value
(
double
)
{
CAF_FAIL
(
"range consumer called with a double"
);
}
void
value
(
int64_t
y
)
{
xs
.
emplace_back
(
y
);
}
};
struct
res_t
{
variant
<
pec
,
double
,
int64_t
>
val
;
template
<
class
T
>
...
...
@@ -54,6 +64,10 @@ struct res_t {
}
};
std
::
string
to_string
(
const
res_t
&
x
)
{
return
caf
::
visit
([](
auto
&
y
)
{
return
deep_to_string
(
y
);
},
x
.
val
);
}
bool
operator
==
(
const
res_t
&
x
,
const
res_t
&
y
)
{
if
(
x
.
val
.
index
()
!=
y
.
val
.
index
())
return
false
;
...
...
@@ -70,7 +84,7 @@ bool operator==(const res_t& x, const res_t& y) {
struct
numbers_parser
{
res_t
operator
()(
string_view
str
)
{
number
s_parser
_consumer
f
;
number_consumer
f
;
string_parser_state
res
{
str
.
begin
(),
str
.
end
()};
detail
::
parser
::
read_number
(
res
,
f
);
if
(
res
.
code
==
pec
::
success
)
...
...
@@ -79,6 +93,17 @@ struct numbers_parser {
}
};
struct
range_parser
{
expected
<
std
::
vector
<
int64_t
>>
operator
()(
string_view
str
)
{
range_consumer
f
;
string_parser_state
res
{
str
.
begin
(),
str
.
end
()};
detail
::
parser
::
read_number
(
res
,
f
,
std
::
true_type
{},
std
::
true_type
{});
if
(
res
.
code
==
pec
::
success
)
return
std
::
move
(
f
.
xs
);
return
make_error
(
res
);
}
};
template
<
class
T
>
typename
std
::
enable_if
<
std
::
is_integral
<
T
>::
value
,
res_t
>::
type
res
(
T
x
)
{
return
{
static_cast
<
int64_t
>
(
x
)};
...
...
@@ -92,6 +117,7 @@ res(T x) {
struct
fixture
{
numbers_parser
p
;
range_parser
r
;
};
}
// namespace
...
...
@@ -205,12 +231,18 @@ CAF_TEST(floating point numbers) {
CHECK_NUMBER
(
0.0
);
CHECK_NUMBER
(
.0
);
CHECK_NUMBER
(
0.
);
CHECK_NUMBER
(
1.1
);
CHECK_NUMBER
(
.1
);
CHECK_NUMBER
(
1.
);
CHECK_NUMBER
(
0.123
);
CHECK_NUMBER
(
.123
);
CHECK_NUMBER
(
123.456
);
CHECK_NUMBER
(
-
0.0
);
CHECK_NUMBER
(
-
.0
);
CHECK_NUMBER
(
-
0.
);
CHECK_NUMBER
(
-
1.1
);
CHECK_NUMBER
(
-
.1
);
CHECK_NUMBER
(
-
1.
);
CHECK_NUMBER
(
-
0.123
);
CHECK_NUMBER
(
-
.123
);
CHECK_NUMBER
(
-
123.456
);
...
...
@@ -269,4 +301,58 @@ CAF_TEST(fractional mantissa with negative exponent) {
CHECK_NUMBER
(
-
42.0001e-5
);
}
#define CHECK_RANGE(expr, ...) \
CAF_CHECK_EQUAL(r(expr), std::vector<int64_t>({__VA_ARGS__}))
CAF_TEST
(
a
range
from
n
to
n
is
just
n
)
{
CHECK_RANGE
(
"0..0"
,
0
);
CHECK_RANGE
(
"1..1"
,
1
);
CHECK_RANGE
(
"2..2"
,
2
);
CHECK_RANGE
(
"101..101"
,
101
);
CHECK_RANGE
(
"101..101..1"
,
101
);
CHECK_RANGE
(
"101..101..2"
,
101
);
CHECK_RANGE
(
"101..101..-1"
,
101
);
CHECK_RANGE
(
"101..101..-2"
,
101
);
}
CAF_TEST
(
ranges
are
either
ascending
or
descending
)
{
CHECK_RANGE
(
"0..1"
,
0
,
1
);
CHECK_RANGE
(
"0..2"
,
0
,
1
,
2
);
CHECK_RANGE
(
"0..3"
,
0
,
1
,
2
,
3
);
CHECK_RANGE
(
"3..0"
,
3
,
2
,
1
,
0
);
CHECK_RANGE
(
"3..1"
,
3
,
2
,
1
);
CHECK_RANGE
(
"3..2"
,
3
,
2
);
}
CAF_TEST
(
ranges
can
use
positive
step
values
)
{
CHECK_RANGE
(
"2..6..2"
,
2
,
4
,
6
);
CHECK_RANGE
(
"3..8..3"
,
3
,
6
);
}
CAF_TEST
(
ranges
can
use
negative
step
values
)
{
CHECK_RANGE
(
"6..2..-2"
,
6
,
4
,
2
);
CHECK_RANGE
(
"8..3..-3"
,
8
,
5
);
}
CAF_TEST
(
ranges
can
use
signed
integers
)
{
CHECK_RANGE
(
"+2..+6..+2"
,
2
,
4
,
6
);
CHECK_RANGE
(
"+6..+2..-2"
,
6
,
4
,
2
);
CHECK_RANGE
(
"+2..-2..-2"
,
2
,
0
,
-
2
);
CHECK_RANGE
(
"-2..+2..+2"
,
-
2
,
0
,
2
);
}
#define CHECK_ERR(expr, enum_value) \
if (auto res = r(expr)) { \
CAF_FAIL("expected expression to produce to an error"); \
} else { \
auto& err = res.error(); \
CAF_CHECK_EQUAL(err.category(), atom("parser")); \
CAF_CHECK_EQUAL(err.code(), static_cast<uint8_t>(enum_value)); \
}
CAF_TEST
(
the
parser
rejects
invalid
step
values
)
{
CHECK_ERR
(
"-2..+2..-2"
,
pec
::
invalid_range_expression
);
CHECK_ERR
(
"+2..-2..+2"
,
pec
::
invalid_range_expression
);
}
CAF_TEST_FIXTURE_SCOPE_END
()
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment