Added start at C++ bindings
This commit is contained in:
parent
61f79252a5
commit
bda2fb4741
5 changed files with 239 additions and 0 deletions
9
src/bindings/cpp/SConscript
Normal file
9
src/bindings/cpp/SConscript
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
# -*- python -*-
|
||||
Import("env libhammer_shared")
|
||||
|
||||
cppenv = env.Clone()
|
||||
cppenv.Append(INCPATH=["."])
|
||||
|
||||
|
||||
libhammerxx = env.SharedLibrary("hammer++", libhammer_shared + ["hammer.cpp"])
|
||||
|
||||
23
src/bindings/cpp/cpp_tests.cpp
Normal file
23
src/bindings/cpp/cpp_tests.cpp
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <hammer/hammer.hpp>
|
||||
#include <hammer/hammer_test.hpp>
|
||||
|
||||
namespace {
|
||||
using namespace ::hammer;
|
||||
TEST(ParserTypes, Token) {
|
||||
Parser p = Token("95\xA2");
|
||||
EXPECT_TRUE(ParsesTo(p, "95\xA2", "<39.35.a2>"));
|
||||
EXPECT_TRUE(ParseFails(p, "95"));
|
||||
}
|
||||
|
||||
TEST(ParserTypes, Ch) {
|
||||
Parser p = Ch(0xA2);
|
||||
EXPECT_TRUE(ParsesTo(p, "\xA2", "u0xa2"));
|
||||
EXPECT_TRUE(ParseFails(p, "\xA3"));
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
1
src/bindings/cpp/hammer/hammer.cpp
Normal file
1
src/bindings/cpp/hammer/hammer.cpp
Normal file
|
|
@ -0,0 +1 @@
|
|||
|
||||
160
src/bindings/cpp/hammer/hammer.hpp
Normal file
160
src/bindings/cpp/hammer/hammer.hpp
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
#ifndef HAMMER_HAMMER__HPP
|
||||
#define HAMMER_HAMMER__HPP
|
||||
|
||||
#include <hammer/hammer.h>
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace hammer {
|
||||
class Parser {
|
||||
|
||||
};
|
||||
|
||||
class ParsedToken {
|
||||
// This object can suddenly become invalid if the underlying parse
|
||||
// tree is destroyed.
|
||||
|
||||
// This object should serve as a very thin wrapper around an HParsedToken*.
|
||||
// In particular sizeof(ParsedToken) should== sizeof(HParsedToken*)
|
||||
// This means that we only get one member variable and no virtual functions.
|
||||
protected:
|
||||
HParsedToken *token;
|
||||
|
||||
public:
|
||||
|
||||
ParsedToken(HParsedToken *inner) : token(inner) {}
|
||||
ParsedToken(const ParsedToken &other) : token(other.token) {}
|
||||
|
||||
inline TokenType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
void* getUser() {
|
||||
return token->user;
|
||||
}
|
||||
// TODO: add accessors.
|
||||
|
||||
|
||||
std::string asUnambiguous() {
|
||||
char* buf = h_write_result_unamb(token);
|
||||
std::string s = std::string(buf);
|
||||
free(buf);
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
class ParseResult {
|
||||
protected:
|
||||
HParseResult *_result;
|
||||
public:
|
||||
|
||||
ParsedToken getAST() {
|
||||
return ParsedToken(_result);
|
||||
}
|
||||
inline string asUnambiguous() {
|
||||
return getAST().asUnambiguous();
|
||||
}
|
||||
|
||||
bool operator bool() {
|
||||
return _result != NULL;
|
||||
}
|
||||
bool operator !() {
|
||||
return _result == NULL;
|
||||
}
|
||||
|
||||
~ParseResult() {
|
||||
h_parse_result_free(_result);
|
||||
_result = NULL;
|
||||
}
|
||||
};
|
||||
|
||||
inline Parser token(const std::string &str) {
|
||||
std::string *str_clone = new std::string(str);
|
||||
return Parser(h_token(str_clone->data(), str.
|
||||
}
|
||||
Parser token(const uint8_t *buf, size_t len);
|
||||
|
||||
Parser ch(char ch);
|
||||
|
||||
Parser ch_range(uint8_t lower, uint8_t upper);
|
||||
|
||||
Parser int64();
|
||||
Parser int32();
|
||||
Parser int16();
|
||||
Parser int8();
|
||||
|
||||
Parser uint64();
|
||||
Parser uint32();
|
||||
Parser uint16();
|
||||
Parser uint8();
|
||||
|
||||
Parser int_range(Parser p, int64_t lower, int64_t upper);
|
||||
|
||||
Parser bits(size_t len, bool sign);
|
||||
|
||||
Parser whitespace(Parser p);
|
||||
|
||||
Parser left(Parser p, Parser q);
|
||||
|
||||
Parser right(Parser p, Parser q);
|
||||
|
||||
Parser middle(Parser p, Parser q, Parser r);
|
||||
|
||||
// TODO: Define Action
|
||||
//Parser action(Parser p, Action a);
|
||||
|
||||
Parser in(string charset);
|
||||
Parser in(const uint8_t *charset, size_t length);
|
||||
Parser in(std::set<uint8_t> charset);
|
||||
|
||||
Parser not_in(string charset);
|
||||
Parser not_in(const uint8_t *charset, size_t length);
|
||||
Parser not_in(std::set<uint8_t> charset);
|
||||
|
||||
Parser end();
|
||||
|
||||
Parser nothing();
|
||||
|
||||
// TODO: figure out varargs
|
||||
//Parser sequence();
|
||||
//
|
||||
//Parser choice();
|
||||
|
||||
Parser butnot(Parser p1, Parser p2);
|
||||
|
||||
Parser difference(Parser p1, Parser p2);
|
||||
|
||||
Parser xor_(Parser p1, Parser p2);
|
||||
|
||||
Parser many(Parser p);
|
||||
|
||||
Parser many1(Parser p);
|
||||
|
||||
Parser repeat_n(Parser p, size_t n);
|
||||
|
||||
Parser optional(Parser p);
|
||||
|
||||
Parser ignore(Parser p);
|
||||
|
||||
Parser sepBy(Parser p, Parser sep);
|
||||
|
||||
Parser sepBy1(Parser p, Parser sep);
|
||||
|
||||
Parser epsilon();
|
||||
|
||||
Parser length_value(Parser length, Parser value);
|
||||
|
||||
// Was attr_bool in the old C bindings.
|
||||
// TODO: Figure out closure
|
||||
//Parser validate(Parser p, Predicate pred);
|
||||
|
||||
Parser and_(Parser p);
|
||||
|
||||
Parser not_(Parser p);
|
||||
|
||||
IndirectParser indirect();
|
||||
static inline void bind_indirect(IndirectParser &indirect, Parser p) {
|
||||
indirect.bind(p);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
46
src/bindings/cpp/hammer/hammer_test.hpp
Normal file
46
src/bindings/cpp/hammer/hammer_test.hpp
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
#ifndef HAMMER_HAMMER_TEST__HPP
|
||||
#define HAMMER_HAMMER_TEST__HPP
|
||||
#include <string>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <hammer/hammer.hpp>
|
||||
|
||||
static ::testing::AssertionResult ParseFails(hammer::Parser parser,
|
||||
const string &input) {
|
||||
hammer::ParseResult result = parser.Parse(input);
|
||||
if (result) {
|
||||
return ::testing::AssertionFailure() << "Parse succeeded with " << result.AsUnambiguous() << "; expected failure";
|
||||
} else {
|
||||
return ::testing::AssertionSuccess();
|
||||
}
|
||||
}
|
||||
|
||||
static ::testing::AssertionResult ParsesOK(hammer::Parser parser,
|
||||
const string &input) {
|
||||
hammer::ParseResult result = parser.Parse(input);
|
||||
if (!result) {
|
||||
return ::testing::AssertionFailure() << "Parse failed; expected success";
|
||||
} else {
|
||||
return ::testing::AssertionSuccess();
|
||||
}
|
||||
}
|
||||
|
||||
static ::testing::AssertionResult ParsesTo(hammer::Parser parser,
|
||||
const string &input,
|
||||
const string &expected_result) {
|
||||
hammer::ParseResult result = parser.Parse(input);
|
||||
if (!result) {
|
||||
return ::testing::AssertionFailure() << "Parse failed; expected success";
|
||||
} else if (result.AsUnambiguous() != expected_result) {
|
||||
return ::testing::AssertionFailure()
|
||||
<< "Parse succeeded with wrong result: got "
|
||||
<< result.AsUnambiguous()
|
||||
<< "; expected "
|
||||
<< expected_result;
|
||||
} else {
|
||||
return ::testing::AssertionSuccess();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif // defined(HAMMER_HAMMER_TEST__HPP)
|
||||
Loading…
Add table
Add a link
Reference in a new issue