From 103c4d93af7e5e84f0406f1ea25ee5f0e7ffd723 Mon Sep 17 00:00:00 2001
From: picomeg <megordon5@gmail.com>
Date: Fri, 14 Feb 2020 08:04:02 +0000
Subject: [PATCH] add several combinators that are more recent than the old JNI
 this update started from.

---
 src/bindings/jni/Example.java                 |  14 ++
 .../com/upstandinghackers/hammer/Hammer.java  |   9 +
 .../jni/com_upstandinghackers_hammer_Hammer.c | 185 +++++++++++++++++-
 3 files changed, 207 insertions(+), 1 deletion(-)

diff --git a/src/bindings/jni/Example.java b/src/bindings/jni/Example.java
index 4e6d7682..52f89e27 100644
--- a/src/bindings/jni/Example.java
+++ b/src/bindings/jni/Example.java
@@ -84,6 +84,20 @@ public static void main(String args[])
     Parser i3parsers[] = {Hammer.ch((byte)'i'), Hammer.uInt8(), Hammer.int8()};
     handle(Hammer.parse(Hammer.sequence(Hammer.ch((byte)'i'), Hammer.uInt8(), Hammer.int8()), i3, i3.length));
 
+    out("permutation");
+    byte ch3[] = {(byte) 'a', (byte) 'b', (byte) 'c'};
+    handle(Hammer.parse(Hammer.permutation(Hammer.ch((byte)'a'), Hammer.ch((byte)'b'), Hammer.ch((byte)'c')), ch3, ch3.length));
+    handle(Hammer.parse(Hammer.permutation(Hammer.ch((byte)'b'), Hammer.ch((byte)'a'), Hammer.ch((byte)'c')), ch3, ch3.length));
+    
+    out("skip");
+    byte ch6[] = {(byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f'};
+    handle(Hammer.parse(Hammer.sequence(Hammer.ch((byte)'a'), Hammer.skip((int)32), Hammer.ch((byte)'f')), ch6, ch6.length));
+    
+    out("seek");
+    final int SEEK_SET = 0;	/* Seek from beginning of file.  */
+    //final int SEEK_CUR = 1;	/* Seek from current position.  */
+    //final int SEEK_END = 2;	/* Seek from end of file.  */
+    handle(Hammer.parse(Hammer.sequence(Hammer.ch((byte)'a'), Hammer.seek((int)40, (int)SEEK_SET), Hammer.ch((byte)'f')), ch6, ch6.length));
     
 }
 
diff --git a/src/bindings/jni/com/upstandinghackers/hammer/Hammer.java b/src/bindings/jni/com/upstandinghackers/hammer/Hammer.java
index 3e06a91e..66ec1b5f 100644
--- a/src/bindings/jni/com/upstandinghackers/hammer/Hammer.java
+++ b/src/bindings/jni/com/upstandinghackers/hammer/Hammer.java
@@ -53,10 +53,12 @@ public class Hammer
     public static native Parser middle(Parser p, Parser x, Parser q);
 //    public static native Parser action(Parser p, Action a);
     public static native Parser in(byte[] charset, int length);
+    public static native Parser notIn(byte[] charset, int length);
     public static native Parser endP();
     public static native Parser nothingP();
     public static native Parser sequence(Parser... parsers);
     public static native Parser choice(Parser... parsers);
+    public static native Parser permutation(Parser... parsers);
     public static native Parser butNot(Parser p1, Parser p2);
     public static native Parser difference(Parser p1, Parser p2);
     public static native Parser xor(Parser p1, Parser p2);
@@ -73,4 +75,11 @@ public class Hammer
     public static native Parser and(Parser p);
     public static native Parser not(Parser p);
     public static native Parser indirect();
+//    public static native Parser bindIndirect(Parser indirect, Parser inner);
+    public static native Parser withEndianess(byte endianess, Parser p);
+//    public static native Parser bind(Parser p, HContinuation k, void *env); //would need to work out mappings
+    public static native Parser skip(int n);
+    public static native Parser seek(int n, int whence); //TODO double check mapping for int whence
+    public static native Parser tell();
+    
 }
