From bda2fb4741ef8a0bde5c54c1e9869f319e8f2b4c Mon Sep 17 00:00:00 2001
From: TQ Hirsch <thequux@upstandinghackers.com>
Date: Thu, 16 Jan 2014 09:38:55 -0500
Subject: [PATCH] Added start at C++ bindings

---
 src/bindings/cpp/SConscript             |   9 ++
 src/bindings/cpp/cpp_tests.cpp          |  23 ++++
 src/bindings/cpp/hammer/hammer.cpp      |   1 +
 src/bindings/cpp/hammer/hammer.hpp      | 160 ++++++++++++++++++++++++
 src/bindings/cpp/hammer/hammer_test.hpp |  46 +++++++
 5 files changed, 239 insertions(+)
 create mode 100644 src/bindings/cpp/SConscript
 create mode 100644 src/bindings/cpp/cpp_tests.cpp
 create mode 100644 src/bindings/cpp/hammer/hammer.cpp
 create mode 100644 src/bindings/cpp/hammer/hammer.hpp
 create mode 100644 src/bindings/cpp/hammer/hammer_test.hpp

diff --git a/src/bindings/cpp/SConscript b/src/bindings/cpp/SConscript
new file mode 100644
index 00000000..448c3929
--- /dev/null
+++ b/src/bindings/cpp/SConscript
@@ -0,0 +1,9 @@
+# -*- python -*-
+Import("env libhammer_shared")
+
+cppenv = env.Clone()
+cppenv.Append(INCPATH=["."])
+
+
+libhammerxx = env.SharedLibrary("hammer++", libhammer_shared + ["hammer.cpp"])
+
diff --git a/src/bindings/cpp/cpp_tests.cpp b/src/bindings/cpp/cpp_tests.cpp
new file mode 100644
index 00000000..b8eda68f
--- /dev/null
+++ b/src/bindings/cpp/cpp_tests.cpp
@@ -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();
+}
diff --git a/src/bindings/cpp/hammer/hammer.cpp b/src/bindings/cpp/hammer/hammer.cpp
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/src/bindings/cpp/hammer/hammer.cpp
@@ -0,0 +1 @@
+
diff --git a/src/bindings/cpp/hammer/hammer.hpp b/src/bindings/cpp/hammer/hammer.hpp
new file mode 100644
index 00000000..61622eea
--- /dev/null
+++ b/src/bindings/cpp/hammer/hammer.hpp
@@ -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
diff --git a/src/bindings/cpp/hammer/hammer_test.hpp b/src/bindings/cpp/hammer/hammer_test.hpp
new file mode 100644
index 00000000..aa9b9940
--- /dev/null
+++ b/src/bindings/cpp/hammer/hammer_test.hpp
@@ -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)
-- 
GitLab