C++ bindings now work!

This commit is contained in:
Meredith L. Patterson 2014-01-16 18:58:36 +01:00
parent 270dc3f1b8
commit 1d6a6d90ab
7 changed files with 195 additions and 86 deletions

View file

@ -19,6 +19,10 @@
#define HAMMER_ALLOCATOR__H__
#include <sys/types.h>
#ifdef __cplusplus
extern "C" {
#endif
// TODO(thequux): Turn this into an "HAllocatorVtable", and add a wrapper that also takes an environment pointer.
typedef struct HAllocator_ {
void* (*alloc)(struct HAllocator_* allocator, size_t size);
@ -44,5 +48,8 @@ typedef struct {
void h_allocator_stats(HArena *arena, HArenaStats *stats);
#ifdef __cplusplus
}
#endif
#endif // #ifndef LIB_ALLOCATOR__H__

2
src/bindings/cpp/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
hammer_test
test_detail.xml

View file

@ -2,7 +2,7 @@
Import("env libhammer_shared")
cppenv = env.Clone()
cppenv.Append(CPPPATH=[".", "vendor/gtest-1.7.0/fused-src"])
cppenv.Append(CPPPATH=[".", "vendor/gtest-1.7.0/fused-src", "../.."])
cppenv.MergeFlags("-Wno-missing-field-initializers -DGTEST_HAS_PTHREAD=0")

View file

@ -1,7 +1,10 @@
#include <gtest/gtest.h>
#include <hammer/hammer.hpp>
#include <hammer/internal.h>
#include <hammer/hammer_test.hpp>
#define a_new_(arena, typ, count) ((typ*)h_arena_malloc((arena), sizeof(typ)*(count)))
namespace {
using namespace ::hammer;
TEST(ParserTypes, Token) {
@ -24,23 +27,23 @@ namespace {
TEST(ParserTypes, Int64) {
Parser p = Int64();
EXPECT_TRUE(ParsesTo(p, "\xff\xff\xff\xfe\x00\x00\x00\x00", "s-0x200000000"));
EXPECT_TRUE(ParseFails(p, "\xff\xff\xff\xfe\x00\x00\x00"));
EXPECT_TRUE(ParsesTo(p, std::string("\xff\xff\xff\xfe\x00\x00\x00\x00", 8), "s-0x200000000"));
EXPECT_TRUE(ParseFails(p, std::string("\xff\xff\xff\xfe\x00\x00\x00", 7)));
}
TEST(ParserTypes, Int32) {
Parser p = Int32();
EXPECT_TRUE(ParsesTo(p, "\xff\xfe\x00\x00", "s-0x20000"));
EXPECT_TRUE(ParseFails(p, "\xff\xfe\x00"));
EXPECT_TRUE(ParsesTo(p, "\x00\x02\x00\x00","s0x20000"));
EXPECT_TRUE(ParseFails(p, "\x00\x02\x00"));
EXPECT_TRUE(ParsesTo(p, std::string("\xff\xfe\x00\x00", 4), "s-0x20000"));
EXPECT_TRUE(ParseFails(p, std::string("\xff\xfe\x00", 3)));
EXPECT_TRUE(ParsesTo(p, std::string("\x00\x02\x00\x00",4) ,"s0x20000"));
EXPECT_TRUE(ParseFails(p, std::string("\x00\x02\x00", 3)));
}
TEST(ParserTypes, Int16) {
Parser p = Int16();
EXPECT_TRUE(ParsesTo(p, "\xfe\x00", "s-0x200"));
EXPECT_TRUE(ParsesTo(p, std::string("\xfe\x00", 2), "s-0x200"));
EXPECT_TRUE(ParseFails(p, "\xfe"));
EXPECT_TRUE(ParsesTo(p, "\x02\x00", "s0x200"));
EXPECT_TRUE(ParsesTo(p, std::string("\x02\x00", 2), "s0x200"));
EXPECT_TRUE(ParseFails(p, "\x01"));
}
@ -52,19 +55,19 @@ namespace {
TEST(ParserTypes, Uint64) {
Parser p = Uint64();
EXPECT_TRUE(ParsesTo(p, "\x00\x00\x00\x02\x00\x00\x00\x00", "u0x200000000"));
EXPECT_TRUE(ParseFails(p, "\x00\x00\x00\x02\x00\x00\x00"));
EXPECT_TRUE(ParsesTo(p, std::string("\x00\x00\x00\x02\x00\x00\x00\x00", 8), "u0x200000000"));
EXPECT_TRUE(ParseFails(p, std::string("\x00\x00\x00\x02\x00\x00\x00", 7)));
}
TEST(ParserTypes, Uint32) {
Parser p = Uint32();
EXPECT_TRUE(ParsesTo(p, "\x00\x02\x00\x00", "u0x20000"));
EXPECT_TRUE(ParseFails(p, "\x00\x02\x00"));
EXPECT_TRUE(ParsesTo(p, std::string("\x00\x02\x00\x00", 4), "u0x20000"));
EXPECT_TRUE(ParseFails(p, std::string("\x00\x02\x00", 3)));
}
TEST(ParserTypes, Uint16) {
Parser p = Uint16();
EXPECT_TRUE(ParsesTo(p, "\x02\x00", "u0x200"));
EXPECT_TRUE(ParsesTo(p, std::string("\x02\x00", 2), "u0x200"));
EXPECT_TRUE(ParseFails(p, "\x02"));
}
@ -82,7 +85,7 @@ namespace {
TEST(ParserTypes, Whitespace) {
Parser p = Whitespace(Ch('a'));
Parser q = Whitespace(EndP());
Parser q = Whitespace(End());
EXPECT_TRUE(ParsesTo(p, "a", "u0x61"));
EXPECT_TRUE(ParsesTo(p, " a", "u0x61"));
EXPECT_TRUE(ParsesTo(p, " a", "u0x61"));
@ -121,13 +124,45 @@ namespace {
EXPECT_TRUE(ParseFails(p, " ab"));
}
// TODO action function
#include <ctype.h>
HParsedToken* upcase(const HParseResult *p, void* user_data) {
switch(p->ast->token_type) {
case TT_SEQUENCE:
{
HParsedToken *ret = a_new_(p->arena, HParsedToken, 1);
HCountedArray *seq = h_carray_new_sized(p->arena, p->ast->seq->used);
ret->token_type = TT_SEQUENCE;
for (size_t i=0; i<p->ast->seq->used; ++i) {
if (TT_UINT == ((HParsedToken*)p->ast->seq->elements[i])->token_type) {
HParsedToken *tmp = a_new_(p->arena, HParsedToken, 1);
tmp->token_type = TT_UINT;
tmp->uint = toupper(((HParsedToken*)p->ast->seq->elements[i])->uint);
h_carray_append(seq, tmp);
} else {
h_carray_append(seq, p->ast->seq->elements[i]);
}
}
ret->seq = seq;
return ret;
}
case TT_UINT:
{
HParsedToken *ret = a_new_(p->arena, HParsedToken, 1);
ret->token_type = TT_UINT;
ret->uint = toupper(p->ast->uint);
return ret;
}
default:
return (HParsedToken*)p->ast;
}
}
TEST(ParserTypes, Action) {
Parser p = Action(Sequence(Choice(Ch('a'), Ch('A'), NULL),
Choice(Ch('b'), Ch('B'), NULL),
NULL),
toupper); // this won't compile
upcase);
EXPECT_TRUE(ParsesTo(p, "ab", "(u0x41 u0x42)"));
EXPECT_TRUE(ParsesTo(p, "AB", "(u0x41 u0x42)"));
EXPECT_TRUE(ParseFails(p, "XX"));
@ -145,14 +180,14 @@ namespace {
EXPECT_TRUE(ParseFails(p, "a"));
}
TEST(ParserTypes, EndP) {
Parser p = Sequence(Ch('a'), EndP(), NULL);
TEST(ParserTypes, End) {
Parser p = Sequence(Ch('a'), End(), NULL);
EXPECT_TRUE(ParsesTo(p, "a", "(u0x61)"));
EXPECT_TRUE(ParseFails(p, "aa"));
}
TEST(ParserTypes, NothingP) {
Parser p = NothingP();
TEST(ParserTypes, Nothing) {
Parser p = Nothing();
EXPECT_TRUE(ParseFails(p, "a"));
}
@ -207,7 +242,7 @@ namespace {
TEST(ParserTypes, Many1) {
Parser p = Many1(Choice(Ch('a'), Ch('b'), NULL));
EXPECT_TRUE(ParseFails(p, "", "()"));
EXPECT_TRUE(ParseFails(p, ""));
EXPECT_TRUE(ParsesTo(p, "a", "(u0x61)"));
EXPECT_TRUE(ParsesTo(p, "b", "(u0x62)"));
EXPECT_TRUE(ParsesTo(p, "aabbaba", "(u0x61 u0x61 u0x62 u0x62 u0x61 u0x62 u0x61)"));
@ -232,7 +267,7 @@ namespace {
}
TEST(ParserTypes, Ignore) {
Parser p = Sequence(Ch('a'), Ignore(Ch('b'), Ch('c'), NULL));
Parser p = Sequence(Ch('a'), Ignore(Ch('b')), Ch('c'), NULL);
EXPECT_TRUE(ParsesTo(p, "abc", "(u0x61 u0x63)"));
EXPECT_TRUE(ParseFails(p, "ac"));
}
@ -256,15 +291,23 @@ namespace {
}
TEST(ParserTypes, EpsilonP) {
Parser p = Sequence(Ch('a'), EpsilonP(), Ch('b'), NULL);
Parser q = Sequence(EpsilonP(), Ch('a'), NULL);
Parser r = Sequence(Ch('a'), EpsilonP(), NULL);
Parser p = Sequence(Ch('a'), Epsilon(), Ch('b'), NULL);
Parser q = Sequence(Epsilon(), Ch('a'), NULL);
Parser r = Sequence(Ch('a'), Epsilon(), NULL);
EXPECT_TRUE(ParsesTo(p, "ab", "(u0x61 u0x62)"));
EXPECT_TRUE(ParsesTo(q, "a", "(u0x61)"));
EXPECT_TRUE(ParsesTo(r, "a", "(u0x61)"));
}
bool validate_test_ab() { return false; }
bool validate_test_ab(HParseResult *p, void* user_data) {
if (TT_SEQUENCE != p->ast->token_type)
return false;
if (TT_UINT != p->ast->seq->elements[0]->token_type)
return false;
if (TT_UINT != p->ast->seq->elements[1]->token_type)
return false;
return (p->ast->seq->elements[0]->uint == p->ast->seq->elements[1]->uint);
}
TEST(ParserTypes, AttrBool) {
Parser p = AttrBool(Many1(Choice(Ch('a'), Ch('b'), NULL)),
@ -293,21 +336,21 @@ namespace {
Ch('b'), NULL);
EXPECT_TRUE(ParsesTo(p, "a+b", "(u0x61 u0x2b u0x62)"));
EXPECT_TRUE(ParseFails(p, "a++b"));
EXPECT_TRUE(ParsesTo(p, "a+b", "(u0x61 (u0x2b) u0x62)"));
EXPECT_TRUE(ParsesTo(p, "a++b", "(u0x61 <2b.2b> u0x62)"));
EXPECT_TRUE(ParsesTo(q, "a+b", "(u0x61 (u0x2b) u0x62)"));
EXPECT_TRUE(ParsesTo(q, "a++b", "(u0x61 <2b.2b> u0x62)"));
}
/*
TEST(ParserTypes, Leftrec) {
IndirectParser p = Indirect();
p.bind(Choice(Sequence(p, Ch('a'), NULL), EpsilonP(), NULL));
Indirect p = Indirect();
p.bind(Choice(Sequence(p, Ch('a'), NULL), Epsilon(), NULL));
EXPECT_TRUE(ParsesTo(p, "a", "(u0x61)"));
EXPECT_TRUE(ParsesTo(p, "aa", "((u0x61) u0x61)"));
EXPECT_TRUE(ParsesTo(p, "aaa", "(((u0x61) u0x61) u0x61)"));
}
*/
TEST(ParserTypes, Rightrec) {
IndirectParser p = Indirect();
p.bind(Choice(Sequence(Ch('a'), p, NULL), EpsilonP(), NULL));
Indirect p = Indirect();
p.bind(Choice(Sequence(Ch('a'), p, NULL), Epsilon(), NULL));
EXPECT_TRUE(ParsesTo(p, "a", "(u0x61)"));
EXPECT_TRUE(ParsesTo(p, "aa", "(u0x61 (u0x61))"));
EXPECT_TRUE(ParsesTo(p, "aaa", "(u0x61 (u0x61 (u0x61)))"));

View file

@ -4,6 +4,9 @@
#include <hammer/hammer.h>
#include <string>
#include <stdint.h>
#include <cstdarg>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused"
namespace hammer {
class ParseResult;
@ -12,9 +15,9 @@ namespace hammer {
const HParser *parser;
Parser(const HParser* inner) : parser(inner) {}
Parser(const Parser &other) : parser(other.parser) {}
ParseResult parse(std::string string);
//static Parser nil = Parser(NULL);
ParseResult parse(const std::string &string);
};
class ParsedToken {
@ -39,7 +42,7 @@ namespace hammer {
void* getUser() const {return token->user;}
uint64_t getUint() const {return token->uint;}
int64_t getSint() const {return token->sint;}
// TODO: Sequence GetSeq() const {return Sequence(token->seq);}
// TODO: Sequence getSeq() const {return Sequence(token->seq);}
std::string getBytes() const {return std::string((char*)token->bytes.token, token->bytes.len); }
@ -78,7 +81,7 @@ namespace hammer {
}
};
inline ParseResult Parser::parse(std::string string) {
inline ParseResult Parser::parse(const std::string &string) {
return ParseResult(h_parse(parser, (uint8_t*)string.data(), string.length()));
}
@ -96,66 +99,109 @@ namespace hammer {
return Parser(h_ch_range(lower,upper));
}
static inline Parser int64() { return Parser(h_int64()); }
static inline Parser int32() { return Parser(h_int32()); }
static inline Parser int16() { return Parser(h_int16()); }
static inline Parser int8 () { return Parser(h_int8 ()); }
static inline Parser Int64() { return Parser(h_int64()); }
static inline Parser Int32() { return Parser(h_int32()); }
static inline Parser Int16() { return Parser(h_int16()); }
static inline Parser Int8 () { return Parser(h_int8 ()); }
static inline Parser uint64() { return Parser(h_uint64()); }
static inline Parser uint32() { return Parser(h_uint32()); }
static inline Parser uint16() { return Parser(h_uint16()); }
static inline Parser uint8 () { return Parser(h_uint8 ()); }
static inline Parser Uint64() { return Parser(h_uint64()); }
static inline Parser Uint32() { return Parser(h_uint32()); }
static inline Parser Uint16() { return Parser(h_uint16()); }
static inline Parser Uint8 () { return Parser(h_uint8 ()); }
static inline Parser int_range(Parser p, int64_t lower, int64_t upper) {
static inline Parser IntRange(Parser p, int64_t lower, int64_t upper) {
return Parser(h_int_range(p.parser, lower, upper));
}
static inline Parser bits(size_t len, bool sign) { return Parser(h_bits(len, sign)); }
static inline Parser whitespace(Parser p) { return Parser(h_whitespace(p.parser)); }
static inline Parser left(Parser p, Parser q) { return Parser(h_left(p.parser, q.parser)); }
static inline Parser right(Parser p, Parser q) { return Parser(h_right(p.parser, q.parser)); }
static inline Parser middle(Parser p, Parser q, Parser r) {
static inline Parser Bits(size_t len, bool sign) { return Parser(h_bits(len, sign)); }
static inline Parser Whitespace(Parser p) { return Parser(h_whitespace(p.parser)); }
static inline Parser Left(Parser p, Parser q) { return Parser(h_left(p.parser, q.parser)); }
static inline Parser Right(Parser p, Parser q) { return Parser(h_right(p.parser, q.parser)); }
static inline Parser Middle(Parser p, Parser q, Parser r) {
return Parser(h_middle(p.parser, q.parser, r.parser));
}
// TODO: Define Action
//Parser action(Parser p, Action a);
// User is responsible for ensuring that function remains allocated.
Parser Action(Parser p, HAction action, void* user_data) {
return Parser(h_action(p.parser, action, user_data));
}
static inline Parser in(std::string charset);
static inline Parser in(const uint8_t *charset, size_t length);
static inline Parser in(std::set<uint8_t> charset);
Parser Action(Parser p, HAction action) {
return Parser(h_action(p.parser, action, NULL));
}
static inline Parser not_in(std::string charset);
static inline Parser not_in(const uint8_t *charset, size_t length);
static inline Parser not_in(std::set<uint8_t> charset);
Parser AttrBool(Parser p, HPredicate pred, void* user_data) {
return Parser(h_attr_bool(p.parser, pred, user_data));
}
static inline Parser end() { return Parser(h_end_p()); }
static inline Parser nothing() { return Parser(h_nothing_p()); }
Parser AttrBool(Parser p, HPredicate pred) {
return Parser(h_attr_bool(p.parser, pred, NULL));
}
static inline Parser In(const std::string &charset) {
return Parser(h_in((const uint8_t*)charset.data(), charset.length()));
}
static inline Parser In(const uint8_t *charset, size_t length) {
return Parser(h_in(charset, length));
}
/* TODO
static inline Parser In(std::set<uint8_t> charset) {
}
*/
static inline Parser NotIn(const std::string &charset) {
return Parser(h_not_in((const uint8_t*)charset.data(), charset.length()));
}
static inline Parser NotIn(const uint8_t *charset, size_t length) {
return Parser(h_not_in(charset, length));
}
/* TODO
static inline Parser NotIn(std::set<uint8_t> charset) { }
*/
static inline Parser End() { return Parser(h_end_p()); }
static inline Parser Nothing() { return Parser(h_nothing_p()); }
// TODO: figure out varargs
//Parser sequence();
//
//Parser choice();
static inline Parser Sequence(Parser p, ...) {
va_list ap;
va_start(ap, p);
// old-skool reinterpret_cast<HParser*>(p)
HParser* ret = h_sequence__v(*(HParser**)(void*)&p,
ap);
va_end(ap);
return Parser(ret);
}
static inline Parser butnot(Parser p1, Parser p2) { return Parser(h_butnot(p1.parser, p2.parser)); }
static inline Parser difference(Parser p1, Parser p2) { return Parser(h_difference(p1.parser, p2.parser)); }
static inline Parser xor_(Parser p1, Parser p2) { return Parser(h_xor(p1.parser, p2.parser)); }
static inline Parser many(Parser p) { return Parser(h_many(p.parser)); }
static inline Parser many1(Parser p) { return Parser(h_many1(p.parser)); }
static inline Parser repeat_n(Parser p, size_t n) { return Parser(h_repeat_n(p.parser, n)); }
static inline Parser optional(Parser p) { return Parser(h_optional(p.parser)); }
static inline Parser ignore(Parser p) { return Parser(h_ignore(p.parser)); }
static inline Parser sepBy(Parser p, Parser sep) { return Parser(h_sepBy(p.parser, sep.parser)); }
static inline Parser sepBy1(Parser p, Parser sep) { return Parser(h_sepBy1(p.parser, sep.parser)); }
static inline Parser epsilon() { return Parser(h_epsilon_p()); }
static inline Parser length_value(Parser length, Parser value) { return Parser(h_length_value(length.parser, value.parser)); }
static inline Parser Choice(Parser p, ...) {
va_list ap;
va_start(ap, p);
// old-skool reinterpret_cast<HParser*>(p)
HParser* ret = h_choice__v(*(HParser**)(void*)&p,
ap);
va_end(ap);
return Parser(ret);
}
static inline Parser ButNot(Parser p1, Parser p2) { return Parser(h_butnot(p1.parser, p2.parser)); }
static inline Parser Difference(Parser p1, Parser p2) { return Parser(h_difference(p1.parser, p2.parser)); }
static inline Parser Xor(Parser p1, Parser p2) { return Parser(h_xor(p1.parser, p2.parser)); }
static inline Parser Many(Parser p) { return Parser(h_many(p.parser)); }
static inline Parser Many1(Parser p) { return Parser(h_many1(p.parser)); }
static inline Parser RepeatN(Parser p, size_t n) { return Parser(h_repeat_n(p.parser, n)); }
static inline Parser Optional(Parser p) { return Parser(h_optional(p.parser)); }
static inline Parser Ignore(Parser p) { return Parser(h_ignore(p.parser)); }
static inline Parser SepBy(Parser p, Parser sep) { return Parser(h_sepBy(p.parser, sep.parser)); }
static inline Parser SepBy1(Parser p, Parser sep) { return Parser(h_sepBy1(p.parser, sep.parser)); }
static inline Parser Epsilon() { return Parser(h_epsilon_p()); }
static inline Parser LengthValue(Parser length, Parser value) { return Parser(h_length_value(length.parser, value.parser)); }
// Was attr_bool in the old C bindings.
// TODO: Figure out closure
//Parser validate(Parser p, Predicate pred);
static inline Parser and_(Parser p) { return Parser(h_and(p.parser)); }
static inline Parser not_(Parser p) { return Parser(h_not(p.parser)); }
static inline Parser And(Parser p) { return Parser(h_and(p.parser)); }
static inline Parser Not(Parser p) { return Parser(h_not(p.parser)); }
class Indirect : public Parser {
public:
@ -169,4 +215,6 @@ namespace hammer {
// return Parser(foo);
//}
}
#pragma GCC diagnostic pop
#endif

View file

@ -7,9 +7,8 @@
#define HAMMER_DECL_UNUSED __attribute__((unused))
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused"
static ::testing::AssertionResult ParseFails (hammer::Parser parser,
const std::string &input) HAMMER_DECL_UNUSED;
static ::testing::AssertionResult ParseFails (hammer::Parser parser,
const std::string &input) {
hammer::ParseResult result = parser.parse(input);
@ -20,6 +19,8 @@ static ::testing::AssertionResult ParseFails (hammer::Parser parser,
}
}
static ::testing::AssertionResult ParsesOK(hammer::Parser parser,
const std::string &input) HAMMER_DECL_UNUSED;
static ::testing::AssertionResult ParsesOK(hammer::Parser parser,
const std::string &input) {
hammer::ParseResult result = parser.parse(input);
@ -30,6 +31,9 @@ static ::testing::AssertionResult ParsesOK(hammer::Parser parser,
}
}
static ::testing::AssertionResult ParsesTo(hammer::Parser parser,
const std::string &input,
const std::string &expected_result) HAMMER_DECL_UNUSED;
static ::testing::AssertionResult ParsesTo(hammer::Parser parser,
const std::string &input,
const std::string &expected_result) {
@ -47,6 +51,4 @@ static ::testing::AssertionResult ParsesTo(hammer::Parser parser,
}
}
#pragma GCC diagnostic pop
#endif // defined(HAMMER_HAMMER_TEST__HPP)

View file

@ -47,8 +47,13 @@
#define h_new(type, count) ((type*)(mm__->alloc(mm__, sizeof(type)*(count))))
#define h_free(addr) (mm__->free(mm__, (addr)))
#ifndef __cplusplus
#define false 0
#define true 1
#endif
#ifdef __cplusplus
extern "C" {
#endif
// This is going to be generally useful.
static inline void h_generic_free(HAllocator *allocator, void* ptr) {
@ -388,5 +393,7 @@ bool h_not_regular(HRVMProg*, void*);
#include <stdlib.h>
#define h_arena_malloc(a, s) malloc(s)
#endif
#ifdef __cplusplus
} // extern "C"
#endif
#endif // #ifndef HAMMER_INTERNAL__H