diff --git a/src/bindings/jni/com_upstandinghackers_hammer_Hammer.c b/src/bindings/jni/com_upstandinghackers_hammer_Hammer.c
index f83414bc..b42a0dfa 100644
--- a/src/bindings/jni/com_upstandinghackers_hammer_Hammer.c
+++ b/src/bindings/jni/com_upstandinghackers_hammer_Hammer.c
@@ -149,6 +149,13 @@ JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_middle
     RETURNWRAP(env, h_middle(UNWRAP(env, p), UNWRAP(env, x), UNWRAP(env, q)));
 }
 
+/**
+ * Given another parser, p, and a function f, returns a parser that
+ * applies p, then applies f to everything in the AST of p's result.
+ *
+ * Result token type: any
+ */
+//HAMMER_FN_DECL(HParser*, h_action, const HParser* p, const HAction a, void* user_data);
 
 JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_in
   (JNIEnv *env, jclass class, jbyteArray charset, jint length)
@@ -157,6 +164,13 @@ JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_in
 }
 
 
+JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_notIn
+  (JNIEnv *env, jclass class, jbyteArray charset, jint length)
+{
+    RETURNWRAP(env, h_not_in((uint8_t*) ((*env)->GetByteArrayElements(env, charset, NULL)), (size_t)length));
+}
+
+
 JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_endP
   (JNIEnv *env, jclass class)
 {
@@ -226,6 +240,57 @@ JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_choice
     RETURNWRAP(env, result);
 }
 
+/**
+ * Given a null-terminated list of parsers, match a permutation phrase of these
+ * parsers, i.e. match all parsers exactly once in any order.
+ *
+ * If multiple orders would match, the lexically smallest permutation is used;
+ * in other words, at any step the remaining available parsers are tried in
+ * the order in which they appear in the arguments.
+ *
+ * As an exception, 'h_optional' parsers (actually those that return a result
+ * of token type TT_NONE) are detected and the algorithm will try to match them
+ * with a non-empty result. Specifically, a result of TT_NONE is treated as a
+ * non-match as long as any other argument matches.
+ *
+ * Other parsers that succeed on any input (e.g. h_many), that match the same
+ * input as others, or that match input which is a prefix of another match can
+ * lead to unexpected results and should probably not be used as arguments.
+ *
+ * The result is a sequence of the same length as the argument list.
+ * Each parser's result is placed at that parser's index in the arguments.
+ * The permutation itself (the order in which the arguments were matched) is
+ * not returned.
+ *
+ * Result token type: TT_SEQUENCE
+ */
+//HAMMER_FN_DECL_VARARGS_ATTR(H_GCC_ATTRIBUTE((sentinel)), HParser*, h_permutation, HParser* p);
+JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_permutation
+  (JNIEnv *env, jclass class, jobjectArray permutation)
+{
+    jsize length;
+    void **parsers;
+    int i;
+    jobject current;
+    const HParser *result;
+
+    length = (*env)->GetArrayLength(env, permutation);
+    parsers = malloc(sizeof(HParser *)*(length+1));
+    if(NULL==parsers)
+    {
+        return NULL;
+    }
+
+    for(i=0; i<length; i++)
+    {
+        current = (*env)->GetObjectArrayElement(env, permutation, (jsize)i);
+        parsers[i] = UNWRAP(env, current);
+    }
+    parsers[length] = NULL;
+
+    result = h_permutation__a(parsers);
+    RETURNWRAP(env, result);
+}
 
 JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_butNot
   (JNIEnv *env, jclass class, jobject p, jobject q)
@@ -310,6 +375,21 @@ JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_lengthValue
     RETURNWRAP(env, h_length_value(UNWRAP(env, length), UNWRAP(env, value)));
 }
 
+/**
+ * This parser attaches a predicate function, which returns true or
+ * false, to a parser. The function is evaluated over the parser's
+ * result.
+ *
+ * The parse only succeeds if the attribute function returns true.
+ *
+ * attr_bool will check whether p's result exists and whether p's
+ * result AST exists; you do not need to check for this in your
+ * predicate function.
+ *
+ * Result token type: p's result type if pred succeeded, NULL otherwise.
+ */
+//HAMMER_FN_DECL(HParser*, h_attr_bool, const HParser* p, HPredicate pred, void* user_data);
+
 
 JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_and
   (JNIEnv *env, jclass class, jobject p)
