Replace peg::any with std::any (when C++17 is available)

pull/72/head
Francesco Guastella 5 years ago
parent 523137c5dd
commit 1afa4988bc
  1. 49
      CMakeLists.txt
  2. 9
      README.md
  3. 15
      example/calc.cc
  4. 13
      example/calc2.cc
  5. 15
      example/calc3.cc
  6. 172
      peglib.h
  7. 99
      test/test.cc

@ -1,37 +1,26 @@
cmake_minimum_required(VERSION 2.8)
# Check if a supported compiler is used and add c++11 flag:
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9)
message(FATAL_ERROR "Need at least gcc 4.9 to compile.")
endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
elseif(MSVC)
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19)
message(FATAL_ERROR "Visual Studio 2015 or newer is required.")
endif()
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.0)
message(FATAL_ERROR "Need at least AppleClang 7.0 to compile.")
cmake_minimum_required(VERSION 3.1.0)
project("cpp-peglib")
# Check if a supported compiler is used to setup the C++ standard to use:
get_property(known_features GLOBAL PROPERTY CMAKE_CXX_KNOWN_FEATURES)
list(FIND known_features "cxx_std_17" found)
if(NOT ${found} EQUAL -1)
# C++17 standard is supported
set(CMAKE_CXX_STANDARD 17)
else()
# Check for C++11 standard support
list(FIND known_features "cxx_std_11" found)
if(NOT ${found} EQUAL -1)
# C++11 standard is supported
set(CMAKE_CXX_STANDARD 11)
endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.4)
message(FATAL_ERROR "Clang below version 3.4 will most likely not work. Please upgrade your compiler.")
endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
else() # no GNU, no MSVC, no Clang
message(WARNING "You are using an unsupported compiler. Compilation has only been tested with MSVC, GCC and Clang.")
endif()
include(CheckCXXCompilerFlag)
check_cxx_compiler_flag(-std=c++11 HAS_CXX11_FLAG)
if(HAS_CXX11_FLAG)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
else()
message(FATAL_ERROR "Your compiler doesn't support the '-std=c++11' flag.")
endif()
if(${found} EQUAL -1)
message(FATAL_ERROR "Your compiler is not supported.")
endif()
set(CMAKE_CXX_EXTENSIONS OFF)
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang"
OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")

