diff --git a/Makefile b/Makefile index bd383a22ff5a0768bd2fd7cb3c2a36baada49630..a70cc406ac287e7e0f677e11b58289d07d4ca5ea 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ # and kick off a recursive make # Also, "make src/all" turns into "make -C src all" -SUBDIRS = src examples +SUBDIRS = src examples jni include config.mk diff --git a/common.mk b/common.mk index a57429db48e76179ff7d2537d78ef73d8b80dec2..0259d5fb0a04930bcdda2c06c8b5459f63e3c388 100644 --- a/common.mk +++ b/common.mk @@ -8,7 +8,7 @@ include $(TOPLEVEL)/config.mk TEST_CFLAGS = $(shell pkg-config --cflags glib-2.0) -DINCLUDE_TESTS TEST_LDFLAGS = $(shell pkg-config --libs glib-2.0) -CFLAGS := -std=gnu99 -Wall -Wextra -Werror -Wno-unused-parameter -Wno-attributes +CFLAGS := -std=gnu99 -Wall -Wextra -Werror -Wno-unused-parameter -Wno-attributes -g LDFLAGS := CC ?= gcc diff --git a/jni/Example.java b/jni/Example.java index 5871d798248eff8beb40c07a3dd1d5a4072b1486..8cfa72428f2c3d7ae4f92d8625b467aebeaacc33 100644 --- a/jni/Example.java +++ b/jni/Example.java @@ -1,38 +1,18 @@ +import com.upstandinghackers.hammer.*; +import java.util.Arrays; /** * Example JHammer usage */ + public class Example { -private HParser initParser() -{ - HParser digit = Hammer.chRange(0x30, 0x39); - HParser alpha = Hammer.choice({Hammer.chRange(0x41, 0x5a), Hammer.chRange(0x61, 0x7a)}); - - HParser plus = Hammer.ch('+'); - HParser slash = Hammer.ch('/'); - HParser equals = Hammer.ch('='); - HParser bsfdig = Hammer.choice({alpha, digit, plus, slash}); - - byte[] AEIMQUYcgkosw048 = "AEIMQUYcgkosw048".getBytes(); - HParser bsfdig_4bit = Hammer.in(AEIMQUYcgkosw048, AEIMQUYcgkosw048.length); - byte[] AQgw = "AQgw".getBytes(); - HParser bsfdig_2bit = Hammer.in(AQgw, AQgw.length); - HParser base64_3 = Hammer.repeatN(bsfdig, 4); - HParser base64_2 = Hammer.sequence({bsfdig, bsfdig, bsfdig_4bit, equals}); - HParser base64_1 = Hammer.sequence({bsfdig, bsfdig_2bit, equals, equals}); - HParser base64 = Hammer.sequence({ Hammer.many(base64_3), - Hammer.optional(Hammer.choice({base64_2, base64_1})) - }); - - return Hammer.sequence({Hammer.whitespace(base64), Hammer.whitespace(Hammer.endP()}}); +static { + System.loadLibrary("jhammer"); } -public static void main(String args[]) +private static void handle(ParseResult result) { - byte[] input = "RXMgaXN0IFNwYXJnZWx6ZWl0IQo=".getBytes(); - int length = input.length; - HParsedResult result = Hammer.parse(initParser(), input, length); if(result == null) { System.out.println("FAIL"); @@ -40,10 +20,73 @@ public static void main(String args[]) else { System.out.println("PASS"); - //TODO: Pretty print + handleToken(result.getAst()); + } +} + +private static void handleToken(ParsedToken p) +{ + if(p==null) + { + System.out.println("Empty AST"); + return; + } + switch(p.getTokenType()) + { + case NONE: out("NONE token type"); break; + case BYTES: out("BYTES token type, value: " + Arrays.toString(p.getBytesValue())); break; + case SINT: out("SINT token type, value: " + p.getSIntValue()); break; + case UINT: out("UINT token type, value: " + p.getUIntValue()); break; + case SEQUENCE: out("SEQUENCE token type"); for(ParsedToken tok : p.getSeqValue()) {handleToken(tok);} break; + case ERR: out("ERR token type"); break; + case USER: out("USER token type"); break; } } +private static void out(String msg) +{ + System.out.println(">> " + msg); +} + +public static void main(String args[]) +{ + out("chRange"); + handle(Hammer.parse(Hammer.chRange((byte)0x30, (byte)0x39), "1".getBytes(), 1)); + handle(Hammer.parse(Hammer.chRange((byte)0x30, (byte)0x39), "a".getBytes(), 1)); + + out("ch"); + handle(Hammer.parse(Hammer.ch((byte)0x31), "1".getBytes(), 1)); + handle(Hammer.parse(Hammer.ch((byte)0x31), "0".getBytes(), 1)); + + out("token"); + handle(Hammer.parse(Hammer.token("herp".getBytes(), 4), "herp".getBytes(), 4)); + handle(Hammer.parse(Hammer.token("herp".getBytes(), 4), "derp".getBytes(), 4)); + + out("intRange"); + byte inbytes[] = {0x31, 0x31, 0x31, 0x31}; + handle(Hammer.parse(Hammer.intRange(Hammer.uInt8(), 0L, 0x32), inbytes, inbytes.length)); + handle(Hammer.parse(Hammer.intRange(Hammer.uInt8(), 0L, 0x30), inbytes, inbytes.length)); + + out("bits"); + handle(Hammer.parse(Hammer.bits(7, false), inbytes, inbytes.length)); + + out("int64"); + byte ints[] = {(byte)0x8F, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF}; + handle(Hammer.parse(Hammer.int64(), ints, ints.length)); + handle(Hammer.parse(Hammer.int64(), inbytes, inbytes.length)); + + out("choice"); + Parser two32s[] = {Hammer.intRange(Hammer.uInt32(), 0x00, 0x01), Hammer.int32()}; + handle(Hammer.parse(Hammer.choice(two32s), ints, ints.length)); + + out("sequence"); + byte i3[] = {(byte)'i', (byte)3, (byte)0xFF}; + Parser i3parsers[] = {Hammer.ch((byte)'i'), Hammer.uInt8(), Hammer.int8()}; + handle(Hammer.parse(Hammer.sequence(i3parsers), i3, i3.length)); + + +} + } diff --git a/jni/Makefile b/jni/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..85be973388223c6b9332c0d72a54f8a283e2c899 --- /dev/null +++ b/jni/Makefile @@ -0,0 +1,42 @@ +JSOURCES := Action.java Hammer.java ParsedToken.java ParseResult.java Parser.java Predicate.java +JSOURCES_NATIVE := Hammer ParsedToken Parser ParseResult +CSOURCES := com_upstandinghackers_hammer_Hammer.c com_upstandinghackers_hammer_ParsedToken.c com_upstandinghackers_hammer_Parser.c com_upstandinghackers_hammer_ParseResult.c + +# ls *.h *.o *.so com/upstandinghackers/hammer/*.class | grep -v jhammer.h | tr '\n' ' '; replace single $ with $$ +OUTPUTS := com/upstandinghackers/hammer/Action.class com/upstandinghackers/hammer/Hammer.class com_upstandinghackers_hammer_Hammer.h com_upstandinghackers_hammer_Hammer.o com/upstandinghackers/hammer/Hammer\$TokenType.class com_upstandinghackers_hammer_Hammer_TokenType.h com/upstandinghackers/hammer/ParsedToken.class com_upstandinghackers_hammer_ParsedToken.h com_upstandinghackers_hammer_ParsedToken.o com/upstandinghackers/hammer/Parser.class com/upstandinghackers/hammer/ParseResult.class com_upstandinghackers_hammer_ParseResult.h com_upstandinghackers_hammer_ParseResult.o com_upstandinghackers_hammer_Parser.h com_upstandinghackers_hammer_Parser.o com/upstandinghackers/hammer/Predicate.class libjhammer.so + +TOPLEVEL := ../ + +JC=javac +JH=javah +CP=com/upstandinghackers/hammer +PACKAGE=com.upstandinghackers.hammer + +include ../common.mk + +JNI_INCLUDE := /usr/lib/jvm/java-6-openjdk/include/ +CFLAGS += -fPIC -I. -I $(TOPLEVEL)/src/ -I jni -I $(JNI_INCLUDE) + +%.java: $(call ifsilent,| $(HUSH)) + $(call hush, "Compiling Java source $@") $(JC) $(CP)/$@ + +all: javacc prepare compile link + +link: compile + $(call hush, "Generating libjhammer.so") $(CC) -shared $(CFLAGS) -o libjhammer.so *.o ../src/*.o ../src/backends/*.o ../src/parsers/*.o + +$(CSOURCES): prepare + $(call hush, "Compiling $@") $(CC) -c $(CFLAGS) $@ + +compile: prepare $(CSOURCES) + +prepare: javacc $(JSOURCES_NATIVE) + +$(JSOURCES_NATIVE): javacc + $(call hush, "Generating JNI headers for $@") $(JH) $(PACKAGE).$@ + +javacc: $(JSOURCES) + +#TODO make this not-as-hardcoded +#clean: +# rm $(CP)/*.class && rm com_upstandinghackers_*.h && rm com_upstandinghackers_*.o && rm libjhammer.so diff --git a/jni/NOTES b/jni/NOTES index 2e6e5bb2775a2d67fda59ab164ff77106b3423f0..564b3f5af43db8859e42a52878e8637a206a6f64 100644 --- a/jni/NOTES +++ b/jni/NOTES @@ -1,12 +1,26 @@ -Compilation: -javac com/upstandinghackers/hammer/*.java +USING THE JNI BINDINGS: +1. import com.upstandinghackers.hammer.*; +2. Add a static initializer block that loads the correct library, like this: static { System.loadLibrary("jhammer"); } +3. Code stuff. Just look at Example.java for a few handy snippets (for walking the resulting syntax tree [AST] etc) +4. Compile your java sources like always +5. Add the folder containing libhammer.so/dll/whatever to Java's library path to run it, for example: java -Djava.library.path=. <CLASS> -Conversion to JNI headers: -find -name "*.class" | sed -e 's/.class$//' | tr '/' '.' | cut -c 3- | xargs javah - -Not working: -enums aren't converted at all, no idea why +UNIMPLEMENTED: +User-defined types, predicates and actions are unimplemented. +Memory leaks because there is no reliable garbage collection. TODO: -Implement the entire JNI side Testing + + +TYPE MAPPING: +Hammer Java JNI +uint8_t byte jbyte jbyte/byte is signed +char byte jbyte jchar would be 16 bit wide +size_t int jint signed as well; jsize == jint, actually +int64_t long jlong +uint64_t long jlong signed! +bool boolean jboolean JNI_TRUE / JNI_FALSE +float float jfloat +double double jdouble +void void void diff --git a/jni/com/upstandinghackers/hammer/Action.java b/jni/com/upstandinghackers/hammer/Action.java new file mode 100644 index 0000000000000000000000000000000000000000..aecb713e44148f02aa76a1555b9d0a77bc608e21 --- /dev/null +++ b/jni/com/upstandinghackers/hammer/Action.java @@ -0,0 +1,8 @@ +package com.upstandinghackers.hammer; + +import java.util.List; + +public interface Action +{ + public List<ParsedToken> execute(ParseResult p); +} diff --git a/jni/com/upstandinghackers/hammer/HAction.java b/jni/com/upstandinghackers/hammer/HAction.java deleted file mode 100644 index 09aeaaff7f4cc0344facfd002a3152e63eb137ff..0000000000000000000000000000000000000000 --- a/jni/com/upstandinghackers/hammer/HAction.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.upstandinghackers.hammer; - -import java.util.List; - -public interface HAction -{ - public List<HParsedToken> execute(HParseResult p); -} diff --git a/jni/com/upstandinghackers/hammer/HParseResult.java b/jni/com/upstandinghackers/hammer/HParseResult.java deleted file mode 100644 index ed5c85beb11b374bca28a1541a06044ea5f43277..0000000000000000000000000000000000000000 --- a/jni/com/upstandinghackers/hammer/HParseResult.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.upstandinghackers.hammer; - -import java.util.List; - -public class HParseResult -{ - public native List<HParsedToken> getAst(); - public native long getBitLength(); -} diff --git a/jni/com/upstandinghackers/hammer/HParsedToken.java b/jni/com/upstandinghackers/hammer/HParsedToken.java deleted file mode 100644 index d8a70d6a670ae96ebe974f3c235f509f63933a51..0000000000000000000000000000000000000000 --- a/jni/com/upstandinghackers/hammer/HParsedToken.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.upstandinghackers.hammer; - -import java.util.List; - -public class HParsedToken -{ - public native Hammer.HTokenType getTokenType(); - public native int getIndex(); - public native byte getBitOffset(); - public native byte[] getBytesValue(); - public native long getSIntValue(); - public native long getUIntValue(); - public native double getDoubleValue(); - public native float getFloatValue(); - public native List<HParsedToken> getSeqValue(); - public native Object getUserValue(); - - native void setTokenType(Hammer.HTokenType type); - native void setIndex(int index); - native void setBitOffset(byte offset); - native void setBytesValue(byte[] value); - native void setSIntValue(long value); - native void setUIntValue(long value); - native void setDoubleValue(double value); - native void setFloatValue(float value); - native void setSeqValue(List<HParsedToken> value); - native void setUserValue(Object value); -} diff --git a/jni/com/upstandinghackers/hammer/HParser.java b/jni/com/upstandinghackers/hammer/HParser.java deleted file mode 100644 index 9f2387aadceb3f7a0751f2f8e143196ee83a4974..0000000000000000000000000000000000000000 --- a/jni/com/upstandinghackers/hammer/HParser.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.upstandinghackers.hammer; - -public class HParser -{ - public native void bindIndirect(HParser inner); -} diff --git a/jni/com/upstandinghackers/hammer/HPredicate.java b/jni/com/upstandinghackers/hammer/HPredicate.java deleted file mode 100644 index 9c87875e2f1544472e8b80368fcd461eb22b1f99..0000000000000000000000000000000000000000 --- a/jni/com/upstandinghackers/hammer/HPredicate.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.upstandinghackers.hammer; - -public interface HPredicate -{ - public boolean apply(HParseResult p); -} diff --git a/jni/com/upstandinghackers/hammer/Hammer.java b/jni/com/upstandinghackers/hammer/Hammer.java index e7ad571b9b19d9a26aab1dba26d28a79b7e79792..cd252d9dbdcfb361aab5ffbdbcb9b21c61a04e26 100644 --- a/jni/com/upstandinghackers/hammer/Hammer.java +++ b/jni/com/upstandinghackers/hammer/Hammer.java @@ -1,4 +1,5 @@ package com.upstandinghackers.hammer; +import java.util.HashMap; public class Hammer { @@ -7,59 +8,69 @@ public class Hammer public final static byte BYTE_LITTLE_ENDIAN = 0x0; public final static byte BIT_LITTLE_ENDIAN = 0x0; - public enum HTokenType + static final HashMap<Integer, TokenType> tokenTypeMap = new HashMap<Integer, TokenType>(); + + public enum TokenType { - TT_NONE(1), - TT_BYTES(2), - TT_SINT(4), - TT_UINT(8), - TT_SEQUENCE(16), - TT_ERR(32), - TT_USER(64), + NONE(1), + BYTES(2), + SINT(4), + UINT(8), + SEQUENCE(16), + ERR(32), + USER(64); private int value; public int getValue() { return this.value; } - private HTokenType(int value) { this.value = value; } + private TokenType(int value) { this.value = value; } + } + + static + { + for(TokenType tt : TokenType.values()) + { + Hammer.tokenTypeMap.put(new Integer(tt.getValue()), tt); + } } - public static native HParseResult parse(HParser parser, byte[] input, int length); - public static native HParser token(byte[] str, int length); - public static native HParser ch(byte c); - public static native HParser chRange(byte from, byte to); - public static native HParser intRange(HParser p, int lower, int upper); - public static native HParser bits(int len, boolean sign); - public static native HParser int64(); - public static native HParser int32(); - public static native HParser int16(); - public static native HParser int8(); - public static native HParser uInt64(); - public static native HParser uInt32(); - public static native HParser uInt16(); - public static native HParser uInt8(); - public static native HParser whitespace(HParser p); - public static native HParser left(HParser p, HParser q); - public static native HParser right(HParser p, HParser q); - public static native HParser middle(HParser p, HParser x, HParser q); - public static native HParser action(HParser p, HAction a); - public static native HParser in(byte[] charset, int length); - public static native HParser endP(); - public static native HParser nothingP(); - public static native HParser sequence(HParser[] parsers); - public static native HParser choice(HParser[] parsers); - public static native HParser butNot(HParser p1, HParser p2); - public static native HParser difference(HParser p1, HParser p2); - public static native HParser xor(HParser p1, HParser p2); - public static native HParser many(HParser p); - public static native HParser many1(HParser p); - public static native HParser repeatN(HParser p, int n); - public static native HParser optional(HParser p); - public static native HParser ignore(HParser p); - public static native HParser sepBy(HParser p, HParser sep); - public static native HParser sepBy1(HParser p, HParser sep); - public static native HParser epsilonP(); - public static native HParser lengthValue(HParser length, HParser value); - public static native HParser attrBool(HParser p, HPredicate pred); - public static native HParser and(HParser p); - public static native HParser not(HParser p); - public static native HParser indirect(); + public static native ParseResult parse(Parser parser, byte[] input, int length); + public static native Parser token(byte[] str, int length); + public static native Parser ch(byte c); + public static native Parser chRange(byte from, byte to); + public static native Parser intRange(Parser p, long lower, long upper); + public static native Parser bits(int len, boolean sign); + public static native Parser int64(); + public static native Parser int32(); + public static native Parser int16(); + public static native Parser int8(); + public static native Parser uInt64(); + public static native Parser uInt32(); + public static native Parser uInt16(); + public static native Parser uInt8(); + public static native Parser whitespace(Parser p); + public static native Parser left(Parser p, Parser q); + public static native Parser right(Parser p, Parser q); + 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 endP(); + public static native Parser nothingP(); + public static native Parser sequence(Parser[] parsers); + public static native Parser choice(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); + public static native Parser many(Parser p); + public static native Parser many1(Parser p); + public static native Parser repeatN(Parser p, int n); + public static native Parser optional(Parser p); + public static native Parser ignore(Parser p); + public static native Parser sepBy(Parser p, Parser sep); + public static native Parser sepBy1(Parser p, Parser sep); + public static native Parser epsilonP(); + public static native Parser lengthValue(Parser length, Parser value); +// public static native Parser attrBool(Parser p, Predicate pred); + public static native Parser and(Parser p); + public static native Parser not(Parser p); + public static native Parser indirect(); } diff --git a/jni/com/upstandinghackers/hammer/ParseResult.java b/jni/com/upstandinghackers/hammer/ParseResult.java new file mode 100644 index 0000000000000000000000000000000000000000..e5ad6c94182e9c70aedcbb8fe81445cae12614c5 --- /dev/null +++ b/jni/com/upstandinghackers/hammer/ParseResult.java @@ -0,0 +1,15 @@ +package com.upstandinghackers.hammer; + +import java.util.List; + +public class ParseResult +{ + public native ParsedToken getAst(); + public native long getBitLength(); + + public native void free(); + public long getInner() {return this.inner;} + + private long inner; + ParseResult(long inner) {this.inner=inner;} +} diff --git a/jni/com/upstandinghackers/hammer/ParsedToken.java b/jni/com/upstandinghackers/hammer/ParsedToken.java new file mode 100644 index 0000000000000000000000000000000000000000..efbc8ed7a388b0940e45fb00574f14ea9bc621c0 --- /dev/null +++ b/jni/com/upstandinghackers/hammer/ParsedToken.java @@ -0,0 +1,40 @@ +package com.upstandinghackers.hammer; + +public class ParsedToken +{ + public Hammer.TokenType getTokenType() + { + int tt = this.getTokenTypeInternal(); + if(0==tt) + return null; + return Hammer.tokenTypeMap.get(new Integer(tt)); + } + + private native int getTokenTypeInternal(); + public native int getIndex(); + public native byte getBitOffset(); + public native byte[] getBytesValue(); + public native long getSIntValue(); + public native long getUIntValue(); + public native double getDoubleValue(); + public native float getFloatValue(); + public native ParsedToken[] getSeqValue(); +// public native Object getUserValue(); + + native void setTokenType(Hammer.TokenType type); + native void setIndex(int index); + native void setBitOffset(byte offset); + native void setBytesValue(byte[] value); + native void setSIntValue(long value); + native void setUIntValue(long value); + native void setDoubleValue(double value); + native void setFloatValue(float value); + native void setSeqValue(ParsedToken value[]); +// native void setUserValue(Object value); + +// public native void free(); + public long getInner() {return this.inner;} + + private long inner; + ParsedToken(long inner) {this.inner=inner;} +} diff --git a/jni/com/upstandinghackers/hammer/Parser.java b/jni/com/upstandinghackers/hammer/Parser.java new file mode 100644 index 0000000000000000000000000000000000000000..2e924cb2ba26a6b21d777deb1bc076f9e7ec1eac --- /dev/null +++ b/jni/com/upstandinghackers/hammer/Parser.java @@ -0,0 +1,11 @@ +package com.upstandinghackers.hammer; + +public class Parser +{ + public native void bindIndirect(Parser inner); + public native void free(); + public long getInner() {return this.inner;} + + private long inner; + Parser(long inner) {this.inner=inner;} +} diff --git a/jni/com/upstandinghackers/hammer/Predicate.java b/jni/com/upstandinghackers/hammer/Predicate.java new file mode 100644 index 0000000000000000000000000000000000000000..52ca4bf7b94569906a072a73587a75b95550a1f4 --- /dev/null +++ b/jni/com/upstandinghackers/hammer/Predicate.java @@ -0,0 +1,6 @@ +package com.upstandinghackers.hammer; + +public interface Predicate +{ + public boolean apply(ParseResult p); +} diff --git a/jni/com_upstandinghackers_hammer_Hammer.c b/jni/com_upstandinghackers_hammer_Hammer.c new file mode 100644 index 0000000000000000000000000000000000000000..f83414bc8bd9c443a338e16300f4eb3bd3637d37 --- /dev/null +++ b/jni/com_upstandinghackers_hammer_Hammer.c @@ -0,0 +1,335 @@ +#include "jhammer.h" +#include "com_upstandinghackers_hammer_Hammer.h" +#include <stdlib.h> + +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_parse + (JNIEnv *env, jclass class, jobject obj, jbyteArray input_, jint length_) +{ + HParser *parser; + uint8_t* input; + size_t length; + HParseResult *result; + jclass resultClass; + jobject retVal; + + parser = UNWRAP(env, obj); + + input = (uint8_t *) ((*env)->GetByteArrayElements(env, input_, NULL)); + length = (size_t) length_; + + result = h_parse(parser, input, length); + + if(result==NULL) + return NULL; + + FIND_CLASS(resultClass, env, "com/upstandinghackers/hammer/ParseResult"); + + NEW_INSTANCE(retVal, env, resultClass, result); + + return retVal; +} + +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_token + (JNIEnv *env, jclass class, jbyteArray str, jint len) +{ + RETURNWRAP(env, h_token((uint8_t *) ((*env)->GetByteArrayElements(env, str, NULL)), (size_t) len)); +} + +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_ch + (JNIEnv *env, jclass class, jbyte c) +{ + RETURNWRAP(env, h_ch((uint8_t) c)); +} + + +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_chRange + (JNIEnv *env, jclass class, jbyte lower, jbyte upper) +{ + + RETURNWRAP(env, h_ch_range((uint8_t) lower, (uint8_t) upper)); +} + + +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_intRange + (JNIEnv *env, jclass class, jobject obj, jlong lower, jlong upper) +{ + HParser *parser; + parser = UNWRAP(env, obj); + RETURNWRAP(env, h_int_range(parser, (int64_t) lower, (int64_t) upper)); +} + + +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_bits + (JNIEnv *env, jclass class, jint len, jboolean sign) +{ + RETURNWRAP(env, h_bits((size_t) len, (bool)(sign & JNI_TRUE))); +} + + +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_int64 + (JNIEnv *env, jclass class) +{ + RETURNWRAP(env, h_int64()); +} + + +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_int32 + (JNIEnv *env, jclass class) +{ + RETURNWRAP(env, h_int32()); +} + + +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_int16 + (JNIEnv *env, jclass class) +{ + RETURNWRAP(env, h_int16()); +} + + +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_int8 + (JNIEnv *env, jclass class) +{ + RETURNWRAP(env, h_int8()); +} + + +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_uInt64 + (JNIEnv *env, jclass class) +{ + RETURNWRAP(env, h_uint64()); +} + + +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_uInt32 + (JNIEnv *env, jclass class) +{ + RETURNWRAP(env, h_uint32()); +} + + +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_uInt16 + (JNIEnv *env, jclass class) +{ + RETURNWRAP(env, h_uint16()); +} + + +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_uInt8 + (JNIEnv *env, jclass class) +{ + RETURNWRAP(env, h_uint8()); +} + + +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_whitespace + (JNIEnv *env, jclass class, jobject parser) +{ + RETURNWRAP(env, h_whitespace(UNWRAP(env, parser))); +} + + +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_left + (JNIEnv *env, jclass class, jobject p, jobject q) +{ + RETURNWRAP(env, h_left(UNWRAP(env, p), UNWRAP(env, q))); +} + + +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_right + (JNIEnv *env, jclass class, jobject p, jobject q) +{ + RETURNWRAP(env, h_right(UNWRAP(env, p), UNWRAP(env, q))); +} + + +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_middle + (JNIEnv *env, jclass class, jobject p, jobject x, jobject q) +{ + RETURNWRAP(env, h_middle(UNWRAP(env, p), UNWRAP(env, x), UNWRAP(env, q))); +} + + +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_in + (JNIEnv *env, jclass class, jbyteArray charset, jint length) +{ + RETURNWRAP(env, h_in((uint8_t *) ((*env)->GetByteArrayElements(env, charset, NULL)), (size_t)length)); +} + + +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_endP + (JNIEnv *env, jclass class) +{ + RETURNWRAP(env, h_end_p()); +} + + +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_nothingP + (JNIEnv *env, jclass class) +{ + RETURNWRAP(env, h_nothing_p()); +} + + +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_sequence + (JNIEnv *env, jclass class, jobjectArray sequence) +{ + jsize length; + void **parsers; + int i; + jobject current; + const HParser *result; + + length = (*env)->GetArrayLength(env, sequence); + parsers = malloc(sizeof(void *)*(length+1)); + if(NULL==parsers) + { + return NULL; + } + + for(i=0; i<length; i++) + { + current = (*env)->GetObjectArrayElement(env, sequence, (jsize)i); + parsers[i] = UNWRAP(env, current); + } + parsers[length] = NULL; + + result = h_sequence__a(parsers); + RETURNWRAP(env, result); +} + + +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_choice + (JNIEnv *env, jclass class, jobjectArray choices) +{ + jsize length; + void **parsers; + int i; + jobject current; + const HParser *result; + + length = (*env)->GetArrayLength(env, choices); + parsers = malloc(sizeof(HParser *)*(length+1)); + if(NULL==parsers) + { + return NULL; + } + + for(i=0; i<length; i++) + { + current = (*env)->GetObjectArrayElement(env, choices, (jsize)i); + parsers[i] = UNWRAP(env, current); + } + parsers[length] = NULL; + + result = h_choice__a(parsers); + RETURNWRAP(env, result); +} + + +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_butNot + (JNIEnv *env, jclass class, jobject p, jobject q) +{ + RETURNWRAP(env, h_butnot(UNWRAP(env, p), UNWRAP(env, q))); +} + + +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_difference + (JNIEnv *env, jclass class, jobject p, jobject q) +{ + RETURNWRAP(env, h_difference(UNWRAP(env, p), UNWRAP(env, q))); +} + + +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_xor + (JNIEnv *env, jclass class, jobject p, jobject q) +{ + RETURNWRAP(env, h_xor(UNWRAP(env, p), UNWRAP(env, q))); +} + + +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_many + (JNIEnv *env, jclass class, jobject p) +{ + RETURNWRAP(env, h_many(UNWRAP(env, p))); +} + + +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_many1 + (JNIEnv *env, jclass class, jobject p) +{ + RETURNWRAP(env, h_many1(UNWRAP(env, p))); +} + + +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_repeatN + (JNIEnv *env, jclass class, jobject p, jint n) +{ + RETURNWRAP(env, h_repeat_n(UNWRAP(env, p), (size_t)n)); +} + + +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_optional + (JNIEnv *env, jclass class, jobject p) +{ + RETURNWRAP(env, h_optional(UNWRAP(env, p))); +} + + +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_ignore + (JNIEnv *env, jclass class, jobject p) +{ + RETURNWRAP(env, h_ignore(UNWRAP(env, p))); +} + + +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_sepBy + (JNIEnv *env, jclass class, jobject p, jobject sep) +{ + RETURNWRAP(env, h_sepBy(UNWRAP(env, p), UNWRAP(env, sep))); +} + + +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_sepBy1 + (JNIEnv *env, jclass class, jobject p, jobject sep) +{ + RETURNWRAP(env, h_sepBy1(UNWRAP(env, p), UNWRAP(env, sep))); +} + + +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_epsilonP + (JNIEnv *env, jclass class) +{ + RETURNWRAP(env, h_epsilon_p()); +} + + +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_lengthValue + (JNIEnv *env, jclass class, jobject length, jobject value) +{ + RETURNWRAP(env, h_length_value(UNWRAP(env, length), UNWRAP(env, value))); +} + + +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_and + (JNIEnv *env, jclass class, jobject p) +{ + RETURNWRAP(env, h_and(UNWRAP(env, p))); +} + + +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_not + (JNIEnv *env, jclass class, jobject p) +{ + RETURNWRAP(env, h_not(UNWRAP(env, p))); +} + + +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_indirect + (JNIEnv *env, jclass class) +{ + RETURNWRAP(env, h_indirect()); +} + + + diff --git a/jni/com_upstandinghackers_hammer_ParseResult.c b/jni/com_upstandinghackers_hammer_ParseResult.c new file mode 100644 index 0000000000000000000000000000000000000000..ad45fe3a6d9ce238fae7c05d2c999ad7cc1ae19e --- /dev/null +++ b/jni/com_upstandinghackers_hammer_ParseResult.c @@ -0,0 +1,45 @@ +#include "jhammer.h" +#include "com_upstandinghackers_hammer_ParseResult.h" + +HParseResult *unwrap_parse_result(JNIEnv *env, jobject obj) +{ + jclass parseResultClass; + jfieldID parseResultInner; + FIND_CLASS(parseResultClass, env, "com/upstandinghackers/hammer/ParseResult"); + parseResultInner = (*env)->GetFieldID(env, parseResultClass, "inner", "J"); + return (HParseResult *)((*env)->GetLongField(env, obj, parseResultInner)); +} + + +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_ParseResult_getAst + (JNIEnv *env, jobject this) +{ + HParseResult *inner; + jclass parsedTokenClass; + jobject retVal; + + if(this == NULL) + return NULL; // parse unsuccessful + inner = unwrap_parse_result(env, this); + if(inner->ast == NULL) + return NULL; // parse successful, but empty + + FIND_CLASS(parsedTokenClass, env, "com/upstandinghackers/hammer/ParsedToken"); + NEW_INSTANCE(retVal, env, parsedTokenClass, inner->ast); + return retVal; + +} + +JNIEXPORT jlong JNICALL Java_com_upstandinghackers_hammer_ParseResult_getBitLength + (JNIEnv *env, jobject this) +{ + HParseResult *inner = unwrap_parse_result(env, this); + return (jlong) (inner->bit_length); +} + +JNIEXPORT void JNICALL Java_com_upstandinghackers_hammer_ParseResult_free + (JNIEnv *env, jobject this) +{ + //XXX: NOT IMPLEMENTED +} + diff --git a/jni/com_upstandinghackers_hammer_ParsedToken.c b/jni/com_upstandinghackers_hammer_ParsedToken.c new file mode 100644 index 0000000000000000000000000000000000000000..e863738a4b80f9c281ec907b86153a25fee99980 --- /dev/null +++ b/jni/com_upstandinghackers_hammer_ParsedToken.c @@ -0,0 +1,195 @@ +#include "jhammer.h" +#include "com_upstandinghackers_hammer_ParsedToken.h" + +#define HPT_UNWRAP(env, this) HParsedToken *inner = unwrap_parsed_token(env, this); assert(inner!=NULL) + +HParsedToken *unwrap_parsed_token(JNIEnv *env, jobject obj) +{ + jclass parsedTokenClass; + jfieldID parsedTokenInner; + FIND_CLASS(parsedTokenClass, env, "com/upstandinghackers/hammer/ParsedToken"); + parsedTokenInner = (*env)->GetFieldID(env, parsedTokenClass, "inner", "J"); + return (HParsedToken *)((*env)->GetLongField(env, obj, parsedTokenInner)); +} + + +JNIEXPORT jint JNICALL Java_com_upstandinghackers_hammer_ParsedToken_getTokenTypeInternal + (JNIEnv *env, jobject this) +{ + HPT_UNWRAP(env, this); + if(inner==NULL) + return (jint)0; + return (jint)(inner->token_type); +} + +JNIEXPORT jint JNICALL Java_com_upstandinghackers_hammer_ParsedToken_getIndex + (JNIEnv *env, jobject this) +{ + HPT_UNWRAP(env, this); + return (jint) (inner->index); +} + +JNIEXPORT jbyte JNICALL Java_com_upstandinghackers_hammer_ParsedToken_getBitOffset + (JNIEnv *env, jobject this) +{ + HPT_UNWRAP(env, this); + return (jbyte) (inner->bit_offset); +} + +JNIEXPORT jbyteArray JNICALL Java_com_upstandinghackers_hammer_ParsedToken_getBytesValue + (JNIEnv *env, jobject this) +{ + jbyteArray outArray; + HPT_UNWRAP(env, this); + outArray = (*env)->NewByteArray(env, (jsize)inner->bytes.len); + (*env)->SetByteArrayRegion(env, outArray, (jsize) 0, (jsize)(inner->bytes.len), (jbyte *)(inner->bytes.token)); + return outArray; +} + +JNIEXPORT jlong JNICALL Java_com_upstandinghackers_hammer_ParsedToken_getSIntValue + (JNIEnv *env, jobject this) +{ + HPT_UNWRAP(env, this); + return (jlong) (inner->sint); +} + +JNIEXPORT jlong JNICALL Java_com_upstandinghackers_hammer_ParsedToken_getUIntValue + (JNIEnv *env, jobject this) +{ + HPT_UNWRAP(env, this); + return (jlong) (inner->uint); +} + +JNIEXPORT jdouble JNICALL Java_com_upstandinghackers_hammer_ParsedToken_getDoubleValue + (JNIEnv *env, jobject this) +{ + HPT_UNWRAP(env, this); + return (jdouble) (inner->dbl); +} + +JNIEXPORT jfloat JNICALL Java_com_upstandinghackers_hammer_ParsedToken_getFloatValue + (JNIEnv *env, jobject this) +{ + HPT_UNWRAP(env, this); + return (jfloat) (inner->flt); +} + +JNIEXPORT jobjectArray JNICALL Java_com_upstandinghackers_hammer_ParsedToken_getSeqValue + (JNIEnv *env, jobject this) +{ + jsize i; + HPT_UNWRAP(env, this); + jsize returnSize = inner->seq->used; + jobject currentObject; + jclass returnClass; + FIND_CLASS(returnClass, env, "com/upstandinghackers/hammer/ParsedToken"); + jobjectArray retVal = (*env)->NewObjectArray(env, returnSize, returnClass, NULL); + for(i = 0; i<returnSize; i++) + { + NEW_INSTANCE(currentObject, env, returnClass, inner->seq->elements[i]); + (*env)->SetObjectArrayElement(env, retVal, i, currentObject); + } + return retVal; +} + +JNIEXPORT void JNICALL Java_com_upstandinghackers_hammer_ParsedToken_setTokenType + (JNIEnv *env, jobject this, jobject tokenType) +{ + jclass tokenTypeClass; + jmethodID getValue; + jint typeVal; + HPT_UNWRAP(env, this); + + FIND_CLASS(tokenTypeClass, env, "com/upstandinghackers/hammer/Hammer$TokenType"); + getValue = (*env)->GetMethodID(env, tokenTypeClass, "getValue", "()I"); + typeVal = (*env)->CallIntMethod(env, tokenType, getValue); + + inner->token_type = (int32_t) typeVal; // unsafe cast, but enums should be of type int +} + +JNIEXPORT void JNICALL Java_com_upstandinghackers_hammer_ParsedToken_setIndex + (JNIEnv *env, jobject this, jint index) +{ + HPT_UNWRAP(env, this); + inner->index = (size_t)index; +} + +JNIEXPORT void JNICALL Java_com_upstandinghackers_hammer_ParsedToken_setBitOffset + (JNIEnv *env, jobject this, jbyte bit_offset) +{ + HPT_UNWRAP(env, this); + inner->bit_offset = (char)bit_offset; +} + +JNIEXPORT void JNICALL Java_com_upstandinghackers_hammer_ParsedToken_setBytesValue + (JNIEnv *env, jobject this, jbyteArray bytes_) +{ + HBytes bytes; + HPT_UNWRAP(env, this); + + bytes.token = (uint8_t *) ((*env)->GetByteArrayElements(env, bytes_, NULL)); + bytes.len = (size_t) (*env)->GetArrayLength(env, bytes_); + + inner->bytes = bytes; + inner->token_type = TT_BYTES; +} + +JNIEXPORT void JNICALL Java_com_upstandinghackers_hammer_ParsedToken_setSIntValue + (JNIEnv *env, jobject this, jlong sint) +{ + HPT_UNWRAP(env, this); + inner->token_type = TT_SINT; + inner->sint = (int64_t)sint; +} + +JNIEXPORT void JNICALL Java_com_upstandinghackers_hammer_ParsedToken_setUIntValue + (JNIEnv *env, jobject this, jlong uint) +{ + HPT_UNWRAP(env, this); + inner->token_type = TT_UINT; + inner->uint = (uint64_t)uint; +} + +JNIEXPORT void JNICALL Java_com_upstandinghackers_hammer_ParsedToken_setDoubleValue + (JNIEnv *env, jobject this, jdouble dbl) +{ + HPT_UNWRAP(env, this); + //token_type? + inner->dbl = (double)dbl; +} + +JNIEXPORT void JNICALL Java_com_upstandinghackers_hammer_ParsedToken_setFloatValue + (JNIEnv *env, jobject this, jfloat flt) +{ + HPT_UNWRAP(env, this); + //token_type? + inner->flt = (float)flt; +} + +JNIEXPORT void JNICALL Java_com_upstandinghackers_hammer_ParsedToken_setSeqValue + (JNIEnv *env, jobject this, jobjectArray values) +{ + HArena *arena; + size_t len, i; + jobject currentValue; + HParsedToken *currentValueInner; + HCountedArray *seq; + HPT_UNWRAP(env, this); + len = (size_t) (*env)->GetArrayLength(env, values); + arena = h_new_arena(&system_allocator, 0); + seq = h_carray_new_sized(arena, len); + + // unwrap each value and append it to the new HCountedArray + for(i = 0; i<len; i++) + { + currentValue = (*env)->GetObjectArrayElement(env, values, (jsize)i); + if(NULL == currentValue) + continue; + currentValueInner = unwrap_parsed_token(env, currentValue); + if(currentValueInner) + h_carray_append(seq, (void *)currentValueInner); + } + + inner->token_type = TT_SEQUENCE; + inner->seq = seq; +} diff --git a/jni/com_upstandinghackers_hammer_Parser.c b/jni/com_upstandinghackers_hammer_Parser.c new file mode 100644 index 0000000000000000000000000000000000000000..4e95e23455b6733ef74d0fdacb9731def2264b02 --- /dev/null +++ b/jni/com_upstandinghackers_hammer_Parser.c @@ -0,0 +1,15 @@ +#include "jhammer.h" +#include "com_upstandinghackers_hammer_Parser.h" + +JNIEXPORT void JNICALL Java_com_upstandinghackers_hammer_Parser_bindIndirect + (JNIEnv *env, jobject this, jobject parser) +{ + h_bind_indirect(UNWRAP(env, this), UNWRAP(env, parser)); +} + +JNIEXPORT void JNICALL Java_com_upstandinghackers_hammer_Parser_free + (JNIEnv *env, jobject this) +{ + //XXX NOT IMPLEMENTED + //h_free(UNWRAP(env, this)); +} diff --git a/jni/jhammer.h b/jni/jhammer.h new file mode 100644 index 0000000000000000000000000000000000000000..077777b723ec09867d30472d5da586a5c6aa9425 --- /dev/null +++ b/jni/jhammer.h @@ -0,0 +1,31 @@ +#ifndef JHAMMER_H +#define JHAMMER_H +#include <jni.h> +#include "internal.h" +#include <assert.h> + +// Unsafe (non-asserting) helpers +#define FIND_CLASS_(env, class) (*env)->FindClass(env, class) +#define REFCONSTRUCTOR_(env, class) (*env)->GetMethodID(env, class, "<init>", "(J)V") +#define NEW_INSTANCE_(env, class, inner) (*env)->NewObject(env, class, REFCONSTRUCTOR_(env, class), (jlong)inner) + +// Safer versions, assert that the result is not NULL +// If one of those asserts fails, it most likely means that there's a typo (wrong class name or method signature) or big trouble (OOM) +#define FIND_CLASS(target, env, class) target = FIND_CLASS_(env, class); assert(target != NULL) +#define REFCONSTRUCTOR(target, env, class) target = REFCONSTRUCTOR_(env, class); assert(target != NULL) +#define NEW_INSTANCE(target, env, class, inner) target = NEW_INSTANCE_(env, class, inner); assert(target != NULL) + + +// Since there's a LOT of wrapping/unwrapping HParsers, these macros make it a bit more readable +#define PARSER_CLASS "com/upstandinghackers/hammer/Parser" +#define PARSER_REF(env) (*env)->GetFieldID(env, FIND_CLASS_(env, PARSER_CLASS), "inner", "J") + +#define RETURNWRAP(env, inner) jclass __cls=FIND_CLASS_(env, PARSER_CLASS); \ + assert(__cls != NULL); \ + jmethodID __constructor = REFCONSTRUCTOR_(env, __cls); \ + assert(__constructor != NULL); \ + return (*env)->NewObject(env, __cls, __constructor, (jlong)inner) + +#define UNWRAP(env, object) (HParser *)((*env)->GetLongField(env, object, PARSER_REF(env))) + +#endif diff --git a/src/Makefile b/src/Makefile index ead051682b2203bf0aeb18e7d7c9f04cdef23311..18d3c3f8cd748ea6289a95be07a53ca019aad71c 100644 --- a/src/Makefile +++ b/src/Makefile @@ -62,6 +62,8 @@ include ../common.mk $(TESTS): CFLAGS += $(TEST_CFLAGS) $(TESTS): LDFLAGS += $(TEST_LDFLAGS) +CFLAGS += -fPIC + all: libhammer.a libhammer.a: $(HAMMER_PARTS) diff --git a/src/hammer.h b/src/hammer.h index d1e86884eb7e85752df074bf4c65f16819f2ab90..31bc021a7a388d90e9bbca36dac8a9785bd7ffa7 100644 --- a/src/hammer.h +++ b/src/hammer.h @@ -167,14 +167,18 @@ typedef struct HBenchmarkResults_ { rtype_t name(__VA_ARGS__, ...); \ rtype_t name##__m(HAllocator* mm__, __VA_ARGS__, ...); \ rtype_t name##__mv(HAllocator* mm__, __VA_ARGS__, va_list ap); \ - rtype_t name##__v(__VA_ARGS__, va_list ap) + rtype_t name##__v(__VA_ARGS__, va_list ap); \ + rtype_t name##__a(void *args[]); \ + rtype_t name##__ma(HAllocator *mm__, void *args[]) // Note: this drops the attributes on the floor for the __v versions #define HAMMER_FN_DECL_VARARGS_ATTR(attr, rtype_t, name, ...) \ rtype_t name(__VA_ARGS__, ...) attr; \ rtype_t name##__m(HAllocator* mm__, __VA_ARGS__, ...) attr; \ rtype_t name##__mv(HAllocator* mm__, __VA_ARGS__, va_list ap); \ - rtype_t name##__v(__VA_ARGS__, va_list ap) + rtype_t name##__v(__VA_ARGS__, va_list ap); \ + rtype_t name##__a(void *args[]); \ + rtype_t name##__ma(HAllocator *mm__, void *args[]) // }}} diff --git a/src/parsers/choice.c b/src/parsers/choice.c index 73dedde6cdb1b7c8ff3f2d036b52e1ce9e8b9d3a..6ea7c5e09b8d94922ac2b2a48fe15a2cea773d09 100644 --- a/src/parsers/choice.c +++ b/src/parsers/choice.c @@ -72,3 +72,27 @@ const HParser* h_choice__mv(HAllocator* mm__, const HParser* p, va_list ap_) { return ret; } +const HParser* h_choice__a(void *args[]) { + return h_choice__ma(&system_allocator, args); +} + +const HParser* h_choice__ma(HAllocator* mm__, void *args[]) { + size_t len = -1; // because do...while + const HParser *arg; + + do { + arg=((HParser **)args)[++len]; + } while(arg); + + HSequence *s = h_new(HSequence, 1); + s->p_array = h_new(const HParser *, len); + + for (size_t i = 0; i < len; i++) { + s->p_array[i] = ((HParser **)args)[i]; + } + + s->len = len; + HParser *ret = h_new(HParser, 1); + ret->vtable = &choice_vt; ret->env = (void*)s; + return ret; +} diff --git a/src/parsers/sequence.c b/src/parsers/sequence.c index 21ae31d959c8cdab9a323a0f63667654d5813bba..564cd1425edf495da84f9d17ff2c38fe8520df47 100644 --- a/src/parsers/sequence.c +++ b/src/parsers/sequence.c @@ -73,3 +73,28 @@ const HParser* h_sequence__mv(HAllocator* mm__, const HParser *p, va_list ap_) { ret->vtable = &sequence_vt; ret->env = (void*)s; return ret; } + +const HParser* h_sequence__a(void *args[]) { + return h_sequence__ma(&system_allocator, args); +} + +const HParser* h_sequence__ma(HAllocator* mm__, void *args[]) { + size_t len = -1; // because do...while + const HParser *arg; + + do { + arg=((HParser **)args)[++len]; + } while(arg); + + HSequence *s = h_new(HSequence, 1); + s->p_array = h_new(const HParser *, len); + + for (size_t i = 0; i < len; i++) { + s->p_array[i] = ((HParser **)args)[i]; + } + + s->len = len; + HParser *ret = h_new(HParser, 1); + ret->vtable = &sequence_vt; ret->env = (void*)s; + return ret; +}