@@ -332,4 +412,107 @@ JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_indirect
 }
 
 
-
+/**
+ * Set the inner parser of an indirect. See comments on indirect for
+ * details.
+ */
+//HAMMER_FN_DECL(void, h_bind_indirect, HParser* indirect, const HParser* inner);
+//JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_bind_indirect
+//  (JNIEnv *env, jclass class, jobject indirect, jobject inner)
+//{
+//    RETURNWRAP(env, h_bind_indirect(UNWRAP(env, indirect), UNWRAP(env, inner)));
+//}
+
+
+/**
+ * This parser runs its argument parser with the given endianness setting.
+ *
+ * The value of 'endianness' should be a bit-wise or of the constants
+ * BYTE_BIG_ENDIAN/BYTE_LITTLE_ENDIAN and BIT_BIG_ENDIAN/BIT_LITTLE_ENDIAN.
+ *
+ * Result token type: p's result type.
+ */
+//HAMMER_FN_DECL(HParser*, h_with_endianness, char endianness, const HParser* p);
+JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_with_endianness
+  (JNIEnv *env, jclass class, jbyte endianess, jobject p)
+{
+    RETURNWRAP(env, h_with_endianness((char) endianess, UNWRAP(env, p)));
+}
+
+
+/**
+ * The 'h_put_value' combinator stashes the result of the parser
+ * it wraps in a symbol table in the parse state, so that non-
+ * local actions and predicates can access this value.
+ *
+ * Try not to use this combinator if you can avoid it.
+ *
+ * Result token type: p's token type if name was not already in
+ * the symbol table. It is an error, and thus a NULL result (and
+ * parse failure), to attempt to rename a symbol.
+ */
+//HAMMER_FN_DECL(HParser*, h_put_value, const HParser *p, const char* name);
+
+/**
+ * The 'h_get_value' combinator retrieves a named HParseResult that
+ * was previously stashed in the parse state.
+ *
+ * Try not to use this combinator if you can avoid it.
+ *
+ * Result token type: whatever the stashed HParseResult is, if
+ * present. If absent, NULL (and thus parse failure).
+ */
+//HAMMER_FN_DECL(HParser*, h_get_value, const char* name);
+
+/**
+ * Monadic bind for HParsers, i.e.:
+ * Sequencing where later parsers may depend on the result(s) of earlier ones.
+ *
+ * Run p and call the result x. Then run k(env,x).  Fail if p fails or if
+ * k(env,x) fails or if k(env,x) is NULL.
+ *
+ * Result: the result of k(x,env).
+ */
+//HAMMER_FN_DECL(HParser*, h_bind, const HParser *p, HContinuation k, void *env);
+
+/**
+ * This parser skips 'n' bits of input.
+ *
+ * Result: None. The HParseResult exists but its AST is NULL.
+ */
+//HAMMER_FN_DECL(HParser*, h_skip, size_t n);
+JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_skip
+  (JNIEnv *env, jclass class, jint n)
+{
+    RETURNWRAP(env, h_skip((size_t) n));
+}
+
+/**
+ * The HParser equivalent of fseek(), 'h_seek' modifies the parser's input
+ * position.  Note that contrary to 'fseek', offsets are in bits, not bytes.
+ * The 'whence' argument uses the same values and semantics: SEEK_SET,
+ * SEEK_CUR, SEEK_END.
+ *
+ * Fails if the new input position would be negative or past the end of input.
+ *
+ * Result: TT_UINT. The new input position.
+ */
+//HAMMER_FN_DECL(HParser*, h_seek, ssize_t offset, int whence);
+//TODO double check mapping for int
+JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_seek
+  (JNIEnv *env, jclass class, jint offset, jint whence)
+{
+    RETURNWRAP(env, h_seek((ssize_t) offset, (int) whence));
+}
+
+/**
+ * Report the current position in bits. Consumes no input.
+ *
+ * Result: TT_UINT. The current input position.
+ */
+//HAMMER_FN_DECL_NOARG(HParser*, h_tell);
+JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_tell
+  (JNIEnv *env, jclass class)
+{
+    RETURNWRAP(env, h_tell());
+}
-- 
GitLab