@ -110,7 +110,14 @@ There are four semantic actions available:
`any& dt` is a 'read-write' context data which can be used for whatever purposes. The initial context data is set in `peg::parser::parse` method.
`peg::any` is a simpler implementatin of [boost::any](http://www.boost.org/doc/libs/1_57_0/doc/html/any.html). It can wrap arbitrary data type.
`peg::any` is a simpler implementatin of [boost::any](http://www.boost.org/doc/libs/1_57_0/doc/html/any.html). It can wrap arbitrary data type.
If the compiler in use supports C++17, by default `peg::any` is defined as an alias to `std::any`.
To force using the simpler `any` implementation that comes with `cpp-peglib`, define `PEGLIB_USE_STD_ANY` as 0 before including `peglib.h`:
```cpp
#define PEGLIB_USE_STD_ANY 0
#include <peglib.h>
[...]
```
A semantic action can return a value of arbitrary data type, which will be wrapped by `peg::any`. If a user returns nothing in a semantic action, the first semantic value in the `const SemanticValues& sv` argument will be returned. (Yacc parser has the same behavior.)

@ -10,20 +10,19 @@
#include <cstdlib>
using namespace peg;
using namespace std;
int main(int argc, const char** argv)
{
if (argc < 2 || string("--help") == argv[1]) {
cout << "usage: calc [formula]" << endl;
if (argc < 2 || std::string("--help") == argv[1]) {
std::cout << "usage: calc [formula]" << std::endl;
return 1;
}
auto reduce = [](const SemanticValues& sv) -> long {
auto result = sv[0].get<long>();
auto result = any_cast<long>(sv[0]);
for (auto i = 1u; i < sv.size(); i += 2) {
auto num = sv[i + 1].get<long>();
auto ope = sv[i].get<char>();
auto num = any_cast<long>(sv[i + 1]);
auto ope = any_cast<char>(sv[i]);
switch (ope) {
case '+': result += num; break;
case '-': result -= num; break;
@ -53,11 +52,11 @@ int main(int argc, const char** argv)
auto expr = argv[1];
long val = 0;
if (parser.parse(expr, val)) {
cout << expr << " = " << val << endl;
std::cout << expr << " = " << val << std::endl;
return 0;
}
cout << "syntax error..." << endl;
std::cout << "syntax error..." << std::endl;
return -1;
}

@ -10,7 +10,6 @@
#include <cstdlib>
using namespace peg;
using namespace std;
//
// PEG syntax:
@ -24,16 +23,16 @@ using namespace std;
//
int main(int argc, const char** argv)
{
if (argc < 2 || string("--help") == argv[1]) {
cout << "usage: calc [formula]" << endl;
if (argc < 2 || std::string("--help") == argv[1]) {
std::cout << "usage: calc [formula]" << std::endl;
return 1;
}
auto reduce = [](const SemanticValues& sv) -> long {
auto result = sv[0].get<long>();
auto result = any_cast<long>(sv[0]);
for (auto i = 1u; i < sv.size(); i += 2) {
auto num = sv[i + 1].get<long>();
auto ope = sv[i].get<char>();
auto num = any_cast<long>(sv[i + 1]);
auto ope = any_cast<char>(sv[i]);
switch (ope) {
case '+': result += num; break;
case '-': result -= num; break;
@ -56,7 +55,7 @@ int main(int argc, const char** argv)
auto expr = argv[1];
long val = 0;
if (EXPRESSION.parse_and_get_value(expr, val).ret) {
cout << expr << " = " << val << endl;
std::cout << expr << " = " << val << std::endl;
return 0;
}

@ -10,16 +10,15 @@
#include <cstdlib>
using namespace peg;
using namespace std;
int main(int argc, const char** argv)
{
if (argc < 2 || string("--help") == argv[1]) {
cout << "usage: calc3 [formula]" << endl;
if (argc < 2 || std::string("--help") == argv[1]) {
std::cout << "usage: calc3 [formula]" << std::endl;
return 1;
}
function<long (const Ast&)> eval = [&](const Ast& ast) {
std::function<long (const Ast&)> eval = [&](const Ast& ast) {
if (ast.name == "NUMBER") {
return stol(ast.token);
} else {
@ -54,15 +53,15 @@ int main(int argc, const char** argv)
parser.enable_ast();
auto expr = argv[1];
shared_ptr<Ast> ast;
std::shared_ptr<Ast> ast;
if (parser.parse(expr, ast)) {
ast = AstOptimizer(true).optimize(ast);
cout << ast_to_s(ast);
cout << expr << " = " << eval(*ast) << endl;
std::cout << ast_to_s(ast);
std::cout << expr << " = " << eval(*ast) << std::endl;
return 0;
}
cout << "syntax error..." << endl;
std::cout << "syntax error..." << std::endl;
return -1;
}

@ -8,6 +8,14 @@
#ifndef CPPPEGLIB_PEGLIB_H
#define CPPPEGLIB_PEGLIB_H
#ifndef PEGLIB_USE_STD_ANY
#ifdef _MSVC_LANG
#define PEGLIB_USE_STD_ANY _MSVC_LANG >= 201703L
#elif defined(__cplusplus)
#define PEGLIB_USE_STD_ANY __cplusplus >= 201703L
#endif
#endif // PEGLIB_USE_STD_ANY
#include <algorithm>
#include <cctype>
#include <cassert>
@ -23,6 +31,9 @@
#include <string>
#include <unordered_map>
#include <vector>
#if PEGLIB_USE_STD_ANY
#include <any>
#endif
// guard for older versions of VC++
#ifdef _MSC_VER
@ -45,7 +56,15 @@ namespace peg {
/*-----------------------------------------------------------------------------
* any
*---------------------------------------------------------------------------*/
#if PEGLIB_USE_STD_ANY
using any = std::any;
// Define a function alias to std::any_cast using perfect forwarding
template <typename T, typename... Args>
auto any_cast( Args&&... args ) -> decltype(std::any_cast<T>(std::forward<Args>( args )... )) {
return std::any_cast<T>( std::forward<Args>( args )... );
}
#else
class any
{
public:
@ -85,55 +104,15 @@ public:
delete content_;
}
bool is_undefined() const {
return content_ == nullptr;
}
template <
typename T,
typename std::enable_if<!std::is_same<T, any>::value, std::nullptr_t>::type = nullptr
>
T& get() {
if (!content_) {
throw std::bad_cast();
}
auto p = dynamic_cast<holder<T>*>(content_);
assert(p);
if (!p) {
throw std::bad_cast();
}
return p->value_;
}
template <
typename T,
typename std::enable_if<std::is_same<T, any>::value, std::nullptr_t>::type = nullptr
>
T& get() {
return *this;
bool has_value() const {
return content_ != nullptr;
}
template <
typename T,
typename std::enable_if<!std::is_same<T, any>::value, std::nullptr_t>::type = nullptr
>
const T& get() const {
assert(content_);
auto p = dynamic_cast<holder<T>*>(content_);
assert(p);
if (!p) {
throw std::bad_cast();
}
return p->value_;
}
template <typename T>
friend T& any_cast(any& val);
template <
typename T,
typename std::enable_if<std::is_same<T, any>::value, std::nullptr_t>::type = nullptr
>
const any& get() const {
return *this;
}
template <typename T>
friend const T& any_cast(const any& val);
private:
struct placeholder {
@ -157,6 +136,41 @@ private:
placeholder* content_;
};
template <typename T>
T& any_cast(any& val) {
if (!val.content_) {
throw std::bad_cast();
}
auto p = dynamic_cast<any::holder<T>*>(val.content_);
assert(p);
if (!p) {
throw std::bad_cast();
}
return p->value_;
}
template <>
any& any_cast<any>(any& val) {
return val;
}
template <typename T>
const T& any_cast(const any& val) {
assert(val.content_);
auto p = dynamic_cast<any::holder<T>*>(val.content_);
assert(p);
if (!p) {
throw std::bad_cast();
}
return p->value_;
}
template <>
const any& any_cast<any>(const any& val) {
return val;
}
#endif
/*-----------------------------------------------------------------------------
* scope_exit
*---------------------------------------------------------------------------*/
@ -499,7 +513,7 @@ struct SemanticValues : protected std::vector<any>
// Transform the semantic value vector to another vector
template <typename T>
auto transform(size_t beg = 0, size_t end = static_cast<size_t>(-1)) const -> vector<T> {
return this->transform(beg, end, [](const any& v) { return v.get<T>(); });
return this->transform(beg, end, [](const any& v) { return any_cast<T>(v); });
}
SemanticValues() : s_(nullptr), n_(0), choice_count_(0), choice_(0) {}
@ -2061,8 +2075,8 @@ public:
SemanticValues sv;
any dt;
auto r = parse_core(s, n, sv, dt, path);
if (r.ret && !sv.empty() && !sv.front().is_undefined()) {
val = sv[0].get<T>();
if (r.ret && !sv.empty() && sv.front().has_value()) {
val = any_cast<T>(sv[0]);
}
return r;
}
@ -2077,8 +2091,8 @@ public:
Result parse_and_get_value(const char* s, size_t n, any& dt, T& val, const char* path = nullptr) const {
SemanticValues sv;
auto r = parse_core(s, n, sv, dt, path);
if (r.ret && !sv.empty() && !sv.front().is_undefined()) {
val = sv[0].get<T>();
if (r.ret && !sv.empty() && sv.front().has_value()) {
val = any_cast<T>(sv[0]);
}
return r;
}
@ -2645,19 +2659,19 @@ private:
void setup_actions() {
g["Definition"] = [&](const SemanticValues& sv, any& dt) {
auto is_macro = sv.choice() == 0;
auto ignore = sv[0].get<bool>();
auto name = sv[1].get<std::string>();
auto ignore = any_cast<bool>(sv[0]);
auto name = any_cast<std::string>(sv[ 1 ]);
std::vector<std::string> params;
std::shared_ptr<Ope> ope;
if (is_macro) {
params = sv[2].get<std::vector<std::string>>();
ope = sv[4].get<std::shared_ptr<Ope>>();
params = any_cast<std::vector<std::string>>(sv[2]);
ope = any_cast<std::shared_ptr<Ope>>(sv[4]);
} else {
ope = sv[3].get<std::shared_ptr<Ope>>();
ope = any_cast<std::shared_ptr<Ope>>(sv[3]);
}
Data& data = *dt.get<Data*>();
Data& data = *any_cast<Data*>(dt);
auto& grammar = *data.grammar;
if (!grammar.count(name)) {
@ -2678,11 +2692,11 @@ private:
g["Expression"] = [&](const SemanticValues& sv) {
if (sv.size() == 1) {
return sv[0].get<std::shared_ptr<Ope>>();
return any_cast<std::shared_ptr<Ope>>(sv[0]);
} else {
std::vector<std::shared_ptr<Ope>> opes;
for (auto i = 0u; i < sv.size(); i++) {
opes.emplace_back(sv[i].get<std::shared_ptr<Ope>>());
opes.emplace_back(any_cast<std::shared_ptr<Ope>>(sv[i]));
}
const std::shared_ptr<Ope> ope = std::make_shared<PrioritizedChoice>(opes);
return ope;
@ -2691,11 +2705,11 @@ private:
g["Sequence"] = [&](const SemanticValues& sv) {
if (sv.size() == 1) {
return sv[0].get<std::shared_ptr<Ope>>();
return any_cast<std::shared_ptr<Ope>>(sv[0]);
} else {
std::vector<std::shared_ptr<Ope>> opes;
for (const auto& x: sv) {
opes.emplace_back(x.get<std::shared_ptr<Ope>>());
opes.emplace_back(any_cast<std::shared_ptr<Ope>>(x));
}
const std::shared_ptr<Ope> ope = std::make_shared<Sequence>(opes);
return ope;
@ -2705,11 +2719,11 @@ private:
g["Prefix"] = [&](const SemanticValues& sv) {
std::shared_ptr<Ope> ope;
if (sv.size() == 1) {
ope = sv[0].get<std::shared_ptr<Ope>>();
ope = any_cast<std::shared_ptr<Ope>>(sv[0]);
} else {
assert(sv.size() == 2);
auto tok = sv[0].get<char>();
ope = sv[1].get<std::shared_ptr<Ope>>();
auto tok = any_cast<char>(sv[0]);
ope = any_cast<std::shared_ptr<Ope>>(sv[1]);
if (tok == '&') {
ope = apd(ope);
} else { // '!'
@ -2720,12 +2734,12 @@ private:
};
g["Suffix"] = [&](const SemanticValues& sv) {
auto ope = sv[0].get<std::shared_ptr<Ope>>();
auto ope = any_cast<std::shared_ptr<Ope>>(sv[0]);
if (sv.size() == 1) {
return ope;
} else {
assert(sv.size() == 2);
auto tok = sv[1].get<char>();
auto tok = any_cast<char>(sv[1]);
if (tok == '?') {
return opt(ope);
} else if (tok == '*') {
@ -2737,18 +2751,18 @@ private:
};
g["Primary"] = [&](const SemanticValues& sv, any& dt) -> std::shared_ptr<Ope> {
Data& data = *dt.get<Data*>();
Data& data = *any_cast<Data*>(dt);
switch (sv.choice()) {
case 0: // Macro Reference
case 1: { // Reference
auto is_macro = sv.choice() == 0;
auto ignore = sv[0].get<bool>();
const auto& ident = sv[1].get<std::string>();
auto ignore = any_cast<bool>(sv[0]);
const auto& ident = any_cast<std::string>(sv[1]);
std::vector<std::shared_ptr<Ope>> args;
if (is_macro) {
args = sv[2].get<std::vector<std::shared_ptr<Ope>>>();
args = any_cast<std::vector<std::shared_ptr<Ope>>>(sv[2]);
}
if (ignore) {
@ -2758,23 +2772,23 @@ private:
}
}
case 2: { // (Expression)
return sv[0].get<std::shared_ptr<Ope>>();
return any_cast<std::shared_ptr<Ope>>(sv[0]);
}
case 3: { // TokenBoundary
return tok(sv[0].get<std::shared_ptr<Ope>>());
return tok(any_cast<std::shared_ptr<Ope>>(sv[0]));
}
case 4: { // CaptureScope
return csc(sv[0].get<std::shared_ptr<Ope>>());
return csc(any_cast<std::shared_ptr<Ope>>(sv[0]));
}
case 5: { // Capture
const auto& name = sv[0].get<std::string>();
auto ope = sv[1].get<std::shared_ptr<Ope>>();
const auto& name = any_cast<std::string>(sv[0]);
auto ope = any_cast<std::shared_ptr<Ope>>(sv[1]);
return cap(ope, [name](const char* a_s, size_t a_n, Context& c) {
c.capture_scope_stack.back()[name] = std::string(a_s, a_n);
});
}
default: {
return sv[0].get<std::shared_ptr<Ope>>();
return any_cast<std::shared_ptr<Ope>>(sv[0]);
}
}
};
@ -2805,14 +2819,14 @@ private:
g["Range"] = [](const SemanticValues& sv) {
switch (sv.choice()) {
case 0: {
auto s1 = sv[0].get<std::string>();
auto s2 = sv[1].get<std::string>();
auto s1 = any_cast<std::string>(sv[0]);
auto s2 = any_cast<std::string>(sv[1]);
auto cp1 = decode_codepoint(s1.c_str(), s1.length());
auto cp2 = decode_codepoint(s2.c_str(), s2.length());
return std::make_pair(cp1, cp2);
}
case 1: {
auto s = sv[0].get<std::string>();
auto s = any_cast<std::string>(sv[0]);
auto cp = decode_codepoint(s.c_str(), s.length());
return std::make_pair(cp, cp);
}

@ -44,7 +44,7 @@ TEST_CASE("Action taking non const Semantic Values parameter", "[general]")
)");
parser["ROOT"] = [&](peg::SemanticValues& sv) {
auto& s = sv[0].get<std::string>();
auto s = peg::any_cast<std::string>(sv[0]);
s[0] = 'H'; // mutate
return std::string(std::move(s)); // move
};
@ -83,11 +83,10 @@ TEST_CASE("String capture test", "[general]")
}
using namespace peg;
using namespace std;
TEST_CASE("String capture test2", "[general]")
{
vector<string> tags;
std::vector<std::string> tags;
Definition ROOT, TAG, TAG_NAME, WS;
ROOT <= seq(WS, zom(TAG));
@ -178,7 +177,7 @@ TEST_CASE("Lambda action test", "[general]")
CHAR <- .
)");
string ss;
std::string ss;
parser["CHAR"] = [&](const SemanticValues& sv) {
ss += *sv.c_str();
};
@ -198,18 +197,18 @@ TEST_CASE("enter/leave handlers test", "[general]")
)");
parser["LTOKEN"].enter = [&](const char*, size_t, any& dt) {
auto& require_upper_case = *dt.get<bool*>();
auto& require_upper_case = *any_cast<bool*>(dt);
require_upper_case = false;
};
parser["LTOKEN"].leave = [&](const char*, size_t, size_t, any&, any& dt) {
auto& require_upper_case = *dt.get<bool*>();
auto& require_upper_case = *any_cast<bool*>(dt);
require_upper_case = true;
};
auto message = "should be upper case string...";
parser["TOKEN"] = [&](const SemanticValues& sv, any& dt) {
auto& require_upper_case = *dt.get<bool*>();
auto& require_upper_case = *any_cast<bool*>(dt);
if (require_upper_case) {
const auto& s = sv.str();
if (!std::all_of(s.begin(), s.end(), ::isupper)) {
@ -225,7 +224,7 @@ TEST_CASE("enter/leave handlers test", "[general]")
REQUIRE(parser.parse("hello=WORLD", dt) == true);
REQUIRE(parser.parse("HELLO=WORLD", dt) == true);
parser.log = [&](size_t ln, size_t col, const string& msg) {
parser.log = [&](size_t ln, size_t col, const std::string& msg) {
REQUIRE(ln == 1);
REQUIRE(col == 7);
REQUIRE(msg == message);
@ -264,7 +263,7 @@ TEST_CASE("WHITESPACE test2", "[general]")
TAB <- '\t'
)");
vector<string> items;
std::vector<std::string> items;
parser["ITEM"] = [&](const SemanticValues& sv) {
items.push_back(sv.token());
};
@ -398,7 +397,7 @@ TEST_CASE("Backtracking with AST", "[general]")
)");
parser.enable_ast();
shared_ptr<Ast> ast;
std::shared_ptr<Ast> ast;
bool ret = parser.parse("ba", ast);
REQUIRE(ret == true);
REQUIRE(ast->nodes.size() == 2);
@ -437,7 +436,7 @@ TEST_CASE("Ignore case test", "[general]") {
TEST_CASE("mutable lambda test", "[general]")
{
vector<string> vec;
std::vector<std::string> vec;
parser pg("ROOT <- 'mutable lambda test'");
@ -459,18 +458,18 @@ TEST_CASE("Simple calculator test", "[general]")
parser["Additive"] = [](const SemanticValues& sv) {
switch (sv.choice()) {
case 0:
return sv[0].get<int>() + sv[1].get<int>();
return any_cast<int>(sv[0]) + any_cast<int>(sv[1]);
default:
return sv[0].get<int>();
return any_cast<int>(sv[0]);
}
};
parser["Multitive"] = [](const SemanticValues& sv) {
switch (sv.choice()) {
case 0:
return sv[0].get<int>() * sv[1].get<int>();
return any_cast<int>(sv[0]) * any_cast<int>(sv[1]);
default:
return sv[0].get<int>();
return any_cast<int>(sv[0]);
}
};
@ -498,10 +497,10 @@ TEST_CASE("Calculator test", "[general]")
// Setup actions
auto reduce = [](const SemanticValues& sv) -> long {
long ret = sv[0].get<long>();
long ret = any_cast<long>(sv[0]);
for (auto i = 1u; i < sv.size(); i += 2) {
auto num = sv[i + 1].get<long>();
switch (sv[i].get<char>()) {
auto num = any_cast<long>(sv[i + 1]);
switch (any_cast<char>(sv[i])) {
case '+': ret += num; break;
case '-': ret -= num; break;
case '*': ret *= num; break;
@ -538,16 +537,16 @@ TEST_CASE("Calculator test2", "[general]")
NUMBER <- [0-9]+
)";
string start;
std::string start;
auto grammar = ParserGenerator::parse(syntax, strlen(syntax), start, nullptr);
auto& g = *grammar;
// Setup actions
auto reduce = [](const SemanticValues& sv) -> long {
long ret = sv[0].get<long>();
long ret = any_cast<long>(sv[0]);
for (auto i = 1u; i < sv.size(); i += 2) {
auto num = sv[i + 1].get<long>();
switch (sv[i].get<char>()) {
auto num = any_cast<long>(sv[i + 1]);
switch (any_cast<char>(sv[i])) {
case '+': ret += num; break;
case '-': ret -= num; break;
case '*': ret *= num; break;
@ -585,10 +584,10 @@ TEST_CASE("Calculator test3", "[general]")
)");
auto reduce = [](const SemanticValues& sv) -> long {
long ret = sv[0].get<long>();
long ret = any_cast<long>(sv[0]);
for (auto i = 1u; i < sv.size(); i += 2) {
auto num = sv[i + 1].get<long>();
switch (sv[i].get<char>()) {
auto num = any_cast<long>(sv[i + 1]);
switch (any_cast<char>(sv[i])) {
case '+': ret += num; break;
case '-': ret -= num; break;
case '*': ret *= num; break;
@ -627,7 +626,7 @@ TEST_CASE("Calculator test with AST", "[general]")
parser.enable_ast();
function<long (const Ast&)> eval = [&](const Ast& ast) {
std::function<long (const Ast&)> eval = [&](const Ast& ast) {
if (ast.name == "NUMBER") {
return stol(ast.token);
} else {
@ -647,7 +646,7 @@ TEST_CASE("Calculator test with AST", "[general]")
}
};
shared_ptr<Ast> ast;
std::shared_ptr<Ast> ast;
auto ret = parser.parse("1+2*3*(4-5+6)/7-8", ast);
ast = peg::AstOptimizer(true).optimize(ast);
auto val = eval(*ast);
@ -667,7 +666,7 @@ TEST_CASE("Ignore semantic value test", "[general]")
parser.enable_ast();
shared_ptr<Ast> ast;
std::shared_ptr<Ast> ast;
auto ret = parser.parse("Hello World", ast);
REQUIRE(ret == true);
@ -687,7 +686,7 @@ TEST_CASE("Ignore semantic value of 'or' predicate test", "[general]")
parser.enable_ast();
shared_ptr<Ast> ast;
std::shared_ptr<Ast> ast;
auto ret = parser.parse("Hello World.", ast);
REQUIRE(ret == true);
@ -706,7 +705,7 @@ TEST_CASE("Ignore semantic value of 'and' predicate test", "[general]")
parser.enable_ast();
shared_ptr<Ast> ast;
std::shared_ptr<Ast> ast;
auto ret = parser.parse("Hello World.", ast);
REQUIRE(ret == true);
@ -721,7 +720,7 @@ TEST_CASE("Literal token on AST test1", "[general]")
)");
parser.enable_ast();
shared_ptr<Ast> ast;
std::shared_ptr<Ast> ast;
auto ret = parser.parse(R"("a\tb")", ast);
REQUIRE(ret == true);
@ -739,7 +738,7 @@ TEST_CASE("Literal token on AST test2", "[general]")
)");
parser.enable_ast();
shared_ptr<Ast> ast;
std::shared_ptr<Ast> ast;
auto ret = parser.parse(R"("a\tb")", ast);
REQUIRE(ret == true);
@ -757,7 +756,7 @@ TEST_CASE("Literal token on AST test3", "[general]")
)");
parser.enable_ast();
shared_ptr<Ast> ast;
std::shared_ptr<Ast> ast;
auto ret = parser.parse(R"("a\tb")", ast);
REQUIRE(ret == true);
@ -798,12 +797,12 @@ TEST_CASE("Semantic values test", "[general]")
for (const auto& rule: parser.get_rule_names()){
parser[rule.c_str()] = [rule](const SemanticValues& sv, any&) {
if (rule == "term") {
REQUIRE(sv[0].get<string>() == "a at 0");
REQUIRE(sv[1].get<string>() == "b at 1");
REQUIRE(sv[2].get<string>() == "c at 2");
return string();
REQUIRE(any_cast<std::string>(sv[0]) == "a at 0");
REQUIRE(any_cast<std::string>(sv[1]) == "b at 1");
REQUIRE(any_cast<std::string>(sv[2]) == "c at 2");
return std::string();
} else {
return rule + " at " + to_string(sv.c_str() - sv.ss);
return rule + " at " + std::to_string(sv.c_str() - sv.ss);
}
};
}
@ -1149,7 +1148,7 @@ TEST_CASE("User defined rule test", "[user rule]")
{
{
"NAME", usr([](const char* s, size_t n, SemanticValues& /*sv*/, any& /*dt*/) -> size_t {
static vector<string> names = { "PEG", "BNF" };
static std::vector<std::string> names = { "PEG", "BNF" };
for (const auto& name: names) {
if (name.size() <= n && !name.compare(0, name.size(), s, name.size())) {
return name.size();
@ -1336,10 +1335,10 @@ TEST_CASE("Macro calculator", "[macro]")
// Setup actions
auto reduce = [](const SemanticValues& sv) -> long {
auto result = sv[0].get<long>();
auto result = any_cast<long>(sv[0]);
for (auto i = 1u; i < sv.size(); i += 2) {
auto num = sv[i + 1].get<long>();
auto ope = sv[i].get<char>();
auto num = any_cast<long>(sv[i + 1]);
auto ope = any_cast<char>(sv[i]);
switch (ope) {
case '+': result += num; break;
case '-': result -= num; break;
@ -1462,7 +1461,7 @@ TEST_CASE("Line information test", "[line information]")
~_ <- [ \t\r\n]+
)");
std::vector<std::pair<int, int>> locations;
std::vector<std::pair<size_t, size_t>> locations;
parser["WORD"] = [&](const peg::SemanticValues& sv) {
locations.push_back(sv.line_info());
};
@ -1473,13 +1472,13 @@ TEST_CASE("Line information test", "[line information]")
ret = parser.parse(" Mon Tue Wed \nThu Fri Sat\nSun\n");
REQUIRE(ret == true);
REQUIRE(locations[0] == std::make_pair(1, 2));
REQUIRE(locations[1] == std::make_pair(1, 6));
REQUIRE(locations[2] == std::make_pair(1, 10));
REQUIRE(locations[3] == std::make_pair(2, 1));
REQUIRE(locations[4] == std::make_pair(2, 6));
REQUIRE(locations[5] == std::make_pair(2, 11));
REQUIRE(locations[6] == std::make_pair(3, 1));
REQUIRE(locations[0] == std::make_pair<size_t, size_t>(1, 2));
REQUIRE(locations[1] == std::make_pair<size_t, size_t>(1, 6));
REQUIRE(locations[2] == std::make_pair<size_t, size_t>(1, 10));
REQUIRE(locations[3] == std::make_pair<size_t, size_t>(2, 1));
REQUIRE(locations[4] == std::make_pair<size_t, size_t>(2, 6));
REQUIRE(locations[5] == std::make_pair<size_t, size_t>(2, 11));
REQUIRE(locations[6] == std::make_pair<size_t, size_t>(3, 1));
}
bool exact(Grammar& g, const char* d, const char* s) {

Loading…
Cancel
Save