diff --git a/.gitignore b/.gitignore index dc459a3210b50406a6481e3208af3dbb3ee200a3..f1c5785fc48fd53c40be0884e98e02d53f3218c3 100644 --- a/.gitignore +++ b/.gitignore @@ -57,3 +57,10 @@ doc/tech_report.bbl doc/tech_report.log doc/tech_report.pdf doc/tech_report.fdb_latexmk +examples/user_types/encoded_data_c +examples/user_types/encoded_data_j +examples/user_types/example_decoder +examples/user_types/example_encoder +doc/tech_report.fls +examples/dynamic/encoded_data +examples/dynamic/gen diff --git a/compiler/2014/C_CodeGen.jrag b/compiler/2014/C_CodeGen.jrag index b7aae053368fb4659ec23e4d363b7bdf52c083d9..bc9d7626628554a1826c98e8a383f36dad4deadc 100644 --- a/compiler/2014/C_CodeGen.jrag +++ b/compiler/2014/C_CodeGen.jrag @@ -1130,11 +1130,39 @@ aspect C_Encoder { " not declared"); } + protected void Decl.C_emitEncoderTypeRegister(C_env env) { + env.println("int labcomm"+env.verStr+"_encoder_type_register_" + + env.prefix + getName() + "("); + env.indent(); + env.println("struct labcomm"+env.verStr+"_encoder *e"); + env.unindent(); + env.println(")"); + env.println("{"); + env.indent(); + env.println("//TODO: add error handling for dependencies"); + + C_emitUserTypeDeps(env, null, true); + + if(!isSampleDecl() || hasDependencies()) { + env.println("return labcomm"+env.verStr+"_internal_encoder_type_register("); + env.indent(); + env.println("e,"); + env.println("&signature_" + env.prefix + getName() + ""); + env.unindent(); + env.println(");"); + } else { + env.println("// the type has no dependencies, do nothing"); + env.println("return 0;"); + } + env.unindent(); + env.println("}"); + } public void TypeDecl.C_emitEncoderRegisterHandler(C_env env) { - // do nothing for type decls + C_emitEncoderTypeRegister(env); } public void SampleDecl.C_emitEncoderRegisterHandler(C_env env) { + C_emitEncoderTypeRegister(env); env.println("int labcomm"+env.verStr+"_encoder_register_" + env.prefix + getName() + "("); env.indent(); @@ -1146,17 +1174,28 @@ aspect C_Encoder { C_emitUserTypeDeps(env, null, false); //XXX HERE BE DRAGONS //currently set to false to turn off //outputting of code - env.println("return labcomm"+env.verStr+"_internal_encoder_register("); + env.println("int result = labcomm"+env.verStr+"_internal_encoder_register("); env.indent(); env.println("e,"); env.println("&signature_" + env.prefix + getName() + ","); env.println("(labcomm"+env.verStr+"_encoder_function)encode_" + env.prefix + getName()); env.unindent(); env.println(");"); + env.println("if(result >= 0) {\n"); + env.indent(); + env.println("labcomm"+env.verStr+"_encoder_type_register_" + env.prefix + getName()+"(e);"); + env.println("labcomm"+env.verStr+"_internal_encoder_type_bind("); + env.indent(); + env.println("e,"); + env.println("&signature_" + env.prefix + getName() + ","); + env.println( (hasDependencies() ? "1" : "0") + ");"); + env.unindent(); + env.println("}"); + env.unindent(); + env.println("return result;"); env.unindent(); env.println("}"); } - } aspect C_EncoderIoctl { @@ -1206,7 +1245,7 @@ aspect C_TypeDependencies { t.C_emitUserTypeDeps(env, t.getName(), outputCode); if(outputCode) { System.out.println("Decl.C_emitUserTypeDeps registering "+t.getName()); - env.println("labcomm"+env.verStr+"_encoder_register_"+env.prefix + t.getName()+"(e);"); + env.println("labcomm"+env.verStr+"_encoder_type_register_"+env.prefix + t.getName()+"(e);"); } else { // Just output a comment String refpath = (via == null) ? "directly" : "indirectly via "+via; env.println(" //Depends ("+refpath+") on "+t.getName() ); @@ -1222,7 +1261,7 @@ aspect C_TypeDependencies { t.C_emitUserTypeRefs(env, t.getName(), outputCode); if(outputCode) { - env.println("labcomm"+env.verStr+"_encoder_register_"+env.prefix + t.getName()+"(e);"); + env.println("labcomm"+env.verStr+"_encoder_type_register_"+env.prefix + t.getName()+"(e);"); } else { // Just output a comment String refpath = (via == null) ? "directly" : "indirectly via "+via; env.println(" //Is referenced ("+refpath+") by "+t.getName() ); @@ -1245,14 +1284,15 @@ aspect C_Signature { eq TypeDecl.C_DeclTypeString() = "LABCOMM_TYPEDEF"; public void Decl.C_emitSignature(C_env env) { - C_emitFlatSignature(env); -// -// if( false && (isReferenced() || isSampleDecl())){ -// Signature signature = getSignature(); -// signature.C_emitSignature(env, !isSampleDecl()); -// } else { -// env.println("// not emitting signature for "+getName()+isReferenced()+isSampleDecl()); -// } + if( (isReferenced() || isSampleDecl())){ + Signature signature = getSignature(); + signature.C_emitSignature(env, !isSampleDecl()); + } else { + env.println("// not emitting signature for "+getName()+isReferenced()+isSampleDecl()); + } + C_emitFlatSignature(env); + + // if(env.versionHasMetaData()) { // if(isReferenced() || isSampleDecl()){ // env.println("(int (*)(void *))labcomm"+env.verStr+"_signature_" + @@ -1274,6 +1314,24 @@ aspect C_Signature { } public void Decl.C_emitFlatSignature(C_env env) { + C_emitSizeofValue(env); + env.println("static struct labcomm"+env.verStr+"_signature " + + "signature_" + env.prefix + getName() + " = {"); + env.indent(); + env.println("\"" + getName() + "\","); + //env.println("sizeof_" + env.prefix + getName() + ","); + //HERE BE DRAGONS? do we need sizeof for typedefs? + env.println("NULL,"); + env.println("0,"); + env.println("NULL,"); + env.println("0,"); // index + env.println("sizeof(signature_tree_" + env.prefix + getName() + "),"); + env.println("signature_tree_" + env.prefix + getName() + ""); + env.unindent(); + env.println(" };"); + env.println("const struct labcomm"+env.verStr+"_signature " + + "*labcomm"+env.verStr+"_signature_" + env.prefix + getName() + + " = &signature_" + env.prefix + getName() + ";"); } public void SampleDecl.C_emitFlatSignature(C_env env){ @@ -1304,7 +1362,9 @@ aspect C_Signature { env.println("sizeof_" + env.prefix + getName() + ","); env.println("sizeof(signature_bytes_" + env.prefix + getName() + "),"); env.println("signature_bytes_" + env.prefix + getName() + ","); - env.println("0"); + env.println("0,"); // index + env.println("sizeof(signature_tree_" + env.prefix + getName() + "),"); + env.println("signature_tree_" + env.prefix + getName() + ""); env.unindent(); env.println(" };"); env.println("const struct labcomm"+env.verStr+"_signature " + @@ -1319,28 +1379,29 @@ aspect C_Signature { public abstract void SignatureLine.C_emitSignature(C_env env, boolean decl); public void TypeRefSignatureLine.C_emitSignature(C_env env, boolean isDecl){ - //env.print(getIndentString()); - //env.println("LABCOMM_SIGDEF_SIGNATURE(labcomm"+env.verStr+"_signature_" + env.prefix + decl.getName() +"),"); + env.print(getIndentString()); + // env.println("LABCOMM_SIGDEF_SIGNATURE(labcomm"+env.verStr+"_signature_" + env.prefix + decl.getName() +"),"); + env.println("LABCOMM_SIGDEF_SIGNATURE(signature_" + env.prefix + decl.getName() +"),"); } public void DataSignatureLine.C_emitSignature(C_env env, boolean decl){ - // String comment = getComment(); - // if (comment != null && comment.length() > 0) { - // env.println(getIndentString() + "// " + comment); - // } - // byte[] data = getData(env.version); - // if (data != null && data.length > 0) { - // env.print(getIndentString()); - // env.print("LABCOMM_SIGDEF_BYTES("+data.length+", \""); - // for (int j = 0 ; j < data.length ; j++) { - // byte d = data[j]; - // //if(d>='a'&&d<='z' || d>='A'&&d<='Z'|| d>='0'&&d<='9' ) - // // env.print(""+(char)d); - // //else - // env.print("\\x"+Integer.toHexString(d)); - // } - // env.println("\"),"); - // } + String comment = getComment(); + if (comment != null && comment.length() > 0) { + env.println(getIndentString() + "// " + comment); + } + byte[] data = getData(env.version); + if (data != null && data.length > 0) { + env.print(getIndentString()); + env.print("LABCOMM_SIGDEF_BYTES("+data.length+", \""); + for (int j = 0 ; j < data.length ; j++) { + byte d = data[j]; + //if(d>='a'&&d<='z' || d>='A'&&d<='Z'|| d>='0'&&d<='9' ) + // env.print(""+(char)d); + //else + env.print("\\x"+Integer.toHexString(d)); + } + env.println("\"),"); + } } // // @@ -1357,18 +1418,18 @@ aspect C_Signature { // //} public void SignatureList.C_emitSignature(C_env env, boolean decl) { -// env.println("static struct labcomm_signature_data signature_tree_" + -// env.prefix + parentDecl().getName() + "[] = {"); -// env.indent(); -// for (int i = 0 ; i < size() ; i++) { -// SignatureLine l = getSignatureLine(i); -// l.C_emitSignature(env, decl); -// } -// -// env.println("LABCOMM_SIGDEF_END"); -// env.println("};"); -// env.unindent(); -// env.println(); + env.println("static struct labcomm_signature_data signature_tree_" + + env.prefix + parentDecl().getName() + "[] = {"); + env.indent(); + for (int i = 0 ; i < size() ; i++) { + SignatureLine l = getSignatureLine(i); + l.C_emitSignature(env, decl); + } + + env.println("LABCOMM_SIGDEF_END"); + env.println("};"); + env.unindent(); + env.println(); } @@ -1432,9 +1493,9 @@ aspect C_Constructor { } public void Decl.C_emitConstructor(C_env env) { - } +// } //XXX - public void SampleDecl.C_emitConstructor(C_env env) { +// public void SampleDecl.C_emitConstructor(C_env env) { env.println("labcomm"+env.verStr+"_set_local_index(&signature_" + env.prefix + getName() + ");"); } diff --git a/compiler/2014/FlatSignature.jrag b/compiler/2014/FlatSignature.jrag index 2a9ca4dd9c48fadfabceecebf215e808d10e0597..b96c119ce386f0a0d2b7e9e2c1edb001050e5f27 100644 --- a/compiler/2014/FlatSignature.jrag +++ b/compiler/2014/FlatSignature.jrag @@ -21,9 +21,9 @@ aspect FlatSignature { getType().flatSignature(list); } - public void SampleRefType.flatSignature(SignatureList list) { - list.addInt(LABCOMM_SAMPLE_REF, "sample"); - } +// public void SampleRefType.flatSignature(SignatureList list) { +// list.addInt(LABCOMM_SAMPLE_REF, "sample"); +// } public void VoidType.flatSignature(SignatureList list) { list.addInt(LABCOMM_STRUCT, "void"); @@ -96,9 +96,9 @@ aspect FlatSignature { return getType().signatureComment() + " '" + getName() +"'"; } - public String SampleRefType.signatureComment() { - return "sample"; - } +// public String SampleRefType.signatureComment() { +// return "sample"; +// } public String PrimType.signatureComment() { return getName(); diff --git a/compiler/2014/Java_CodeGen.jrag b/compiler/2014/Java_CodeGen.jrag index 478a0ac4222f5cebdff8af2168197784e79543d8..62a59eff2b4d6db81c899e25dfbc817121f70aaa 100644 --- a/compiler/2014/Java_CodeGen.jrag +++ b/compiler/2014/Java_CodeGen.jrag @@ -454,10 +454,10 @@ aspect Java_Class { env.println(); } - //public void TypeDecl.Java_emitSignature(Java_env env) { - // Signature signature = getSignature(); - // signature.Java_emitSignature(env, true); - //} + public void TypeDecl.Java_emitSignature(Java_env env) { + Signature signature = getSignature(); + signature.Java_emitSignature(env, true); + } public void Decl.Java_emitSignature(Java_env env) { //always emit the flat signature, as it is needed @@ -465,10 +465,10 @@ aspect Java_Class { //the type_ids of dependent types. Therefore, flat sigs //are used for matching Java_emitFlatSignature(env); - //if(isReferenced() || isSampleDecl()){ - // Signature signature = getSignature(); - // signature.Java_emitSignature(env, !isSampleDecl()); - //} + if(isReferenced() || (isSampleDecl() && hasDependencies() )){ + Signature signature = getSignature(); + signature.Java_emitSignature(env, !isSampleDecl()); + } } public void Decl.Java_emitFlatSignature(Java_env env){ @@ -497,7 +497,8 @@ aspect Java_Class { //XXX TODO: refactor: split into a static class ("TypeDefSingleton"?)and a (smaller) dispatcher public void Decl.Java_emitDispatcher(Java_env env, boolean isSample) { - String genericStr = ""; //env.versionHasMetaData()?"<"+getName()+">":""; + // String genericStr = ""; //env.versionHasMetaData()?"<"+getName()+">":""; + String genericStr = "<"+getName()+">"; env.println("private static Dispatcher dispatcher = new Dispatcher();"); env.println(); env.println("public SampleDispatcher getDispatcher() {"); @@ -544,16 +545,20 @@ aspect Java_Class { env.println("return "+isSample+";"); env.unindent(); env.println("}"); -// env.println("public boolean hasStaticSignature() {"); -// env.indent(); -// env.println("return "+!hasDependencies()+";"); -// env.unindent(); -// env.println("}"); + env.println("public boolean hasDependencies() {"); + env.indent(); + env.println("return "+hasDependencies()+";"); + env.unindent(); + env.println("}"); env.println(); env.println("/** return the flat signature. */"); env.println("public byte[] getSignature() {"); env.indent(); - env.println("return signature;"); + if(isSample) { + env.println("return signature;"); + } else { + env.println("throw new Error(\"a TYPE_DEF has no flat signature\");"); + } env.unindent(); env.println("}"); env.println(); @@ -563,15 +568,16 @@ aspect Java_Class { // env.unindent(); // env.println("}"); // env.println(); -// env.println("public void encodeSignatureMetadata(Encoder e, int index) throws IOException{"); -// env.indent(); -// env.println("e.encodePacked32(Constant.TYPE_DEF);"); -// env.println("e.encodePacked32(index);"); -// env.println("e.encodeString(getName());"); -// env.println("emitSignature(e);"); -// env.unindent(); -// env.println("}"); -// env.println(); + env.println("public void encodeTypeDef(Encoder e, int index) throws IOException{"); + env.indent(); + if(!isSample || hasDependencies()) { + env.println("emitSignature(e);"); + } else { + env.println("// the type has no dependencies, do nothing"); + } + env.unindent(); + env.println("}"); + env.println(); env.println("public boolean canDecodeAndHandle() {"); env.indent(); env.println("return "+isSample+";"); diff --git a/compiler/2014/LabComm.ast b/compiler/2014/LabComm.ast index 904cc17eb4fe26462b674394a81df391be9690dd..d3d5e592fc95cb38bf9fd3844d8b3ad2d3cb9081 100644 --- a/compiler/2014/LabComm.ast +++ b/compiler/2014/LabComm.ast @@ -1,39 +1,37 @@ Program ::= Decl*; -//TODO: Add signatures to the abstract grammar, so that -//they can be extended and refined by more than one aspect. -//sketch: -Signature ::= SignatureList FlatSignatureList:SignatureList; -SignatureList ::= SignatureLine*; -abstract SignatureLine ::= <Indent:int> <Comment:String>; -abstract DataSignatureLine : SignatureLine; -ByteArraySignatureLine : DataSignatureLine ::= <Data:byte[]>; -IntSignatureLine : DataSignatureLine ::= <Data:int>; -StringSignatureLine : DataSignatureLine ::= <Data:String>; -TypeRefSignatureLine : SignatureLine ::= Decl; - - -//abstract Decl ::= Type <Name:String>; -// the signature list be defined as a non-terminal attribute: abstract Decl ::= Type <Name:String> /Signature/; -TypeDecl : Decl; + +TypeDecl : Decl; SampleDecl : Decl; +//Signatures are in the abstract grammar, so that +//they can be extended and refined by aspects. + +Signature ::= SignatureList FlatSignatureList:SignatureList; +SignatureList ::= SignatureLine*; +abstract SignatureLine ::= <Indent:int> <Comment:String>; +abstract DataSignatureLine : SignatureLine; +ByteArraySignatureLine : DataSignatureLine ::= <Data:byte[]>; +IntSignatureLine : DataSignatureLine ::= <Data:int>; +StringSignatureLine : DataSignatureLine ::= <Data:String>; +TypeRefSignatureLine : SignatureLine ::= Decl; + Field ::= Type <Name:String>; abstract Type; -VoidType : Type; -SampleRefType : Type; -PrimType : Type ::= <Name:String> <Token:int>; -UserType : Type ::= <Name:String>; -StructType : Type ::= Field*; -ParseArrayType : Type ::= Type Dim*; -abstract ArrayType :Type ::= Type Exp*; -VariableArrayType : ArrayType; -FixedArrayType : ArrayType; +VoidType : Type; +//SampleRefType : Type; +PrimType : Type ::= <Name:String> <Token:int>; +UserType : Type ::= <Name:String>; +StructType : Type ::= Field*; +ParseArrayType : Type ::= Type Dim*; +abstract ArrayType : Type ::= Type Exp*; +VariableArrayType : ArrayType; +FixedArrayType : ArrayType; Dim ::= Exp*; abstract Exp; IntegerLiteral : Exp ::= <Value:String>; -VariableSize : Exp; +VariableSize : Exp; diff --git a/compiler/2014/PrettyPrint.jrag b/compiler/2014/PrettyPrint.jrag index a7fa877109c55e7ad17f64ab1385f8d9638ad662..3808c952309d375c828023c199472d2e6b9e43de 100644 --- a/compiler/2014/PrettyPrint.jrag +++ b/compiler/2014/PrettyPrint.jrag @@ -68,9 +68,9 @@ aspect PrettyPrint { out.print("void"); } - public void SampleRefType.ppPrefix(PrintStream out) { - out.print("sample"); - } +// public void SampleRefType.ppPrefix(PrintStream out) { +// out.print("sample"); +// } public void PrimType.ppPrefix(PrintStream out) { out.print(getName()); diff --git a/compiler/2014/Signature.jrag b/compiler/2014/Signature.jrag index 5395095487bde26c2df7a19b0ea4f452144995d9..b32e53580aa900e31357333904aeeb115180bcf0 100644 --- a/compiler/2014/Signature.jrag +++ b/compiler/2014/Signature.jrag @@ -158,7 +158,6 @@ aspect Signature { } public void TypeDecl.genSigLineForDecl(SignatureList list, boolean decl) { - //System.out.println("************ TypeDecl.genSigLine("+decl+").... for "+getName()); if(decl){ getType().genSigLineForDecl(list, decl); }else{ @@ -167,7 +166,6 @@ aspect Signature { } public void SampleDecl.genSigLineForDecl(SignatureList list, boolean decl) { - //System.out.println("************ SampleDecl.genSigLine("+decl+").... for "+getName()); getType().genSigLineForDecl(list, decl); } @@ -176,25 +174,20 @@ aspect Signature { list.addInt(0, null); } - public void SampleRefType.genSigLineForDecl(SignatureList list, boolean decl) { - list.addInt(LABCOMM_SAMPLE_REF, "sample"); - } +// public void SampleRefType.genSigLineForDecl(SignatureList list, boolean decl) { +// list.addInt(LABCOMM_SAMPLE_REF, "sample"); +// } public void PrimType.genSigLineForDecl(SignatureList list, boolean decl) { list.addInt(getToken(), null); } + /* For UserType, the decl parameter is ignored, as a UserType + * will always be a TypeRef + */ public void UserType.genSigLineForDecl(SignatureList list, boolean decl) { - if(decl){ - //System.out.println("************ UserType.genSigLine("+decl+").... for "+getName()); - TypeDecl thet=lookupType(getName()); - //System.out.println("************ thet: "+thet.getName() +":"+thet.getType()); - thet.genSigLineForDecl(list, decl); - }else{ - //System.out.println("************ UserType.genSigLine("+decl+").... for "+getName()); + TypeDecl thet = lookupType(getName()); - // System.out.println("************ thet: "+thet.getName() +":"+thet.getType()); list.addTypeRef(thet, null); - } } public void ArrayType.genSigLineForDecl(SignatureList list, boolean decl) { diff --git a/doc/tech_report.tex b/doc/tech_report.tex index bb97773e075c356449a1bf874eaf8aa348246703..e0ae1d6df930a48e998c5182c5c00bc34d2f12f6 100644 --- a/doc/tech_report.tex +++ b/doc/tech_report.tex @@ -437,6 +437,11 @@ come from two independent number series. To identify which \verb+TYPE_DECL+ a particular \verb+SAMPLE_DECL+ corresponds to, the \verb+TYPE_BINDING+ packet is used. +For sample types that do not depend on any typedefs, no \verb+TYPE_DECL+ +is sent, and the \verb+TYPE_BINDING+ binds the sample id to the special +value zero to indicate that the type definition is identical to the +flattened signature. + \subsection{Example} The labcomm declaration @@ -484,6 +489,42 @@ not required to do so. However, if multiple \verb+TYPE_DECL+ packets are sent for the same \verb+typedef+, the encoder must use the same \verb+type_id+. +\subsection{Decoding in-band type descriptions} + +In LabComm, the in-band data descriptions are equivalent to \footnote{in +the sense that they contain all information needed to recreate} the data +description source (i.e., the ``.lc-file''). +% +As the type declarations (a.k.a. \emph{signatures}) are written before +sample data on every channel, they can be used to interpret data with +an unknown (by the receiver) format. + +The libraries provide functionality to subscribe to (i.e., register a +\emph{handler} for) sample and type declarations. + +On the low level, the handler receives an instance of the signature +data structure corresponding to the received declaration. + + +For higher-level processing, the Java library provides the +\verb+ASTbuilder+ class, which builds an abstract syntax tree in +the internal representation of the LabComm compiler. +That enables the user to use the complete functionality of the +LabComm compiler, e.g. code generation, on declarations received in a +LabComm stream. + + +In combination with on-the-fly compilation and class-loading (or +linking) that makes it possible to dynamically create handlers for +previously unknown data types. Thereby, it enables dynamic configuration +of LabComm endpoints in static languages without the overhead of +interpreting signatures (at the one-time cost of code generation and +compilation). + + + + + \section{Ideas/Discussion}: @@ -498,6 +539,177 @@ Java primitive types. However, it is unlikely that the entire range is actually way of supporting the common cases is to include run-time checks for overflow in the Java encoders and decoders. +\section{Related work} + +Two in-band self-descibing communication protocols are Apache +Avro\cite{avro} and EDN, the extensible data notation developed for +Clojure and Datomic\cite{EDN}. + +EDN encodes \emph{values} as UTF-8 strings. The documentation says +``edn is a system for the conveyance of values. It is not a type system, +and has no schemas.'' That said, it is \emph{extensible} in the sense +that it has a special \emph{dispatch charachter}, \verb+#+, which can +be used to add a \emph{tag} to a value. A tag indicates a semantic +interpretation of a value, and that allows the reader to support +handlers for specific tags, enabling functionality similar to that of +labcomm. + +\subsection{Apache Avro} + +Apache Avro is similar to LabComm in that it has a textual language +for declaring data, a binary protocol for transmitting data, and code +generation for several languages. + +Avro is a larger system, including RPC \emph{protocols}, support for +using different \emph{codecs} for data compression, and \emph{schema +resolution} to support handling schema evolution and transparent +interoperability between different versions of a schema. + +\subsubsection*{Data types} + +In the table, the Avro type names are listed, and matched to the +corresponding LabComm type: + +\begin{tabular}{|l|c|c|} +\hline + Type & Labcomm & Avro \\ + \hline Primitive types \\ \hline + +int & 4 bytes & varint \\ +long & 8 bytes & varint \\ +float & 4 bytes & 4 bytes \\ +long & 8 bytes & 8 bytes \\ +string & varint + utf8[] & varint + utf8[] \\ +bytes & varint + byte[] & varint + byte[]\\ + + \hline Complex types \\ \hline + +struct/record & concat of fields & concat of fields \\ +arrays & varIdx[] : elements & block[] \\ +map & n/a & block[] \\ +union & n/a & (varint idx) : value \\ +fixed & byte[n] & the number of bytes declared in +the schema\\ +\hline +\end{tabular} + + where + +\begin{verbatim} + block ::= (varint count) : elem[count] [*1] + count == 0 --> no more blocks + + +[*1] for arrays, count == 0 --> end of array + if count < 0, there are |count| elements + preceded by a varint block_size to allow + fast skipping +\end{verbatim} + +In maps, keys are strings, and values according to the schema. + +In unions, the index indicates the kind of value and the +value is encoded according to the schema. + +Note that the Avro data type \verb+bytes+ corresponds to the +LabComm declaration \verb+byte[_]+, i.e. a varaible length byte array. + +\subsubsection*{the wire protocol} + +\begin{tabular}{|l|c|c|} + \hline + What & LabComm & Avro \\ \hline + Data description & Binary signature & JSON schema \\ + Signature sent only once pre connection& posible & possible \\ + Signature sent with each sample & possible & possible \\ + Data encoding & binary & binary \\ + \hline +\end{tabular} + + +Both avro and labcomm use varints when encoding data, similar in that +they both send a sequence of bytes containing 7 bit chunks (with the +eight bit signalling more chunks to come), but they differ in range, +endianness and signedness. + +\begin{verbatim} + LabComm Avro + unsigned 32 bit signed zig-zag coding + most significant chunk least significant chunk + first first + + 0 -> 00 0 -> 00 + 1 -> 01 -1 -> 01 + 2 -> 02 1 -> 02 + ... -2 -> 03 + 2 -> 04 + ... + 127 -> 7f -64 -> 7f + 128 -> 81 00 64 -> 80 01 + 129 -> 81 01 -65 -> 81 01 + 130 -> 81 02 65 -> 82 01 + ... ... +\end{verbatim} + +\paragraph{Avro Object Container Files} can be seen as a counterpart + to a LabComm channel: +Avro includes a simple object container file format. A file has a +schema, and all objects stored in the file must be written according to +that schema, using binary encoding. Objects are stored in blocks that +may be compressed. Syncronization markers are used between blocks to +permit efficient splitting of files, and enable detection of +corrupt blocks. + + +The major difference is the sync markers that LabComm does not have, as +LabComm assumes that, while the transport may drop packets, there will +be no bit errors in a received packet. If data integrity is required, +that is delegated to the reader and writer for the particular transport. + +\subsubsection{Fetures not in LabComm} + +Avro has a set of features with no counterpart in LabComm. They include + +\paragraph{Codecs.} + +Avro has multiple codecs (for compression of the data): + + \begin{verbatim} + Required Codecs: + - null : The "null" codec simply passes through data uncompressed. + + - deflate : The "deflate" codec writes the data block using the deflate + algorithm as specified in RFC 1951, and typically implemented using the + zlib library. Note that this format (unlike the "zlib format" in RFC + 1950) does not have a checksum. + + Optional Codecs + + - snappy: The "snappy" codec uses Google's Snappy compression library. Each + compressed block is followed by the 4-byte, big-endian CRC32 checksum of + the uncompressed data in the block. + + \end{verbatim} + + \paragraph{Schema Resolution.} The main objective of LabComm is to + ensure correct operation at run-time. Therefore, a LabComm decoder + requires the signatures for each handled sample to match exactly. + + Avro, on the other hand, supports the evolution of schemas and + provides support for reading data where the ordering of fields + differ (but names and types are the same), numerical types differ + but can be + \emph{promoted} (E.g., \verb+int+ can be promoted to \verb+long+, + \verb+float+, or \verb+double+.), and record fields have been added + or removed (but are nullable or have default values). + + \paragraph{Schema fingerprints.} Avro defines a \emph{Parsing + Canonical Form} to define when two JSON schemas are ``the same''. + To reduce the overhead when, e.g., tagging data with the schema + there is support for creating a \emph{fingerprint} using 64/128/256 + bit hashing, in combination with a centralized repository for + fingerprint/schema pairs. + \bibliography{refs}{} \bibliographystyle{plain} @@ -558,22 +770,23 @@ first. The built-in data types are encoded as follows: \begin{lstlisting}[basicstyle=\footnotesize\ttfamily] -||Type ||Encoding/Size || -||----------||---------------------------------------------------|| -||boolean || 8 bits || -||byte || 8 bits || -||short || 16 bits || -||integer || 32 bits || -||long || 64 bits || -||float || 32 bits || -||double || 64 bits || -||string || length (varint), followed by UTF8 encoded string || -||array || each variable index (varint), || -|| || followed by encoded elements || -||struct || concatenation of encoding of each element || -|| || in declaration order || +||Type ||Encoding/Size || +||-----------||---------------------------------------------------|| +||boolean || 8 bits || +||byte || 8 bits || +||short || 16 bits || +||integer || 32 bits || +||long || 64 bits || +||float || 32 bits || +||double || 64 bits || +||sample_ref || 32 bits || +||string || length (varint), followed by UTF8 encoded string || +||array || each variable index (varint), || +|| || followed by encoded elements || +||struct || concatenation of encoding of each element || +|| || in declaration order || \end{lstlisting} - +\pagebreak \subsection{Protocol grammar} \label{sec:ConcreteGrammar} \begin{lstlisting}[basicstyle=\footnotesize\ttfamily] diff --git a/examples/simple/Encoder.java b/examples/simple/Encoder.java index d70384cee5fe7452d4cb413db3c7c6ef09f9e7a1..15e48582cb1d08b879980b61a76dad86928fea9c 100644 --- a/examples/simple/Encoder.java +++ b/examples/simple/Encoder.java @@ -16,12 +16,14 @@ public class Encoder throws Exception { encoder = new EncoderChannel(out); + doavoid.register(encoder); theTwoInts.register(encoder); IntString.register(encoder); TwoArrays.register(encoder); } public void doEncode() throws java.io.IOException { + TwoInts x = new TwoInts(); x.a = 17; x.b = 42; @@ -35,6 +37,9 @@ public class Encoder // ta.variable = new int[][] {{1,2},{0x11,0x12},{0x21,0x22},{0x31,0x32}}; ta.variable = new int[][] {{1,2, 3, 4},{0x21,0x22,0x23,0x24}}; + System.out.println("Encoding doavoid"); + doavoid.encode(encoder); + System.out.println("Encoding theTwoInts, a="+x.a+", b="+x.b); theTwoInts.encode(encoder, x); diff --git a/examples/simple/EncoderIS.java b/examples/simple/EncoderIS.java new file mode 100644 index 0000000000000000000000000000000000000000..4d7fd3a138bf64dcc1022c00409a940d0934da5f --- /dev/null +++ b/examples/simple/EncoderIS.java @@ -0,0 +1,53 @@ +import java.io.File; +import java.io.FileOutputStream; +import java.io.OutputStream; + +import se.lth.control.labcomm.EncoderChannel; + +/** + * Simple encoder + */ +public class EncoderIS +{ + + EncoderChannel encoder; + + public EncoderIS(OutputStream out) + throws Exception + { + encoder = new EncoderChannel(out); +// doavoid.register(encoder); +// theTwoInts.register(encoder); + IntString.register(encoder); +// TwoArrays.register(encoder); + } + + public void doEncodeIS() throws java.io.IOException { + IntString a = new IntString(); + a.x = 17; + a.s = "A string"; + + IntString b = new IntString(); + b.x = 9; + b.s = "Hej"; + + IntString c = new IntString(); + c.x = 133742; + c.s = "Thirteenthirtysevenfourtytwo"; + + System.out.println("Encoding IntStrings"); + IntString.encode(encoder, a); + IntString.encode(encoder, b); + IntString.encode(encoder, c); + } + + + public static void main(String[] arg) throws Exception { + FileOutputStream fos = new FileOutputStream(arg[0]); + EncoderIS example = new EncoderIS(fos); + example.doEncodeIS(); + fos.close(); + } + +} + diff --git a/examples/simple/example_decoder.c b/examples/simple/example_decoder.c index 122745d62aebe4ea9831dfbf4280d4f267e40425..107aadae3c237bc263ac359ab9534337ff627884 100644 --- a/examples/simple/example_decoder.c +++ b/examples/simple/example_decoder.c @@ -8,6 +8,10 @@ #include "gen/simple.h" #include <stdio.h> +static void handle_simple_doavoid(simple_doavoid *v, void *context) { + printf("Got a void.\n"); +} + static void handle_simple_theTwoInts(simple_TwoInts *v,void *context) { printf("Got theTwoInts. a=%d, b=%d\n", v->a, v->b); } @@ -69,6 +73,7 @@ int main(int argc, char *argv[]) { return 1; } + labcomm_decoder_register_simple_doavoid(decoder, handle_simple_doavoid, context); labcomm_decoder_register_simple_theTwoInts(decoder, handle_simple_theTwoInts, context); labcomm_decoder_register_simple_anotherTwoInts(decoder, handle_simple_anotherTwoInts, context); labcomm_decoder_register_simple_IntString(decoder, handle_simple_IntString, context); diff --git a/examples/user_types/Decoder.java b/examples/user_types/Decoder.java index bdb17374517015db59e66c02c3144b9d9bf886bc..29069b1cfb9d456f65b1c0f598f67a17a77e695c 100644 --- a/examples/user_types/Decoder.java +++ b/examples/user_types/Decoder.java @@ -1,22 +1,46 @@ import java.io.File; import java.io.FileInputStream; import java.io.InputStream; +import java.io.IOException; import se.lth.control.labcomm.DecoderChannel; +import se.lth.control.labcomm.TypeDef; +import se.lth.control.labcomm.TypeDefParser; +//import se.lth.control.labcomm.TypeBinding; public class Decoder - implements twoLines.Handler - + implements twoLines.Handler, +// TypeDef.Handler, +// TypeBinding.Handler, + TypeDefParser.TypeDefListener, + twoInts.Handler, + theFirstInt.Handler, + theSecondInt.Handler, + doavoid.Handler, + intAndRef.Handler { - DecoderChannel decoder; + private DecoderChannel decoder; + private TypeDefParser tdp; public Decoder(InputStream in) throws Exception { decoder = new DecoderChannel(in); + doavoid.register(decoder, this); + twoInts.register(decoder, this); twoLines.register(decoder, this); + theFirstInt.register(decoder, this); + theSecondInt.register(decoder, this); + intAndRef.register(decoder, this); + doavoid.registerSampleRef(decoder); + this.tdp = TypeDefParser.registerTypeDefParser(decoder); + // TypeDef.register(decoder, this); + // TypeBinding.register(decoder, this); + + tdp.addListener(this); + try { System.out.println("Running decoder."); decoder.run(); @@ -33,6 +57,48 @@ public class Decoder return "Line from "+genPoint(l.start)+" to "+genPoint(l.end); } +// public void handle_TypeDef(TypeDef d) throws java.io.IOException { +// System.out.println("Got TypeDef: "+d.getName()+"("+d.getIndex()+")"); +// } +// +// public void handle_TypeBinding(TypeBinding d) throws java.io.IOException { +// System.out.println("Got TypeBinding: "+d.getSampleIndex()+" --> "+d.getTypeIndex()+""); +// } + + public void onTypeDef(TypeDefParser.ParsedTypeDef d) { + System.out.println("ontype_def: "); + System.out.print((d.isSampleDef()?"sample ":"typedef ")+d); + System.out.println(" "+d.getName()+";"); + //for(byte b: d.getSignature()) { + // System.out.print(Integer.toHexString(b)+" "); + //} + //System.out.println(); + //try { + // tdp.parseSignature(d.getIndex()); + //} catch(IOException ex) { ex.printStackTrace();} + } + + public void handle_doavoid() throws java.io.IOException { + System.out.println("Got a void."); + } + + public void handle_twoInts(twoInts d) throws java.io.IOException { + System.out.print("Got twoInts: "); + System.out.println(d.a +", "+d.b); + } + + public void handle_theFirstInt(int d) throws java.io.IOException { + System.out.println("Got theFirstInt: "+d); + } + + public void handle_theSecondInt(int d) throws java.io.IOException { + System.out.println("Got theSecondInt: "+d); + } + + public void handle_intAndRef(intAndRef d) throws java.io.IOException { + System.out.println("Got intAndRef: "+d.x+", "+d.reference); + } + public void handle_twoLines(twoLines d) throws java.io.IOException { System.out.print("Got twoLines: "); System.out.println("Line l1: "+genLine(d.l1)); diff --git a/examples/user_types/Encoder.java b/examples/user_types/Encoder.java index aa2f80e9617aa3b47b468f4d46469573743a8bc9..d5687a2ce1d86b9643cddc58921373618b80b7bd 100644 --- a/examples/user_types/Encoder.java +++ b/examples/user_types/Encoder.java @@ -16,10 +16,37 @@ public class Encoder throws Exception { encoder = new EncoderChannel(out); + doavoid.register(encoder); + twoInts.register(encoder); twoLines.register(encoder); + theFirstInt.register(encoder); + theSecondInt.register(encoder); + intAndRef.register(encoder); + doavoid.registerSampleRef(encoder); } public void doEncode() throws java.io.IOException { + System.out.println("Encoding doavoid"); + doavoid.encode(encoder); + + intAndRef iar = new intAndRef(); + iar.x = 17; + iar.reference = doavoid.class; + + System.out.println("Encoding intAndRef"); + intAndRef.encode(encoder, iar); + + twoInts ti = new twoInts(); + ti.a = 12; + ti.b = 21; + + System.out.println("Encoding twoInts"); + twoInts.encode(encoder, ti); + + System.out.println("Encoding the Ints"); + theFirstInt.encode(encoder, 71); + theSecondInt.encode(encoder, 24); + twoLines x = new twoLines(); line l1 = new line(); point p11 = new point(); diff --git a/examples/user_types/ExampleDecoder.cs b/examples/user_types/ExampleDecoder.cs index 1b6bc0d2ae2e96e3e5213afaadddbbf10245f286..95b1fca4e2bf1d0adc4bad67823137b03980163c 100644 --- a/examples/user_types/ExampleDecoder.cs +++ b/examples/user_types/ExampleDecoder.cs @@ -7,7 +7,12 @@ using se.lth.control.labcomm; namespace user_types { - class Decoder : twoLines.Handler + class Decoder : twoLines.Handler, + twoInts.Handler, + theFirstInt.Handler, + theSecondInt.Handler, + doavoid.Handler, + intAndRef.Handler { DecoderChannel dec; @@ -15,6 +20,12 @@ namespace user_types { dec = new DecoderChannel(stream); twoLines.register(dec, this); + twoInts.register(dec, this); + theFirstInt.register(dec, this); + theSecondInt.register(dec, this); + doavoid.register(dec, this); + intAndRef.register(dec, this); + doavoid.registerSampleRef(dec); try { Console.WriteLine("Running decoder."); @@ -41,6 +52,33 @@ namespace user_types Console.WriteLine("Line l2: " + genLine(d.l2)); } + public void handle(twoInts d) + { + Console.WriteLine("Got twoInts: "); + Console.WriteLine("a: "+d.a); + Console.WriteLine("b: "+d.b); + } + + void theFirstInt.Handler.handle(int d) + { + Console.WriteLine("Got theFirstInt: "+d); + } + + void theSecondInt.Handler.handle(int d) + { + Console.WriteLine("Got theSecondInt: "+d); + } + + void doavoid.Handler.handle() + { + Console.WriteLine("Got a void."); + } + + void intAndRef.Handler.handle(intAndRef d) + { + Console.WriteLine("Got intAndRef: "+d.x+" : "+d.reference); + } + static void Main(string[] args) { new Decoder(new FileStream(args[0], FileMode.Open)); diff --git a/examples/user_types/Makefile b/examples/user_types/Makefile index 4af38f677bad712cd6a0701411555d2104d65229..7603ffd308aedc0b23d1399d0050c1a257f34c27 100644 --- a/examples/user_types/Makefile +++ b/examples/user_types/Makefile @@ -1,15 +1,16 @@ LCDIR=../.. -LCCJAR=${LCDIR}/compiler/labcomm2014_compiler.jar # the LabComm compiler -LCLJAR=${LCDIR}/lib/java/labcomm2014.jar # the LabComm library +LCCJAR=${LCDIR}/compiler/labcomm2014_compiler.jar# the LabComm compiler +LCLJAR=${LCDIR}/lib/java/labcomm2014.jar# the LabComm library EXECUTABLES=example_encoder example_decoder \ - Encoder.class Decoder.class \ + Encoder.class Decoder.class TDDecoder.class \ ExampleEncoder.exe ExampleDecoder.exe + include ${LCDIR}/lib/c/os_compat.mk GENDIR=gen -.PHONY: all cleanbuild clean distclean build run allall buildcs runwcs +.PHONY: all cleanbuild clean distclean build run allall buildcs runwcs runjastadd all: cleanbuild run @@ -49,6 +50,7 @@ build : java -jar ${LCDIR}/compiler/labcomm_compiler.jar --java=${GENDIR} --c=${GENDIR}/test.c --h=${GENDIR}/test.h --python=${GENDIR}/test.py --cs=${GENDIR}/test.cs test.lc javac -cp ${LCDIR}/lib/java/labcomm2014.jar:. ${GENDIR}/*.java Encoder.java Decoder.java + javac -cp ${LCDIR}/lib/java/labcomm2014.jar:${LCCJAR}:${GENDIR}:. TDDecoder.java ${CC} ${CFLAGS} ${LDFLAGS} -Wall -Werror -Wno-unused-function \ -I. -I${LCDIR}/lib/c/2014 -L${LCDIR}/lib/c \ @@ -122,7 +124,7 @@ runwcs: build ExampleEncoder.exe ExampleDecoder.exe @PYTHONPATH=${LCDIR}/lib/python ../wiki_example/example_decoder.py encoded_data_j LabComm2014 @echo "************ running C# decoder: *****************" - @LD_LIBRARY_PATH=${LCDIR}/lib/c/ ./ExampleDecoder.exe encoded_data_j + @LD_LIBRARY_PATH=${LCDIR}/lib/c/ mono ./ExampleDecoder.exe encoded_data_j @echo "************ running C encoder: *****************" @LD_LIBRARY_PATH=${LCDIR}/lib/c/ ./example_encoder encoded_data_c @@ -137,7 +139,7 @@ runwcs: build ExampleEncoder.exe ExampleDecoder.exe @PYTHONPATH=${LCDIR}/lib/python ../wiki_example/example_decoder.py encoded_data_c LabComm2014 @echo "************ running C# decoder: *****************" - @./ExampleDecoder.exe encoded_data_c + @mono ./ExampleDecoder.exe encoded_data_c @echo "************ running python encoder: *****************" @PYTHONPATH=${LCDIR}/lib/python:${GENDIR} ./example_encoder.py encoded_data_p LabComm2014 @@ -152,10 +154,10 @@ runwcs: build ExampleEncoder.exe ExampleDecoder.exe PYTHONPATH=${LCDIR}/lib/python ../wiki_example/example_decoder.py encoded_data_p LabComm2014 @echo "************ running C# decoder: *****************" - @./ExampleDecoder.exe encoded_data_p + @mono ./ExampleDecoder.exe encoded_data_p @echo "************ running C# encoder: *****************" - @./ExampleEncoder.exe encoded_data_cs + @mono ./ExampleEncoder.exe encoded_data_cs @echo "************ running Java decoder: *****************" @java -cp .:${LCDIR}/lib/java/labcomm2014.jar:${GENDIR} Decoder encoded_data_cs @@ -167,8 +169,19 @@ runwcs: build ExampleEncoder.exe ExampleDecoder.exe @PYTHONPATH=${LCDIR}/lib/python ../wiki_example/example_decoder.py encoded_data_cs LabComm2014 @echo "************ running C# decoder: *****************" - @./ExampleDecoder.exe encoded_data_cs + @mono ./ExampleDecoder.exe encoded_data_cs + +runjastadd: cleanbuild + @echo + @echo "********************************************" + @echo "*** ************ running example with JastAdd unparsing ***" + @echo "********************************************" + @echo + + @java -cp .:${LCDIR}/lib/java/labcomm2014.jar:${GENDIR} Encoder encoded_data_j + @echo "************ running Java TypeDefdecoder: *****************" + java -cp .:${LCDIR}/lib/java/labcomm2014.jar:${LCCJAR}:${GENDIR} TDDecoder encoded_data_j clean: diff --git a/examples/user_types/TDDecoder.java b/examples/user_types/TDDecoder.java new file mode 100644 index 0000000000000000000000000000000000000000..6bfdb3ca8f33b5af819472e65a229f4f177e3fd3 --- /dev/null +++ b/examples/user_types/TDDecoder.java @@ -0,0 +1,139 @@ +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.io.IOException; + +import se.lth.control.labcomm.DecoderChannel; +import se.lth.control.labcomm.TypeDef; +import se.lth.control.labcomm.TypeDefParser; +import se.lth.control.labcomm.ASTbuilder; +//import se.lth.control.labcomm.TypeBinding; + +import se.lth.control.labcomm2014.compiler.Program; +import java.io.FileOutputStream; +import java.io.PrintStream; + +import java.util.Vector; +import java.util.LinkedList; +import java.util.Iterator; + + +public class TDDecoder + implements twoLines.Handler, +// TypeDef.Handler, +// TypeBinding.Handler, + TypeDefParser.TypeDefListener, + twoInts.Handler, + theFirstInt.Handler, + theSecondInt.Handler, + doavoid.Handler, + intAndRef.Handler +{ + + private DecoderChannel decoder; + private TypeDefParser tdp; + + public TDDecoder(InputStream in) + throws Exception + { + decoder = new DecoderChannel(in); + twoInts.register(decoder, this); + twoLines.register(decoder, this); + theFirstInt.register(decoder, this); + theSecondInt.register(decoder, this); + doavoid.register(decoder, this); + intAndRef.register(decoder, this); + doavoid.registerSampleRef(decoder); + this.tdp = TypeDefParser.registerTypeDefParser(decoder); + // TypeDef.register(decoder, this); + // TypeBinding.register(decoder, this); + + + tdp.addListener(this); + + try { + System.out.println("Running decoder."); + decoder.run(); + } catch (java.io.EOFException e) { + System.out.println("Decoder reached end of file."); + } + } + + private String genPoint(point p) { + return "("+p.x.val+", "+p.y.val+")"; + } + + private String genLine(line l) { + return "Line from "+genPoint(l.start)+" to "+genPoint(l.end); + } + +// public void handle_TypeDef(TypeDef d) throws java.io.IOException { +// System.out.println("Got TypeDef: "+d.getName()+"("+d.getIndex()+")"); +// } +// +// public void handle_TypeBinding(TypeBinding d) throws java.io.IOException { +// System.out.println("Got TypeBinding: "+d.getSampleIndex()+" --> "+d.getTypeIndex()+""); +// } + + public void onTypeDef(TypeDefParser.ParsedTypeDef d) { + if(d.isSampleDef()){ + System.out.println("onTypeDef (sample): "); + ASTbuilder v = new ASTbuilder(); + Program p = v.makeProgram((TypeDefParser.ParsedSampleDef) d); + try { + //FileOutputStream f = new FileOutputStream("/tmp/foopp"+d.getName()+".txt"); + //PrintStream out = new PrintStream(f); + p.pp(System.out); + //p.C_genC(System.out, new Vector(), "lcname", "prefix", 2014); + //p.J_gen(out, "testpackage", 2014); + //out.close(); + } catch (Throwable e) { + System.err.println("Exception: " + e); + e.printStackTrace(); + } + } + //System.out.println(" "+d.getName()+";"); + //for(byte b: d.getSignature()) { + // System.out.print(Integer.toHexString(b)+" "); + //} + //System.out.println(); + //try { + // tdp.parseSignature(d.getIndex()); + //} catch(IOException ex) { ex.printStackTrace();} + } + + public void handle_twoInts(twoInts d) throws java.io.IOException { + System.out.print("Got twoInts: "); + System.out.println(d.a +", "+d.b); + } + + public void handle_theFirstInt(int d) throws java.io.IOException { + System.out.println("Got theFirstInt: "+d); + } + + public void handle_theSecondInt(int d) throws java.io.IOException { + System.out.println("Got theSecondInt: "+d); + } + + public void handle_doavoid() throws java.io.IOException { + System.out.println("Got a void."); + } + + public void handle_intAndRef(intAndRef d) throws java.io.IOException { + System.out.println("Got intAndRef: "+d.x+", "+d.reference); + } + + public void handle_twoLines(twoLines d) throws java.io.IOException { + System.out.print("Got twoLines: "); + System.out.println("Line l1: "+genLine(d.l1)); + System.out.println(" Line l2: "+genLine(d.l2)); + } + + + public static void main(String[] arg) throws Exception { + TDDecoder example = new TDDecoder( + new FileInputStream(new File(arg[0])) + ); + } +} + diff --git a/examples/user_types/example_decoder.c b/examples/user_types/example_decoder.c index 1edc52ff2bb0ac37c009d705d0226123d5f67adb..b727f8a47d85007db2bd3c05141c9d5da150ad5a 100644 --- a/examples/user_types/example_decoder.c +++ b/examples/user_types/example_decoder.c @@ -8,8 +8,36 @@ #include "gen/test.h" #include <stdio.h> +static void handle_test_doavoid(test_doavoid *v,void *context) { + printf("Got a void.\n"); +} + +static void handle_test_intAndRef(test_intAndRef *v,void *context) { + printf("Got intAndRef. (%d : %s) \n", v->x, v->reference->name); +} + +static void handle_test_twoInts(test_twoInts *v,void *context) { + printf("Got twoInts. (%d,%d) \n", v->a, v->b); +} + +static void handle_test_theFirstInt(int *v,void *context) { + printf("Got theFirstInt. (%d) \n", *v); +} + +static void handle_test_theSecondInt(int *v,void *context) { + printf("Got theSecondInt. (%d) \n", *v); +} + +static void handle_type_def(struct labcomm_raw_type_def *v,void *context) { + printf("Got type_def. (0x%x) %s\n", v->index, v->name); +} + +static void handle_type_binding(struct labcomm_type_binding *v,void *context) { + printf("Got type binding. 0x%x --> 0x%x\n", v->sample_index, v->type_index); +} + static void handle_test_twoLines(test_twoLines *v,void *context) { - printf("Got theTwoInts. (%d,%d) -> (%d,%d), (%d,%d) -> (%d,%d)\n", v->l1.start.x.val, v->l1.start.y.val, + printf("Got twoLines. (%d,%d) -> (%d,%d), (%d,%d) -> (%d,%d)\n", v->l1.start.x.val, v->l1.start.y.val, v->l1.end.x.val, v->l1.end.y.val, v->l2.start.x.val, v->l2.start.y.val, v->l2.end.x.val, v->l2.end.y.val); @@ -33,7 +61,16 @@ int main(int argc, char *argv[]) { return 1; } + labcomm_decoder_register_test_doavoid(decoder, handle_test_doavoid, context); + labcomm_decoder_register_test_intAndRef(decoder, handle_test_intAndRef, context); + labcomm_decoder_sample_ref_register(decoder,labcomm_signature_test_doavoid ); + + labcomm_decoder_register_test_twoInts(decoder, handle_test_twoInts, context); + labcomm_decoder_register_test_theFirstInt(decoder, handle_test_theFirstInt, context); + labcomm_decoder_register_test_theSecondInt(decoder, handle_test_theSecondInt, context); labcomm_decoder_register_test_twoLines(decoder, handle_test_twoLines, context); + labcomm_decoder_register_labcomm_type_def(decoder, handle_type_def, context); + labcomm_decoder_register_labcomm_type_binding(decoder, handle_type_binding, context); printf("Decoding:\n"); labcomm_decoder_run(decoder); diff --git a/examples/user_types/test.lc b/examples/user_types/test.lc index d2225394b890937f471e6984a8122aff11b3d51b..75497b4df01e761d47efba7dd95cc7bb1611fcf9 100644 --- a/examples/user_types/test.lc +++ b/examples/user_types/test.lc @@ -2,6 +2,16 @@ typedef struct { int val; } coord; +typedef int anInt; + +typedef void avoid; +sample avoid doavoid; + +sample struct { + int x; + sample reference; +} intAndRef; + typedef struct { coord x; coord y; @@ -23,3 +33,11 @@ sample struct { line l2; foo f; } twoLines; + +sample struct { + int a; + int b; +} twoInts; + +sample anInt theFirstInt; +sample anInt theSecondInt; diff --git a/examples/wiki_example/run b/examples/wiki_example/run index e3477ea720ff97ebc29ac2339cbcdcae121752ce..276d46b4292c6d0aa635c243713f17fe0ec4f903 100755 --- a/examples/wiki_example/run +++ b/examples/wiki_example/run @@ -16,9 +16,9 @@ gcc -Wall -Werror -o example_encoder -I../../lib/c/2014 \ example.c \ ../../lib/c/liblabcomm2014.a || exit 1 -javac -cp ../../lib/java:. *.java || exit 1 +javac -cp ../../lib/java/labcomm.jar:. *.java || exit 1 # Run through all executables (c->java->Python) ./example_encoder one two || exit 1 -java -cp ../../lib/java:. example_decoder_encoder example.encoded example.javaencoded || exit 1 +java -cp ../../lib/java/labcomm.jar:. example_decoder_encoder example.encoded example.javaencoded || exit 1 PYTHONPATH=../../lib/python ./example_decoder.py example.javaencoded || exit 1 diff --git a/lib/c/2006/labcomm2006.c b/lib/c/2006/labcomm2006.c index 8f628cfccd6b10dda2635577cfd6c150e7ec4625..ff09b636127ffd0746165b98db2b453d975bad96 100644 --- a/lib/c/2006/labcomm2006.c +++ b/lib/c/2006/labcomm2006.c @@ -237,7 +237,7 @@ void *labcomm2006_signature_array_ref(struct labcomm2006_memory *memory, } } -static int local_index = 0x40; +static int local_index = LABCOMM_USER; void labcomm2006_set_local_index(struct labcomm2006_signature *signature) { diff --git a/lib/c/2006/labcomm2006_private.h b/lib/c/2006/labcomm2006_private.h index 4c3361026bf8e3c83af75fcca44cdebec43453b5..378719ccd2f7eff21df847ffb37cc76ad3838ac9 100644 --- a/lib/c/2006/labcomm2006_private.h +++ b/lib/c/2006/labcomm2006_private.h @@ -42,7 +42,7 @@ #define LABCOMM_SAMPLE 0x02 #define LABCOMM_ARRAY 0x10 #define LABCOMM_STRUCT 0x11 -#define LABCOMM_USER 0x80 /* ..0xffffffff */ +#define LABCOMM_USER 0x40 /* ..0xffffffff */ /* * Predefined primitive type indices diff --git a/lib/c/2014/Makefile b/lib/c/2014/Makefile index 6742429773437384c38c06148fc6af2bd9f78dc5..f5a9f1098233a7f6fcd9766fe5298ebac3ec5a52 100644 --- a/lib/c/2014/Makefile +++ b/lib/c/2014/Makefile @@ -20,6 +20,7 @@ OBJS=labcomm$(VERSION).o \ labcomm$(VERSION)_decoder.o \ labcomm$(VERSION)_dynamic_buffer_writer.o \ labcomm$(VERSION)_fd_reader.o \ + labcomm$(VERSION)_type_signature.o \ labcomm$(VERSION)_fd_writer.o \ labcomm$(VERSION)_pthread_scheduler.o @@ -29,8 +30,12 @@ ifeq ($(LABCOMM_EXPERIMENTAL),true) experimental/labcomm_thr_reader_writer.o \ experimental/ThrottleDrv/ethernet_drv.o \ experimental/ThrottleDrv/throttle_drv.o \ - experimental/labcomm_udp_reader_writer.o\ - experimental/labcomm_sig_parser.o + experimental/labcomm_udp_reader_writer.o +endif + +# Enable experimental objects by `make LABCOMM_SIG_PARSER=true` +ifeq ($(LABCOMM_SIG_PARSER),true) + OBJS += experimental/labcomm_sig_parser.o endif LABCOMM_JAR=../../../compiler/labcomm$(LIBVERSION)_compiler.jar @@ -83,8 +88,8 @@ distclean: clean ../liblabcomm$(LIBVERSION).a: $(OBJS) ar -r $@ $^ -# Enable experimental objects by `make LABCOMM_EXPERIMENTAL=true` -ifeq ($(LABCOMM_EXPERIMENTAL),true) +# Enable sig parser objects by `make LABCOMM_SIG_PARSER=true` +ifeq ($(LABCOMM_SIG_PARSER),true) experimental/test_sig_parser : experimental/labcomm_sig_parser.o experimental/test_sig_parser.c endif diff --git a/lib/c/2014/experimental/labcomm_sig_parser.c b/lib/c/2014/experimental/labcomm_sig_parser.c index 7c4a586717e1944a1d9db016d24fd21fbf4cb3f4..75e9771e53f0fa85df6577b6aee8ef6707ba7609 100644 --- a/lib/c/2014/experimental/labcomm_sig_parser.c +++ b/lib/c/2014/experimental/labcomm_sig_parser.c @@ -15,8 +15,6 @@ * - The RETURN_STRINGS and where/if to allocate strings is to be decided, it * is currently not used * - * - TYPE_DECL is not tested (is it ever sent?) - * * - The dynamic allocation of the parser is not quite dynamic, the sizes are * set through the init function, and are then static. * This should be adapted when allocation is parameterized/user-definable @@ -66,7 +64,7 @@ static int unpack_varint(unsigned char *buf, unsigned char cont = TRUE; do { - char c = buf[idx+i]; + unsigned char c = buf[idx+i]; res = (res << 7) | (c & 0x7f); cont = c & 0x80; i++; @@ -218,6 +216,7 @@ void getStr(labcomm_sig_parser_t *b, unsigned char *dest, size_t size) { if( size > rem ) size = rem; strncpy((char *)dest, (char *)&b->c[b->idx], size); + dest[size] = 0; b->idx += size; } @@ -271,6 +270,7 @@ static size_t labcomm_sizeof_primitive(unsigned int type) return 2; case TYPE_INTEGER : case TYPE_FLOAT : + case TYPE_SAMPLE_REF : return 4; case TYPE_LONG : case TYPE_DOUBLE : @@ -340,7 +340,65 @@ int encoded_size_parse_sig(struct labcomm_signature *sig, void *sample) return -1; } -static int accept_signature(labcomm_sig_parser_t *d) +static int accept_signature(labcomm_sig_parser_t *d, + labcomm_type type, + unsigned int start, + unsigned int uid, char *name) +{ + get_varint(d); // ignore sig len + VERBOSE_PRINTF("\ntype = "); + accept_type(d); + //printf(" : "); + //unsigned int dt = pop(d); +#ifdef USE_TYPE_AND_SIZE + unsigned int type = pop_val(d); + unsigned int enc_size = pop_val(d); +#else + pop_val(d); // unsigned int type + pop_val(d); // unsigned int enc_size +#endif + if(type != PKG_SAMPLE_DECL) { + if(type == PKG_SAMPLE_REF) { + INFO_PRINTF("accept_signature: ignoring sample ref\n"); + return TRUE; + } else if (type == PKG_TYPE_DECL) { + INFO_PRINTF("accept_signature: ignoring typedef\n"); + return TRUE; + } else { + error("decl is neither sample, ref, or typedef???"); + return FALSE; + } + } + unsigned int end = d->idx; + unsigned int len = end-start; + + struct labcomm_signature *newsig = get_sig_t(d, uid); +// newsig->type = type; + if(len <= d->max_sig_len) { + d->signatures_length[uid-LABCOMM_USER] = len; + memcpy(d->signatures[uid-LABCOMM_USER], &d->c[start], len); + newsig->size = len; + newsig->signature = d->signatures[uid-LABCOMM_USER]; + newsig->name = name; + } else { + error("sig longer than max length (this ought to be dynamic...)"); + } + VERBOSE_PRINTF("signature for uid %x: %s (start=%x,end=%x,len=%d)\n", uid, get_signature_name(d, uid), start,end, len); + INFO_PRINTF("accept_signature: %s\n", newsig->name); +#ifdef LABCOMM_EXPERIMENTAL_CACHED_ENCODED_SIZE + if(! d->current_decl_is_varsize) { + newsig->cached_encoded_size = enc_size; + newsig->encoded_size = encoded_size_static; + INFO_PRINTF(".... is static size = %d\n", enc_size); + } else { + newsig->cached_encoded_size = -1; + newsig->encoded_size = encoded_size_parse_sig; + INFO_PRINTF(".... is variable size\n"); + } +#endif + return TRUE; +} +static int accept_decl(labcomm_sig_parser_t *d, labcomm_type type) { if(accept_user_id(d)) { unsigned int uid = pop_val(d); @@ -354,54 +412,24 @@ static int accept_signature(labcomm_sig_parser_t *d) free(str); #endif unsigned char lenlen = labcomm_varint_sizeof(nlen); - get_varint(d); // ignore sig len - VERBOSE_PRINTF("\ntype = "); - accept_type(d); - //printf(" : "); - //unsigned int dt = pop(d); -#ifdef USE_TYPE_AND_SIZE - unsigned int type = pop_val(d); - unsigned int enc_size = pop_val(d); -#else - pop_val(d); // unsigned int type - pop_val(d); // unsigned int enc_size -#endif - unsigned int end = d->idx; - unsigned int len = end-start; - - struct labcomm_signature *newsig = get_sig_t(d, uid); -// newsig->type = type; - if(len <= d->max_sig_len) { - d->signatures_length[uid-LABCOMM_USER] = len; - memcpy(d->signatures[uid-LABCOMM_USER], &d->c[start], len); - newsig->size = len; - newsig->signature = d->signatures[uid-LABCOMM_USER]; - } else { - error("sig longer than max length (this ought to be dynamic...)"); - } + if(type != PKG_SAMPLE_DECL) { + // don't record typedefs and samplerefs (for now) + // to avoid number clashes with sample defs + // in the parser struct + return accept_signature(d, type, start, uid, (char *) &d->c[nstart+lenlen]); + } if(nlen < d->max_name_len) { // leave 1 byte for terminating NULL + char *name; d->signatures_name_length[uid-LABCOMM_USER] = nlen; memcpy(d->signatures_name[uid-LABCOMM_USER], &d->c[nstart+lenlen], nlen); d->signatures_name[uid-LABCOMM_USER][nlen]=0; - newsig->name = d->signatures_name[uid-LABCOMM_USER]; + name = d->signatures_name[uid-LABCOMM_USER]; + return accept_signature(d, type, start, uid, name); } else { error("sig name longer than max length (this ought to be dynamic..."); + return FALSE; } - VERBOSE_PRINTF("signature for uid %x: %s (start=%x,end=%x, nlen=%d,len=%d)\n", uid, get_signature_name(d, uid), start,end, nlen, len); - INFO_PRINTF("SIG: %s\n", newsig->name); -#ifdef LABCOMM_EXPERIMENTAL_CACHED_ENCODED_SIZE - if(! d->current_decl_is_varsize) { - newsig->cached_encoded_size = enc_size; - newsig->encoded_size = encoded_size_static; - INFO_PRINTF(".... is static size = %d\n", enc_size); - } else { - newsig->cached_encoded_size = -1; - newsig->encoded_size = encoded_size_parse_sig; - INFO_PRINTF(".... is variable size\n"); - } -#endif - return TRUE; } else { error("sample_decl with uid < LABCOMM_USER"); return FALSE; @@ -412,7 +440,7 @@ static int accept_signature(labcomm_sig_parser_t *d) int accept_packet(labcomm_sig_parser_t *d) { size_t nbytes; unsigned int type = peek_varint(d, &nbytes) ; - if(type == VERSION ) { + if(type == PKG_VERSION ) { advancen(d, nbytes);//consume type field get_varint(d); //ignore length field VERBOSE_PRINTF("got version.\n"); @@ -422,19 +450,37 @@ int accept_packet(labcomm_sig_parser_t *d) { char *str = (char *) pop_ptr(d); free(str); #endif - }else if(type == TYPE_DECL ) { - //XXX is this used? If so, is it correct? + } else if (type == PKG_SAMPLE_DECL) { + d->current_decl_is_varsize = FALSE; // <-- a conveniance flag in labcomm_sig_parser_t advancen(d, nbytes); + VERBOSE_PRINTF("sample_decl "); + get_varint(d); //ignore length field + accept_decl(d, type); + } else if (type == PKG_SAMPLE_REF) { d->current_decl_is_varsize = FALSE; // <-- a conveniance flag in labcomm_sig_parser_t - VERBOSE_PRINTF("type_decl "); + advancen(d, nbytes); + VERBOSE_PRINTF("sample_ref "); get_varint(d); //ignore length field - accept_signature(d); - } else if (type == SAMPLE_DECL) { + accept_decl(d, type); + }else if(type == PKG_TYPE_DECL ) { d->current_decl_is_varsize = FALSE; // <-- a conveniance flag in labcomm_sig_parser_t + advancen(d, nbytes);//consume type field + VERBOSE_PRINTF("type_decl "); + get_varint(d); //ignore length field + accept_decl(d, type); + } else if (type == PKG_TYPE_BINDING) { + VERBOSE_PRINTF("type_binding "); advancen(d, nbytes); - VERBOSE_PRINTF("sample_decl "); get_varint(d); //ignore length field - accept_signature(d); +#ifdef VERBOSE + int sid = +#endif + get_varint(d); //ignore sample id field +#ifdef VERBOSE + int tid = +#endif + get_varint(d); //ignore type id field + VERBOSE_PRINTF("sid=0x%x, tid=0x%x\n ", sid, tid); } else if(type >= LABCOMM_USER) { #ifdef EXIT_WHEN_RECEIVING_DATA printf("*** got sample data, exiting\n"); @@ -447,7 +493,7 @@ int accept_packet(labcomm_sig_parser_t *d) { error("got unknown type (<LABCOMM_USER)"); exit(1); #else - int len = get_varint(d); //ignore length field + int len = get_varint(d); // length field printf("got unknown tag: 0x%x, skipping %d bytes\n",type, len); advancen(d, len); #endif @@ -464,13 +510,14 @@ static int accept_user_id(labcomm_sig_parser_t *d){ push_val(d, uid); return TRUE; } else { + error("uid < LABCOMM_USER"); return FALSE; } } static int accept_string(labcomm_sig_parser_t *d){ unsigned int len = get_varint(d); - unsigned char *str=malloc(len); + unsigned char *str=malloc(len+1); // len is without terminating null getStr(d, str, len); VERBOSE_PRINTF("%s", str); #ifdef RETURN_STRINGS @@ -527,6 +574,11 @@ static int accept_type(labcomm_sig_parser_t *d){ labcomm_sig_parser_t_set_varsize(d); push_val(d, 0); break; + case TYPE_SAMPLE_REF : + VERBOSE_PRINTF("sample\n"); + advancen(d, nbytes); + push_val(d, 4); + break; case ARRAY_DECL : accept_array_decl(d); pop_val(d); // ignore element type @@ -537,7 +589,10 @@ static int accept_type(labcomm_sig_parser_t *d){ // push(d, pop(d) is a NOP --> leave size on stack break; default : - printf("accept_type default (type==%x) should not happen\n", type); + //should we distinguish between SAMPLE_DEF and TYPE_DEF here? + //printf("accept_type default (type==%x) should not happen\n", type); + VERBOSE_PRINTF("user type 0x%x\n",type); + advancen(d, nbytes); push_val(d, 0); push_val(d, type); return FALSE; @@ -601,7 +656,11 @@ static int accept_struct_decl(labcomm_sig_parser_t *d){ if(tid == STRUCT_DECL) { advancen(d, nbytes); unsigned int nf = get_varint(d); - VERBOSE_PRINTF("%d field struct:\n", nf); + if(nf == 0) { + VERBOSE_PRINTF("void\n"); + } else { + VERBOSE_PRINTF("%d field struct:\n", nf); + } int i; #ifdef USE_UNUSED_VARS int numVar=0; @@ -708,7 +767,7 @@ static int skip_array(labcomm_sig_parser_t *d, unsigned char *sig, int len, int int skip_struct(labcomm_sig_parser_t *d, unsigned char *sig, unsigned int len, int *pos) { size_t nbytes; - unsigned int nFields = unpack_varint(sig,*pos, &nbytes); + int nFields = unpack_varint(sig,*pos, &nbytes); *pos += nbytes; unsigned int i; unsigned int skipped=0; @@ -719,7 +778,7 @@ int skip_struct(labcomm_sig_parser_t *d, unsigned char *sig, unsigned int len, i #ifdef DEBUG VERBOSE_PRINTF("field #%d:\n----namelen==%d\n",i,namelen); char name[namelen+1]; //HERE BE DRAGONS. alloca? - strncpy(name, sig+*pos+nbytes, namelen); + strncpy(name, (const char *)sig+*pos+nbytes, namelen); name[namelen]=0; VERBOSE_PRINTF("----name = %s\n",name); #endif @@ -797,7 +856,7 @@ int skip_type(unsigned int type, labcomm_sig_parser_t *d, } #else int skip_type(unsigned int type, labcomm_sig_parser_t *d, - unsigned char *sig, unsigned int len, int *pos) + const char *sig, unsigned int len, int *pos) { int skipped=0; VERBOSE_PRINTF("skip_type %x\n", type); @@ -849,7 +908,7 @@ int skip_packed_sample_data(labcomm_sig_parser_t *d, struct labcomm_signature *s unsigned int skipped = 0; //skipped byte counter while(pos < sig->size) { size_t nbytes; - unsigned int type = unpack_varint(sig->signature,pos, &nbytes); + int type = unpack_varint(sig->signature,pos, &nbytes); pos+=nbytes; skipped += skip_type(type, d, sig->signature, sig->size, &pos); } diff --git a/lib/c/2014/experimental/labcomm_sig_parser.h b/lib/c/2014/experimental/labcomm_sig_parser.h index b40a534ef5461e9b12f79fe3af8053842d4011e4..46a1d1e41ba7e68379437f2e3b3bdd1f563b0b4c 100644 --- a/lib/c/2014/experimental/labcomm_sig_parser.h +++ b/lib/c/2014/experimental/labcomm_sig_parser.h @@ -8,14 +8,18 @@ #ifndef LABCOMM_SIG_PARSER_H #define LABCOMM_SIG_PARSER_H +#include "../labcomm.h" #include "../labcomm_private.h" -#undef DEBUG -#undef QUIET_STACK // don't print anything for push/pop +#define DEBUG +#define QUIET_STACK // don't print anything for push/pop #undef DEBUG_STACK_VERBOSE // dump stack, otherwise just print value of top #undef QUIET //just print type and size when skipping data -// #undef VERBOSE // print in great detail +#define VERBOSE // print in great detail + + +#undef SKIP_BY_PARSING #undef STATIC_ALLOCATION //dynamic allocation not completely implemented @@ -24,6 +28,7 @@ #define MAX_SIGNATURES 16 #define MAX_NAME_LEN 32 #define MAX_SIG_LEN 128 +#define TYPEDEF_BASE MAX_SIGNATURES #endif @@ -43,21 +48,24 @@ typedef struct { size_t max_signatures; // set by init(...) size_t max_name_len; size_t max_sig_len; + // arrays for signatures and typedefs + // signatures start at index 0 + // typedefs start at index MAX_SIGNATURES #ifdef STATIC_ALLOCATION - struct labcomm_signature sig_ts[MAX_SIGNATURES]; + struct labcomm_signature sig_ts[2*MAX_SIGNATURES]; - unsigned int signatures_length[MAX_SIGNATURES]; - unsigned int signatures_name_length[MAX_SIGNATURES]; - unsigned char signatures_name[MAX_SIGNATURES][MAX_NAME_LEN]; - unsigned char signatures[MAX_SIGNATURES][MAX_SIG_LEN]; + unsigned int signatures_length[2*MAX_SIGNATURES]; + unsigned int signatures_name_length[2*MAX_SIGNATURES]; + unsigned char signatures_name[2*MAX_SIGNATURES][MAX_NAME_LEN]; + unsigned char signatures[2*MAX_SIGNATURES][MAX_SIG_LEN]; #else - struct labcomm_signature *sig_ts; // [MAX_SIGNATURES] + struct labcomm_signature *sig_ts; // [2*MAX_SIGNATURES] - unsigned int *signatures_length; // [MAX_SIGNATURES] - unsigned char **signatures; // [MAX_SIGNATURES][MAX_SIG_LEN]; + unsigned int *signatures_length; // [2*MAX_SIGNATURES] + unsigned char **signatures; // [2*MAX_SIGNATURES][MAX_SIG_LEN]; - unsigned int *signatures_name_length; // [MAX_SIGNATURES] - char **signatures_name; // [MAX_SIGNATURES][MAX_NAME_LEN]; + unsigned int *signatures_name_length; // [2*MAX_SIGNATURES] + char **signatures_name; // [2*MAX_SIGNATURES][MAX_NAME_LEN]; #endif } labcomm_sig_parser_t; @@ -104,17 +112,12 @@ int skip_packed_sample_data(labcomm_sig_parser_t *p, struct labcomm_signature *s #undef RETURN_STRINGS // not really tested -#ifndef TRUE - -#define FALSE 0 -#define TRUE 1 - -#endif - typedef enum{ - VERSION = LABCOMM_VERSION, - SAMPLE_DECL = LABCOMM_SAMPLE_DEF, - TYPE_DECL = LABCOMM_TYPEDEF, + PKG_VERSION = LABCOMM_VERSION, + PKG_SAMPLE_DECL = LABCOMM_SAMPLE_DEF, + PKG_SAMPLE_REF = LABCOMM_SAMPLE_REF, + PKG_TYPE_DECL = LABCOMM_TYPE_DEF, + PKG_TYPE_BINDING = LABCOMM_TYPE_BINDING, ARRAY_DECL = LABCOMM_ARRAY, STRUCT_DECL = LABCOMM_STRUCT, @@ -126,6 +129,7 @@ typedef enum{ TYPE_LONG = LABCOMM_LONG, TYPE_FLOAT = LABCOMM_FLOAT, TYPE_DOUBLE = LABCOMM_DOUBLE, - TYPE_STRING = LABCOMM_STRING + TYPE_STRING = LABCOMM_STRING, + TYPE_SAMPLE_REF = LABCOMM_REF } labcomm_type ; #endif diff --git a/lib/c/2014/labcomm.c b/lib/c/2014/labcomm.c index a1994aff1ec08e7356295f4d3dcd6d12408e9446..a01c96bd8018687e8e3356e50ad01c3025d50ba3 100644 --- a/lib/c/2014/labcomm.c +++ b/lib/c/2014/labcomm.c @@ -47,19 +47,19 @@ UNWRAP_ac( __VA_ARGS__) = UNWRAP_ac(__VA_ARGS__)->next; \ } -int labcomm_reader_alloc(struct labcomm_reader *r, +int labcomm_reader_alloc(struct labcomm_reader *r, struct labcomm_reader_action_context *action_context) { UNWRAP(alloc, r, action_context); } -int labcomm_reader_free(struct labcomm_reader *r, +int labcomm_reader_free(struct labcomm_reader *r, struct labcomm_reader_action_context *action_context) { UNWRAP(free, r, action_context); } -int labcomm_reader_start(struct labcomm_reader *r, +int labcomm_reader_start(struct labcomm_reader *r, struct labcomm_reader_action_context *action_context, int local_index, int remote_index, const struct labcomm_signature *signature, @@ -68,41 +68,41 @@ int labcomm_reader_start(struct labcomm_reader *r, UNWRAP(start, r, action_context, local_index, remote_index, signature, value); } -int labcomm_reader_end(struct labcomm_reader *r, +int labcomm_reader_end(struct labcomm_reader *r, struct labcomm_reader_action_context *action_context) { UNWRAP(end, r, action_context); } -int labcomm_reader_fill(struct labcomm_reader *r, +int labcomm_reader_fill(struct labcomm_reader *r, struct labcomm_reader_action_context *action_context) { UNWRAP(fill, r, action_context); } -int labcomm_reader_ioctl(struct labcomm_reader *r, +int labcomm_reader_ioctl(struct labcomm_reader *r, struct labcomm_reader_action_context *action_context, int local_index, int remote_index, - const struct labcomm_signature *signature, + const struct labcomm_signature *signature, uint32_t ioctl_action, va_list args) { - UNWRAP(ioctl, r, action_context, + UNWRAP(ioctl, r, action_context, local_index, remote_index, signature, ioctl_action, args); } -int labcomm_writer_alloc(struct labcomm_writer *w, +int labcomm_writer_alloc(struct labcomm_writer *w, struct labcomm_writer_action_context *action_context) { UNWRAP(alloc, w, action_context); } -int labcomm_writer_free(struct labcomm_writer *w, +int labcomm_writer_free(struct labcomm_writer *w, struct labcomm_writer_action_context *action_context) { UNWRAP(free, w, action_context); } -int labcomm_writer_start(struct labcomm_writer *w, +int labcomm_writer_start(struct labcomm_writer *w, struct labcomm_writer_action_context *action_context, int index, const struct labcomm_signature *signature, void *value) @@ -110,26 +110,26 @@ int labcomm_writer_start(struct labcomm_writer *w, UNWRAP(start, w, action_context, index, signature, value); } -int labcomm_writer_end(struct labcomm_writer *w, +int labcomm_writer_end(struct labcomm_writer *w, struct labcomm_writer_action_context *action_context) { UNWRAP(end, w, action_context); -} +} -int labcomm_writer_flush(struct labcomm_writer *w, +int labcomm_writer_flush(struct labcomm_writer *w, struct labcomm_writer_action_context *action_context) { UNWRAP(flush, w, action_context); -} +} -int labcomm_writer_ioctl(struct labcomm_writer *w, - struct labcomm_writer_action_context *action_context, - int index, - const struct labcomm_signature *signature, +int labcomm_writer_ioctl(struct labcomm_writer *w, + struct labcomm_writer_action_context *action_context, + int index, + const struct labcomm_signature *signature, uint32_t ioctl_action, va_list args) { UNWRAP(ioctl, w, action_context, index, signature, ioctl_action, args); -} +} #undef UNWRAP #undef UNWRAP_ac @@ -137,12 +137,12 @@ int labcomm_writer_ioctl(struct labcomm_writer *w, -static const char *labcomm_error_string[] = { +static const char *labcomm_error_string[] = { #define LABCOMM_ERROR(name, description) description , #include "labcomm_error.h" #undef LABCOMM_ERROR }; -static const int labcomm_error_string_count = (sizeof(labcomm_error_string) / +static const int labcomm_error_string_count = (sizeof(labcomm_error_string) / sizeof(labcomm_error_string[0])); @@ -175,7 +175,7 @@ void labcomm2014_on_error_fprintf(enum labcomm_error error_id, size_t nbr_va_arg fprintf(stderr, "}\n"); va_end(arg_pointer); - } + } #else ; // If labcomm can't be compiled with stdio the user will have to make an own error callback functionif he/she needs error reporting. #endif @@ -207,8 +207,8 @@ void *labcomm_signature_array_ref(struct labcomm_memory *memory, *first = index; *last = index + 1; *data = labcomm_memory_alloc(memory, 0, size); - if (*data) { - memset(*data, 0, size); + if (*data) { + memset(*data, 0, size); } } else if (index < *first || *last <= index) { void *old_data = *data; @@ -221,8 +221,8 @@ void *labcomm_signature_array_ref(struct labcomm_memory *memory, *data = labcomm_memory_alloc(memory, 0, n * size); if (*data) { memset(*data, 0, n * size); - memcpy(*data + (old_first - *first) * size, - old_data, + memcpy(*data + (old_first - *first) * size, + old_data, (old_last - old_first) * size); } // dump(old_data, size, old_first, old_last); @@ -236,7 +236,7 @@ void *labcomm_signature_array_ref(struct labcomm_memory *memory, } } -static int local_index = 0x40; +static int local_index = LABCOMM_USER; void labcomm_set_local_index(struct labcomm_signature *signature) { @@ -257,6 +257,11 @@ int labcomm_get_local_index(const struct labcomm_signature *signature) return signature->index; } +int labcomm_get_local_type_index(const struct labcomm_signature *signature) +{ + return labcomm_get_local_index(signature); +} + int labcomm_internal_sizeof(const struct labcomm_signature *signature, void *v) { diff --git a/lib/c/2014/labcomm.h b/lib/c/2014/labcomm.h index 4bc6b6cb881f3a16be1780d97adbdeb972dee73c..dd8859e8654e1118e4154609165befc271883420 100644 --- a/lib/c/2014/labcomm.h +++ b/lib/c/2014/labcomm.h @@ -39,20 +39,7 @@ struct labcomm_encoder; struct labcomm_decoder; -/* - * Signature entry - */ -struct labcomm_signature { - char *name; - int (*encoded_size)(void *); /* void* refers to sample_data */ - int size; - unsigned char *signature; - int index; -#ifdef LABCOMM_EXPERIMENTAL_CACHED_ENCODED_SIZE - int cached_encoded_size; // -1 if not initialized or type is variable size -#endif -}; - +#include "labcomm_type_signature.h" /* * Error handling. */ @@ -85,9 +72,6 @@ typedef int (*labcomm_handle_new_datatype_callback)( struct labcomm_decoder *decoder, struct labcomm_signature *sig); -void labcomm_decoder_register_new_datatype_handler(struct labcomm_decoder *d, - labcomm_handle_new_datatype_callback on_new_datatype); - /* * Dynamic memory handling * lifetime == 0 memory that will live for as long as the diff --git a/lib/c/2014/labcomm_decoder.c b/lib/c/2014/labcomm_decoder.c index 54575ee1eaf7fbb62fecc0dc0427b4696f08cb39..cac035f6cb431e97efad2836dd33f5d86dd3fcb6 100644 --- a/lib/c/2014/labcomm_decoder.c +++ b/lib/c/2014/labcomm_decoder.c @@ -26,6 +26,18 @@ #include "labcomm_ioctl.h" #include "labcomm_dynamic_buffer_writer.h" +#ifdef DEBUG +#define DEBUG_FPRINTF(str, ...) fprintf(str, ##__VA_ARGS__) +#else +#define DEBUG_FPRINTF(str, ...) +#endif + +#ifdef DECODER_DEBUG +#define DECODER_DEBUG_FPRINTF(str, ...) fprintf(str, ##__VA_ARGS__) +#else +#define DECODER_DEBUG_FPRINTF(str, ...) +#endif + struct sample_entry { int remote_index; const struct labcomm_signature *signature; @@ -166,6 +178,21 @@ static int handle_sample_ref(struct labcomm_decoder *d, int remote_index, return result; } +static int decoder_skip(struct labcomm_decoder *d, int len, int tag) +{ + int i; + DECODER_DEBUG_FPRINTF(stdout, "got tag 0x%x, skipping %d bytes\n", tag, len); + for(i = 0; i <len; i++){ + DECODER_DEBUG_FPRINTF(stderr, "."); + labcomm_read_byte(d->reader); + if (d->reader->error < 0) { + DECODER_DEBUG_FPRINTF(stderr, "\nerror while skipping: %d\n", d->reader->error); + return d->reader->error; + } + } + DECODER_DEBUG_FPRINTF(stderr, "\n"); + return tag; +} static int decode_sample_def_or_ref(struct labcomm_decoder *d, int kind) { @@ -200,16 +227,21 @@ static int decode_sample_def_or_ref(struct labcomm_decoder *d, int kind) goto free_signature_signature; } } - if (kind == LABCOMM_SAMPLE_DEF) { - result = handle_sample_def(d, remote_index, &signature); - } else if (kind == LABCOMM_SAMPLE_REF) { - result = handle_sample_ref(d, remote_index, &signature); - if (result == -ENOENT) { - /* Dummy value to silently continue */ - result = LABCOMM_SAMPLE_REF; - } - } else { - result = -EINVAL; + switch (kind) { + case LABCOMM_SAMPLE_DEF: { + result = handle_sample_def(d, remote_index, &signature); + break; + } + case LABCOMM_SAMPLE_REF: { + result = handle_sample_ref(d, remote_index, &signature); + if (result == -ENOENT) { + /* Dummy value to silently continue */ + result = LABCOMM_SAMPLE_REF; + } + break; + } + default: + result = -EINVAL; } free_signature_signature: labcomm_memory_free(d->memory, 1, signature.signature); @@ -249,18 +281,6 @@ static void reader_alloc(struct labcomm_decoder *d) } } -static int decoder_skip(struct labcomm_decoder *d, int len, int tag) -{ - int i; - printf("got tag 0x%x, skipping %d bytes\n", tag, len); - for(i = 0; i <len; i++){ - labcomm_read_byte(d->reader); - if (d->reader->error < 0) { - return d->reader->error; - } - } - return tag; -} /* d - decoder to read from registry - decoder to lookup signatures (registry != d only if nesting decoders, e.g., when decoding pragma) @@ -368,17 +388,29 @@ int labcomm_decoder_decode_one(struct labcomm_decoder *d) } labcomm_memory_free(d->memory, 1, version); } else if (! d->version_ok) { - fprintf(stderr, "No VERSION %d %d\n", remote_index, length); + DEBUG_FPRINTF(stderr, "No VERSION %d %d\n", remote_index, length); result = -ECONNRESET; } else if (remote_index == LABCOMM_SAMPLE_DEF) { result = decode_sample_def_or_ref(d, LABCOMM_SAMPLE_DEF); } else if (remote_index == LABCOMM_SAMPLE_REF) { result = decode_sample_def_or_ref(d, LABCOMM_SAMPLE_REF); + } else if (remote_index == LABCOMM_TYPE_DEF) { + result = decode_and_handle(d, d, remote_index); + if(result == -ENOENT) { + //No handler for type_defs, skip + result = decoder_skip(d, length, remote_index); + } + } else if (remote_index == LABCOMM_TYPE_BINDING) { + result = decode_and_handle(d, d, remote_index); + if(result == -ENOENT) { + //No handler for type_bindings, skip + result = decoder_skip(d, length, remote_index); + } } else if (remote_index == LABCOMM_PRAGMA) { result = decode_pragma(d, d, length); } else if (remote_index < LABCOMM_USER) { - fprintf(stderr, "SKIP %d %d\n", remote_index, length); - result = remote_index; + DECODER_DEBUG_FPRINTF(stderr, "SKIP %d %d\n", remote_index, length); + result = decoder_skip(d, length, remote_index); } else { result = decode_and_handle(d, d, remote_index); } @@ -453,6 +485,133 @@ int labcomm_internal_decoder_ioctl(struct labcomm_decoder *d, return result; } +#ifndef LABCOMM_NO_TYPEDECL +//// Code for allowing user code to handle type_defs +//// (should perhaps be moved to another file) + +static void decode_raw_type_def( + struct labcomm_reader *r, + void (*handle)( + struct labcomm_raw_type_def *v, + void *context + ), + void *context +) +{ + struct labcomm_raw_type_def v; + v.index = labcomm_read_packed32(r); + if (r->error < 0) { goto out; } + v.name = labcomm_read_string(r); + if (r->error < 0) { goto free_name; } + v.length = labcomm_read_packed32(r); + if (r->error < 0) { goto free_name; } + int i; + v.signature_data = labcomm_memory_alloc(r->memory, 1, v.length); + if(v.signature_data) { + for(i=0; i<v.length; i++) { + v.signature_data[i] = labcomm_read_byte(r); + if (r->error < 0) { goto free_sig; } + } + handle(&v, context); + } +free_sig: + labcomm_memory_free(r->memory, 1, v.signature_data); +free_name: + labcomm_memory_free(r->memory, 1, v.name); +out: + return; +} +int labcomm_decoder_register_labcomm_type_def( + struct labcomm_decoder *d, + void (*handler)( + struct labcomm_raw_type_def *v, + void *context + ), + void *context +) +{ + int tag = LABCOMM_TYPE_DEF; + struct sample_entry *entry; + int *remote_to_local; + + labcomm_scheduler_data_lock(d->scheduler); + entry = LABCOMM_SIGNATURE_ARRAY_REF(d->memory, + d->local, struct sample_entry, + tag); + if (entry == NULL) { tag = -ENOMEM; goto unlock; } + entry->remote_index = tag; + entry->signature = NULL; + entry->decode = (labcomm_decoder_function) decode_raw_type_def; + entry->handler =(labcomm_handler_function) handler; + entry->context = context; + + remote_to_local = LABCOMM_SIGNATURE_ARRAY_REF(d->memory, + d->remote_to_local, int, + tag); + *remote_to_local = tag; +unlock: + labcomm_scheduler_data_unlock(d->scheduler); + + return tag; +} + + +static void decode_type_binding( + struct labcomm_reader *r, + void (*handle)( + struct labcomm_type_binding *v, + void *context + ), + void *context +) +{ + struct labcomm_type_binding v; + v.sample_index = labcomm_read_packed32(r); + if (r->error < 0) { goto out; } + v.type_index = labcomm_read_packed32(r); + if (r->error < 0) { goto out; } + handle(&v, context); +out: + return; +} + +int labcomm_decoder_register_labcomm_type_binding( + struct labcomm_decoder *d, + void (*handler)( + struct labcomm_type_binding *v, + void *context + ), + void *context +) +{ + int tag = LABCOMM_TYPE_BINDING; + struct sample_entry *entry; + int *remote_to_local; + + labcomm_scheduler_data_lock(d->scheduler); + entry = LABCOMM_SIGNATURE_ARRAY_REF(d->memory, + d->local, struct sample_entry, + tag); + if (entry == NULL) { tag = -ENOMEM; goto unlock; } + entry->remote_index = tag; + entry->signature = NULL; + entry->decode = (labcomm_decoder_function) decode_type_binding; + entry->handler =(labcomm_handler_function) handler; + entry->context = context; + + remote_to_local = LABCOMM_SIGNATURE_ARRAY_REF(d->memory, + d->remote_to_local, int, + tag); + *remote_to_local = tag; +unlock: + labcomm_scheduler_data_unlock(d->scheduler); + + return tag; +} + +//// End type_def handling +#endif + int labcomm_internal_decoder_register( struct labcomm_decoder *d, const struct labcomm_signature *signature, diff --git a/lib/c/2014/labcomm_encoder.c b/lib/c/2014/labcomm_encoder.c index 4085bbd38c30a93af55714f54ead443ebaf563a3..4b71ed03285dfd9dfc1de13f29c4c02705d12794 100644 --- a/lib/c/2014/labcomm_encoder.c +++ b/lib/c/2014/labcomm_encoder.c @@ -24,6 +24,10 @@ #include "labcomm.h" #include "labcomm_private.h" #include "labcomm_ioctl.h" +#include "labcomm_dynamic_buffer_writer.h" + +//define the following to disable encoding of typedefs +#undef LABCOMM_WITHOUT_TYPE_DEFS struct labcomm_encoder { struct labcomm_writer *writer; @@ -32,13 +36,15 @@ struct labcomm_encoder { struct labcomm_scheduler *scheduler; LABCOMM_SIGNATURE_ARRAY_DEF(registered, int); LABCOMM_SIGNATURE_ARRAY_DEF(sample_ref, int); + LABCOMM_SIGNATURE_ARRAY_DEF(typedefs, int); }; -struct labcomm_encoder *labcomm_encoder_new( +static struct labcomm_encoder *internal_encoder_new( struct labcomm_writer *writer, struct labcomm_error_handler *error, struct labcomm_memory *memory, - struct labcomm_scheduler *scheduler) + struct labcomm_scheduler *scheduler, + labcomm_bool outputVer) { struct labcomm_encoder *result; @@ -58,25 +64,31 @@ struct labcomm_encoder *labcomm_encoder_new( result->scheduler = scheduler; LABCOMM_SIGNATURE_ARRAY_INIT(result->registered, int); LABCOMM_SIGNATURE_ARRAY_INIT(result->sample_ref, int); + LABCOMM_SIGNATURE_ARRAY_INIT(result->typedefs, int); labcomm_writer_alloc(result->writer, result->writer->action_context); - labcomm_writer_start(result->writer, - result->writer->action_context, - LABCOMM_VERSION, NULL, CURRENT_VERSION); - labcomm_write_packed32(result->writer, LABCOMM_VERSION); -#ifdef LENGTH_INCL_TAG - length = (labcomm_size_packed32(LABCOMM_VERSION) + - labcomm_size_string(CURRENT_VERSION)); -#else - length = labcomm_size_string(CURRENT_VERSION); -#endif - labcomm_write_packed32(result->writer, length); - labcomm_write_string(result->writer, CURRENT_VERSION); - labcomm_writer_end(result->writer, result->writer->action_context); + if(outputVer) { + labcomm_writer_start(result->writer, + result->writer->action_context, + LABCOMM_VERSION, NULL, CURRENT_VERSION); + labcomm_write_packed32(result->writer, LABCOMM_VERSION); + length = labcomm_size_string(CURRENT_VERSION); + labcomm_write_packed32(result->writer, length); + labcomm_write_string(result->writer, CURRENT_VERSION); + labcomm_writer_end(result->writer, result->writer->action_context); + } } return result; } +struct labcomm_encoder *labcomm_encoder_new( + struct labcomm_writer *writer, + struct labcomm_error_handler *error, + struct labcomm_memory *memory, + struct labcomm_scheduler *scheduler) +{ + return internal_encoder_new(writer,error,memory,scheduler,TRUE); +} void labcomm_encoder_free(struct labcomm_encoder* e) { struct labcomm_memory *memory = e->memory; @@ -84,6 +96,7 @@ void labcomm_encoder_free(struct labcomm_encoder* e) labcomm_writer_free(e->writer, e->writer->action_context); LABCOMM_SIGNATURE_ARRAY_FREE(e->memory, e->registered, int); LABCOMM_SIGNATURE_ARRAY_FREE(e->memory, e->sample_ref, int); + LABCOMM_SIGNATURE_ARRAY_FREE(e->memory, e->typedefs, int); labcomm_memory_free(memory, 0, e); } @@ -99,9 +112,10 @@ int labcomm_internal_encoder_register( labcomm_scheduler_writer_lock(e->scheduler); if (index <= 0) { goto out; } done = LABCOMM_SIGNATURE_ARRAY_REF(e->memory, e->registered, int, index); - if (*done) { goto out; } - *done = 1; - err = labcomm_writer_start(e->writer, e->writer->action_context, + if (*done) { + goto out; } + *done = 1; + err = labcomm_writer_start(e->writer, e->writer->action_context, index, signature, NULL); if (err == -EALREADY) { result = 0; goto out; } if (err != 0) { result = err; goto out; } @@ -139,7 +153,11 @@ int labcomm_internal_encode( index = labcomm_get_local_index(signature); length = (signature->encoded_size(value)); labcomm_scheduler_writer_lock(e->scheduler); - result = labcomm_writer_start(e->writer, e->writer->action_context, + if (! LABCOMM_SIGNATURE_ARRAY_GET(e->registered, int, index, 0)) { + result = -EINVAL; + goto no_end; + } + result = labcomm_writer_start(e->writer, e->writer->action_context, index, signature, value); if (result == -EALREADY) { result = 0; goto no_end; } if (result != 0) { goto out; } @@ -167,8 +185,8 @@ int labcomm_encoder_sample_ref_register( done = LABCOMM_SIGNATURE_ARRAY_REF(e->memory, e->sample_ref, int, index); if (*done) { goto out; } - *done = 1; - err = labcomm_writer_start(e->writer, e->writer->action_context, + *done = 1; + err = labcomm_writer_start(e->writer, e->writer->action_context, index, signature, NULL); if (err == -EALREADY) { result = 0; goto out; } if (err != 0) { result = err; goto out; } @@ -195,20 +213,20 @@ out: return result; } -int labcomm_encoder_ioctl(struct labcomm_encoder *encoder, +int labcomm_encoder_ioctl(struct labcomm_encoder *encoder, uint32_t action, ...) { int result; va_list va; - + if (LABCOMM_IOC_SIG(action) != LABCOMM_IOC_NOSIG) { result = -EINVAL; goto out; } - + va_start(va, action); - result = labcomm_writer_ioctl(encoder->writer, + result = labcomm_writer_ioctl(encoder->writer, encoder->writer->action_context, 0, NULL, action, va); va_end(va); @@ -217,7 +235,7 @@ out: return result; } -int labcomm_internal_encoder_ioctl(struct labcomm_encoder *encoder, +int labcomm_internal_encoder_ioctl(struct labcomm_encoder *encoder, const struct labcomm_signature *signature, uint32_t action, va_list va) { @@ -225,8 +243,8 @@ int labcomm_internal_encoder_ioctl(struct labcomm_encoder *encoder, int index; index = labcomm_get_local_index(signature); - result = labcomm_writer_ioctl(encoder->writer, - encoder->writer->action_context, + result = labcomm_writer_ioctl(encoder->writer, + encoder->writer->action_context, index, signature, action, va); return result; } @@ -245,3 +263,136 @@ int labcomm_internal_encoder_signature_to_index( return index; } + +/********************************************************** + * Start of code related to sending (hierarchical) + * typedefs. Define LABCOMM_WITHOUT_TYPEDEFS to disable + **********************************************************/ +#ifndef LABCOMM_WITHOUT_TYPE_DEFS + +static void write_sig_tree_byte(char b, const struct labcomm_signature *signature, + void *context) +{ + struct labcomm_encoder *e = context; + if(signature) { + labcomm_write_packed32(e->writer, labcomm_get_local_index(signature)); + }else { + if (e->writer->pos >= e->writer->count) { + labcomm_writer_flush(e->writer, e->writer->action_context); + } + e->writer->data[e->writer->pos] = b; + e->writer->pos++; + } +} + +static void do_write_signature(struct labcomm_encoder * e, + const struct labcomm_signature *signature, + unsigned char flatten) +{ + map_signature(write_sig_tree_byte, e, signature, flatten); +} + +static void sig_size(char b, const struct labcomm_signature *signature, + void *context) +{ + int *result = context; + int diff; + if(signature) { + int idx = labcomm_get_local_index(signature); + diff = labcomm_size_packed32(idx); + }else { + diff = 1; + } + (*result)+=diff; +} + +static int calc_sig_encoded_size(struct labcomm_encoder *e, + const struct labcomm_signature *sig) +{ + int result=0; + map_signature(sig_size, &result, sig, FALSE); + return result; +} + +static int internal_reg_type( + struct labcomm_encoder *e, + const struct labcomm_signature *signature, + labcomm_bool flatten) +{ + int result = -EINVAL; + int index, *done, err; + + index = labcomm_get_local_index(signature); + labcomm_scheduler_writer_lock(e->scheduler); + if (index <= 0) { goto out; } + done = LABCOMM_SIGNATURE_ARRAY_REF(e->memory, e->typedefs, int, index); + if (*done) { goto out; } + *done = 1; + err = labcomm_writer_start(e->writer, e->writer->action_context, + index, signature, NULL); + if (err == -EALREADY) { result = 0; goto out; } + if (err != 0) { result = err; goto out; } + + int sig_size = calc_sig_encoded_size(e, signature); + int len = labcomm_size_packed32(index) + + labcomm_size_string(signature->name) + + labcomm_size_packed32(sig_size) + + sig_size; + + labcomm_write_packed32(e->writer, LABCOMM_TYPE_DEF); + labcomm_write_packed32(e->writer, len); + labcomm_write_packed32(e->writer, index); + labcomm_write_string(e->writer, signature->name); + labcomm_write_packed32(e->writer, sig_size); + do_write_signature(e, signature, FALSE); + + labcomm_writer_end(e->writer, e->writer->action_context); + result = e->writer->error; +out: + labcomm_scheduler_writer_unlock(e->scheduler); + return result; +} +#endif + +int labcomm_internal_encoder_type_register( + struct labcomm_encoder *e, + const struct labcomm_signature *signature) +{ +#ifndef LABCOMM_WITHOUT_TYPE_DEFS + return internal_reg_type(e, signature, FALSE); +#else + return 0; +#endif +} +int labcomm_internal_encoder_type_bind( + struct labcomm_encoder *e, + const struct labcomm_signature *signature, + char has_deps) +{ +#ifndef LABCOMM_WITHOUT_TYPE_DEFS + int result = -EINVAL; + int err; + int sindex = labcomm_get_local_index(signature); + int tindex = has_deps ? labcomm_get_local_type_index(signature) : LABCOMM_BIND_SELF; + labcomm_scheduler_writer_lock(e->scheduler); + if(sindex <= 0 || (has_deps && tindex <= 0)) {goto out;} + err = labcomm_writer_start(e->writer, e->writer->action_context, + LABCOMM_TYPE_BINDING, signature, NULL); + if (err == -EALREADY) { result = 0; goto out; } + if (err != 0) { result = err; goto out; } + int length = (labcomm_size_packed32(sindex) + + labcomm_size_packed32(tindex)); + labcomm_write_packed32(e->writer, LABCOMM_TYPE_BINDING); + labcomm_write_packed32(e->writer, length); + labcomm_write_packed32(e->writer, sindex); + labcomm_write_packed32(e->writer, tindex); + labcomm_writer_end(e->writer, e->writer->action_context); + result = e->writer->error; + +out: + labcomm_scheduler_writer_unlock(e->scheduler); + return result; +#else + return 0; +#endif +} diff --git a/lib/c/2014/labcomm_private.h b/lib/c/2014/labcomm_private.h index 8ed93ce02c11d33e423be5332481eae6fa6360b2..1cef97dc4cec3abc311e040517d189b2aa10a6e3 100644 --- a/lib/c/2014/labcomm_private.h +++ b/lib/c/2014/labcomm_private.h @@ -42,8 +42,8 @@ #define LABCOMM_VERSION 0x01 #define LABCOMM_SAMPLE_DEF 0x02 #define LABCOMM_SAMPLE_REF 0x03 -#define LABCOMM_TYPEDEF 0x04 -#define LABCOMM_TYPEBINDING 0x05 +#define LABCOMM_TYPE_DEF 0x04 +#define LABCOMM_TYPE_BINDING 0x05 #define LABCOMM_PRAGMA 0x3f #define LABCOMM_USER 0x40 /* ..0xffffffff */ @@ -66,6 +66,11 @@ #define LABCOMM_STRING 0x27 #define LABCOMM_REF 0x28 +/* + * other special values + */ + +#define LABCOMM_BIND_SELF 0 /* * Macro to automagically call constructors in modules compiled @@ -365,6 +370,15 @@ int labcomm_writer_ioctl(struct labcomm_writer *w, int index, const struct labcomm_signature *signature, uint32_t ioctl_action, va_list args); +int labcomm_internal_encoder_type_register( + struct labcomm_encoder *e, + const struct labcomm_signature *signature); + +int labcomm_internal_encoder_type_bind( + struct labcomm_encoder *e, + const struct labcomm_signature *signature, + char has_deps); + int labcomm_internal_encoder_register( struct labcomm_encoder *encoder, const struct labcomm_signature *signature, @@ -544,4 +558,6 @@ void labcomm_set_local_index(struct labcomm_signature *signature); /* Get the local index for a signature */ int labcomm_get_local_index(const struct labcomm_signature *s); +int labcomm_get_local_type_index(const struct labcomm_signature *s); + #endif diff --git a/lib/c/2014/labcomm_type_signature.c b/lib/c/2014/labcomm_type_signature.c new file mode 100644 index 0000000000000000000000000000000000000000..3cb9cc36e266b32977491b049fea0a1141234f6a --- /dev/null +++ b/lib/c/2014/labcomm_type_signature.c @@ -0,0 +1,128 @@ +#include "labcomm.h" +#include <string.h> // for memcmp +#include <stdio.h> // for debug printf + +/* Dump signature bytes on stdout + */ + +void labcomm_signature_print(struct labcomm_signature_data *signature) +{ + struct labcomm_signature_data *p = signature ; + while (p->length != -1) { + if (p->length) { + int i; + for ( i = 0 ; i < p->length ; i++) { + printf("%02x ", p->u.bytes[i]); + } + } else if(p->u.signature){ + labcomm_signature_print(p->u.signature->treedata); + } else { + printf("neither data nor ref, bailing out.\n"); + return; + } + p+=1; + } + printf("\n"); +} +static labcomm_bool sig_dump_checked(struct labcomm_signature_data *signature, + char *buf, int *len, int buflen); + +/* buf (out) : byte array to write signature into + len (in/out): input: buf size, out: signature length + + return TRUE if aborted due to overrun + */ +labcomm_bool labcomm_signature_dump(struct labcomm_signature_data *signature, + char *buf, int *len) +{ + int buflen = *len; + *len = 0; + return sig_dump_checked(signature, buf, len, buflen); +} + +/* internal function with bounds checking for buf. + * buflen: capacity of buf + */ +static labcomm_bool sig_dump_checked(struct labcomm_signature_data *signature, + char *buf, int *len, int buflen) +{ + struct labcomm_signature_data *p = signature; + while ( (p->length != -1) && (*len < buflen)) { + if (p->length) { + int i; + for ( i = 0 ; (i < p->length) && (*len < buflen); i++) { + *buf++ = p->u.bytes[i]; + ++*len; + } + } else if(p->u.signature){ + int tmplen=*len; + //recursing. c.f. dump() + sig_dump_checked(p->u.signature->treedata, buf, len, buflen); + int inner_len = *len-tmplen; + buf += inner_len; + } else { + //printf("neither data nor ref, bailing out.\n"); + return TRUE; + } + p+=1; + } + return (*len >= buflen); +} + +/* compare signature (flattened, if needed) to other + return TRUE if equal +*/ +labcomm_bool labcomm_signature_cmp( struct labcomm_signature_data *s1, + struct labcomm_signature_data *s2) +{ + int buflen=512; + char buf1[buflen]; + int len1=buflen; + char buf2[buflen]; + int len2=buflen; + labcomm_bool res1 = labcomm_signature_dump(s1, buf1, &len1); + labcomm_bool res2 = labcomm_signature_dump(s2, buf2, &len2); + if(res1 || res2) { + printf("WARNING: OVERRUN\n"); + return FALSE; + } else { + return(len1 == len2 && memcmp(buf1, buf2, len1)==0); + } +} +/* maps a function f(char b, struct labcomm_signature *s, void *context) + * on each byte (or type ref) in the signature. + * + * If flatten, the signature is flattened to a byte array, and the + * second argument to f is always zero. + * + * Otherwise, when a type ref is encountered, f is called with the first + * argument zero and the referenced type as the second argument. + * + * The context parameter is passed on, unaltered, to f + */ +void map_signature( void(*f)(char, const struct labcomm_signature *, void *), + void *context, + const struct labcomm_signature *signature, labcomm_bool flatten) +{ + struct labcomm_signature_data* p = signature->treedata; + while (p->length != -1) { + //fprintf(stderr, "%p %x\n", p, p->length); + if (p->length) { + int i; + for ( i = 0 ; i < p->length ; i++) { + (*f)(p->u.bytes[i], 0, context); + } + } else if (p->u.signature) { + if(p->u.signature == 0) printf("p->u.signature == null\n"); + if(flatten) { + map_signature(f, context, p->u.signature, flatten); + } else { + (*f)(0, p->u.signature, context); + } + } else { + fprintf(stderr, "neither data nor ref, bailing out.\n"); + return; + } + p+=1; + } +} diff --git a/lib/c/2014/labcomm_type_signature.h b/lib/c/2014/labcomm_type_signature.h new file mode 100644 index 0000000000000000000000000000000000000000..e556589b3c80fc87227d1f7b66e7a72a74d61edb --- /dev/null +++ b/lib/c/2014/labcomm_type_signature.h @@ -0,0 +1,139 @@ +#ifndef LABCOMM_TYPE_SIGNATURE_H +#define LABCOMM_TYPE_SIGNATURE_H + +//XXX move to common.h +#ifndef labcomm_bool +#define labcomm_bool char +#define TRUE 1 +#define FALSE 0 +#endif + +/* + * Signature entry + */ +#ifndef LABCOMM_NO_TYPEDECL +#ifdef USE_UNIONS + +/* Useful for C99 and up (or GCC without -pedantic) */ + +#define LABCOMM_SIGDEF_BYTES_OR_SIGNATURE \ + union { \ + char *bytes; \ + struct labcomm_signature* signature; \ + } u; + +#define LABCOMM_SIGDEF_BYTES(l, b) { l, .u.bytes=b } +#define LABCOMM_SIGDEF_SIGNATURE(s) { 0, .u.signature=&s } // addressof, as s is pointing at the sig struct, not directly the the sig_bytes[] +#define LABCOMM_SIGDEF_END { -1, .u.bytes=0 } + +#else + +#define LABCOMM_SIGDEF_BYTES_OR_SIGNATURE \ + struct { \ + char *bytes; \ + const struct labcomm_signature *signature; \ + } u; + +#define LABCOMM_SIGDEF_BYTES(l, b) { l, { b, 0 } } +#define LABCOMM_SIGDEF_SIGNATURE(s) { 0, { 0, &s } } +#define LABCOMM_SIGDEF_END { -1, { 0, 0 } } + +#endif + +struct labcomm_signature_data { + int length; + LABCOMM_SIGDEF_BYTES_OR_SIGNATURE +}; + +#endif +struct labcomm_signature { + char *name; + int (*encoded_size)(void *); /* void* refers to sample_data */ + int size; + unsigned char *signature; + int index; +#ifndef LABCOMM_NO_TYPEDECL + int tdsize; + struct labcomm_signature_data *treedata; +#endif +#ifdef LABCOMM_EXPERIMENTAL_CACHED_ENCODED_SIZE + int cached_encoded_size; // -1 if not initialized or type is variable size +#endif +}; + +/* a struct for "raw" type_defs, to be used as an intermediate representation + * between decoder and signature parser + */ + +struct labcomm_raw_type_def { + char *name; + int index; + int length; + char *signature_data; +}; + +/* a struct for type bindings + */ + +struct labcomm_type_binding { + int sample_index; + int type_index; +}; + +/* + * functions + */ + + +/* register a handler for type_defs and type bindings + */ + +int labcomm_decoder_register_labcomm_type_def( + struct labcomm_decoder *d, + void (*handler)( + struct labcomm_raw_type_def *v, + void *context + ), + void *context +); + +int labcomm_decoder_register_labcomm_type_binding( + struct labcomm_decoder *d, + void (*handler)( + struct labcomm_type_binding *v, + void *context + ), + void *context +); + +/* Dump signature bytes on stdout + */ + +void labcomm_signature_print(struct labcomm_signature_data *signature); + +/* compare signatures (flattened, if needed) to other +* return TRUE if equal +*/ +labcomm_bool labcomm_signature_cmp( struct labcomm_signature_data *s2, + struct labcomm_signature_data *s1); + +/* flatten and dump signature to a byte array. + * buf (out) : byte array to write signature into + * len (in/out): input: buf size, out: signature length + * + * return TRUE if aborted due to overrun + */ +labcomm_bool labcomm_signature_dump(struct labcomm_signature_data *signature, + char *buf, int *len); + +/* maps function f on each byte in the signature + * if flatten, the signature is flattened, and the second argument of + * f is always zero + * otherwise, when a type ref is encountered, f is called with the first + * argument zero and the type ref as the second argument. + */ +void map_signature( void(*f)(char, const struct labcomm_signature *, void *), + void *context, + const struct labcomm_signature *signature, labcomm_bool flatten); + +#endif diff --git a/lib/c/2014/test/generated_encoding.lc b/lib/c/2014/test/generated_encoding.lc index e561abee3d5bacbdd502fed94a013ed829bfe46f..4055562aaa48c83c9e92c7d1f008f13ab0468039 100644 --- a/lib/c/2014/test/generated_encoding.lc +++ b/lib/c/2014/test/generated_encoding.lc @@ -1,4 +1,5 @@ -sample void V; +typedef void v_t; +sample v_t V; sample byte B; sample struct { int i; diff --git a/lib/c/2014/test/test_labcomm.c b/lib/c/2014/test/test_labcomm.c index e37950e612d3ffb38c08bdec4b31c0325cb851a7..c8526776e98ea640a92ac6305dd97d2e87c05f60 100644 --- a/lib/c/2014/test/test_labcomm.c +++ b/lib/c/2014/test/test_labcomm.c @@ -30,6 +30,44 @@ #include "labcomm_default_scheduler.h" #include "test/gen/test_sample.h" +static struct labcomm_writer writer; + +static struct expect { + char *description; + int result; + int (*trampoline)(struct labcomm_decoder *context); + struct labcomm_decoder *context; +} *expect; + +static void check_expect() +{ + struct expect *p = expect; + + { + int i; + for (i = 0 ; i < writer.pos ; i++) { + fprintf(stderr, "%02x ", writer.data[i]); + } + fprintf(stderr, "\n"); + } + if (p && p->trampoline) { + int err; + + expect = p + 1; + fprintf(stderr, "Checking '%s' expected=%d ", p->description, p->result); + err = p->trampoline(p->context); + fprintf(stderr, "actual=%d\n", err); + if (p->result >= 0 && p->result != err) { + fprintf(stderr, "FAILED\n"); + exit(1); + } else if (err == 0) { + fprintf(stderr, "FAILED (unexpected 0)\n"); + exit(1); + } + writer.pos = 0; + } +} + static unsigned char buffer[512]; static int writer_alloc(struct labcomm_writer *w, @@ -41,6 +79,7 @@ static int writer_alloc(struct labcomm_writer *w, return 0; } + static int writer_start(struct labcomm_writer *w, struct labcomm_writer_action_context *action_context, int index, const struct labcomm_signature *signature, @@ -48,15 +87,27 @@ static int writer_start(struct labcomm_writer *w, { return 0; } + +static int buf_writer_end( + struct labcomm_writer *w, + struct labcomm_writer_action_context *action_context) +{ + check_expect(); + return 0; +} + const struct labcomm_writer_action writer_action = { .alloc = writer_alloc, .start = writer_start, + .end = buf_writer_end, }; + static struct labcomm_writer_action_context writer_action_context = { .next = NULL, .action = &writer_action, .context = NULL }; + static struct labcomm_writer writer = { .action_context = &writer_action_context, .data = buffer, @@ -76,21 +127,25 @@ static int reader_alloc(struct labcomm_reader *r, return 0; } + static int reader_fill(struct labcomm_reader *r, struct labcomm_reader_action_context *action_context) { r->error = -ENOMEM; return r->error; } + const struct labcomm_reader_action reader_action = { .alloc = reader_alloc, .fill = reader_fill, }; + static struct labcomm_reader_action_context reader_action_context = { .next = NULL, .action = &reader_action, .context = NULL }; + static struct labcomm_reader reader = { .action_context = &reader_action_context, .data = buffer, @@ -106,6 +161,7 @@ static test_sample_test_var encoder_var = { .n_2 = 1, .a = encoder_data, }; + static int32_t decoder_data[256]; static test_sample_test_var decoder_var = { .n_0 = 1, @@ -127,8 +183,9 @@ int test_decode_one(struct labcomm_decoder *decoder) reader.pos = 0; result = labcomm_decoder_decode_one(decoder); if (result >= 0 ) { - fprintf(stderr, "Got result from buffer with bogus length (%d)\n", - result); + fprintf(stderr, + "Got result from buffer with bogus length (%d, %d != %d)\n", + result, reader.count, writer.pos); exit(1); } } @@ -137,7 +194,7 @@ int test_decode_one(struct labcomm_decoder *decoder) reader.count = writer.pos; result = labcomm_decoder_decode_one(decoder); if (result < 0) { - fprintf(stderr, "Got result from buffer with correct length (%d)\n", + fprintf(stderr, "Got no result from buffer with correct length (%d)\n", result); exit(1); } @@ -174,26 +231,35 @@ static void test_encode_decode(struct labcomm_encoder *encoder, int main(void) { - int err, i; - struct labcomm_encoder *encoder = labcomm_encoder_new( - &writer, + int i; + struct labcomm_decoder *decoder = labcomm_decoder_new( + &reader, labcomm_default_error_handler, labcomm_default_memory, labcomm_default_scheduler); - struct labcomm_decoder *decoder = labcomm_decoder_new( - &reader, + struct expect expect_version[] = { + { "Version", 1, test_decode_one, decoder }, + { 0, 0, 0 } + }; + expect = expect_version; + struct labcomm_encoder *encoder = labcomm_encoder_new( + &writer, labcomm_default_error_handler, labcomm_default_memory, labcomm_default_scheduler); - err = test_decode_one(decoder); - fprintf(stderr, "decode of version -> index %d\n", err); - writer.pos = 0; labcomm_decoder_register_test_sample_test_var(decoder, handle_test_var, NULL); + struct expect expect_registration[] = { + { "Sampledef", -1, test_decode_one, decoder }, +#ifdef SHOULD_THIS_BE_REMOVED + { "Typedef", -1, test_decode_one, decoder }, +#endif + { "Binding", -1, test_decode_one, decoder }, + { 0, 0, 0 } + }; + expect = expect_registration; labcomm_encoder_register_test_sample_test_var(encoder); - err = test_decode_one(decoder); - fprintf(stderr, "decode of register -> index %d\n", err); test_encode_decode(encoder, decoder, 12, 1, 1); if (decoder_var.a[0] != encoder_var.a[0]) { fprintf(stderr, "Failed to decode correct value %d != %d\n", diff --git a/lib/c/2014/test/test_labcomm_copy.c b/lib/c/2014/test/test_labcomm_copy.c index 728195582a491be649adcb05c4aaa3c930456f69..9261e666cd723d47ddcc97714b4c374eee55f001 100644 --- a/lib/c/2014/test/test_labcomm_copy.c +++ b/lib/c/2014/test/test_labcomm_copy.c @@ -199,6 +199,7 @@ int main(int argc, char **argv) while (labcomm_decoder_decode_one(decoder) > 0) ; + printf("cache_s1.i = %d, s1.i = %d\n", cache_s1.i, s1.i); assert(cache_s1.i == s1.i); puts("S1 copied ok"); diff --git a/lib/c/2014/test/test_labcomm_generated_encoding.c b/lib/c/2014/test/test_labcomm_generated_encoding.c index 58462aa0b4dd62a319ef60004ccf37db05a84a30..11f9d7c32fd492543a9ab017a279c85ec369c413 100644 --- a/lib/c/2014/test/test_labcomm_generated_encoding.c +++ b/lib/c/2014/test/test_labcomm_generated_encoding.c @@ -32,8 +32,21 @@ #define IOCTL_WRITER_ASSERT_BYTES 4096 #define IOCTL_WRITER_RESET 4097 +#define EXPECT(...) \ + { \ + int expected[] = __VA_ARGS__; \ + labcomm_encoder_ioctl(encoder, IOCTL_WRITER_ASSERT_BYTES, \ + __LINE__, \ + sizeof(expected)/sizeof(expected[0]), \ + expected); \ + } + +#define VARIABLE(i) -(i + 1) +#define IS_VARIABLE(i) (i < 0) + static unsigned char buffer[128]; struct labcomm_writer *writer; +static int seen_variable[1024]; static int buf_writer_alloc( struct labcomm_writer *w, @@ -96,13 +109,23 @@ static int buf_writer_ioctl( int *expected = va_arg(arg, int *); int i, mismatch; + mismatch = 0; if (w->pos != count) { - fprintf(stderr, "Invalid length encoded %d != %d (%s:%d)\n", + fprintf(stderr, "Invalid length detected %d != %d (%s:%d)\n", w->pos, count, __FILE__, line); mismatch = 1; } - for (mismatch = 0, i = 0 ; i < count ; i++) { - if (expected[i] >= 0 && expected[i] != buffer[i]) { + for (i = 0 ; i < count ; i++) { + if (IS_VARIABLE(expected[i])) { + if (seen_variable[VARIABLE(expected[i])] == -1) { + seen_variable[VARIABLE(expected[i])] = buffer[i]; + } + if (seen_variable[VARIABLE(expected[i])] != buffer[i]) { + fprintf(stderr, "Unexpected variable (%d: != %d)\n", + seen_variable[VARIABLE(expected[i])], buffer[i]); + mismatch = 1; + } + } else if (expected[i] != buffer[i]) { mismatch = 1; } } @@ -116,7 +139,7 @@ static int buf_writer_ioctl( printf("\n"); for (i = 0 ; i < count ; i++) { if (expected[i] < 0) { - printf(".. "); + printf("v%d ", VARIABLE(expected[i])); } else { printf("%2.2x ", expected[i] ); } @@ -167,21 +190,18 @@ void dump_encoder(struct labcomm_encoder *encoder) printf("\n"); } -#define EXPECT(...) \ - { \ - int expected[] = __VA_ARGS__; \ - labcomm_encoder_ioctl(encoder, IOCTL_WRITER_ASSERT_BYTES, \ - __LINE__, \ - sizeof(expected)/sizeof(expected[0]), \ - expected); \ - } - int main(void) { generated_encoding_B B = 1; generated_encoding_R R; + struct labcomm_encoder *encoder; + int i; + + for (i = 0 ; i < sizeof(seen_variable)/sizeof(seen_variable[0]) ; i++) { + seen_variable[i] = -1; + } - struct labcomm_encoder *encoder = labcomm_encoder_new( + encoder = labcomm_encoder_new( &buffer_writer, labcomm_default_error_handler, labcomm_default_memory, @@ -193,13 +213,24 @@ int main(void) /* Register twice to make sure that only one registration gets encoded */ labcomm_encoder_register_generated_encoding_V(encoder); labcomm_encoder_register_generated_encoding_V(encoder); - EXPECT({ 0x02, 0x06, -1, 0x01, 'V', 0x02, 0x11, 0x00 }); + EXPECT({ 0x02, 0x06, VARIABLE(0), 0x01, 'V', 0x02, 0x11, 0x00, + 0x04, 0x08, VARIABLE(1), 0x03, 'v', '_', 't', 0x02, 0x11, 0x00, + 0x04, 0x05, VARIABLE(2), 0x01, 'V', 0x01, VARIABLE(1), + 0x05, 0x02, VARIABLE(0), VARIABLE(2) }); labcomm_encoder_ioctl(encoder, IOCTL_WRITER_RESET); /* Register twice to make sure that only one registration gets encoded */ labcomm_encoder_register_generated_encoding_B(encoder); labcomm_encoder_register_generated_encoding_B(encoder); - EXPECT({0x02, 0x05, -1, 0x01, 'B', 0x01, 0x21}); + EXPECT({ 0x02, 0x05, VARIABLE(3), 0x01, 'B', 0x01, 0x21, + 0x05, 0x02, VARIABLE(3), LABCOMM_BIND_SELF }); + + labcomm_encoder_ioctl(encoder, IOCTL_WRITER_RESET); + /* Register twice to make sure that only one registration gets encoded */ + labcomm_encoder_register_generated_encoding_R(encoder); + labcomm_encoder_register_generated_encoding_R(encoder); + EXPECT({ 0x02, 0x08, VARIABLE(4), 0x01, 'R', 0x04, 0x10, 0x01, 0x04, 0x28, + 0x05, 0x02, VARIABLE(4), LABCOMM_BIND_SELF }); labcomm_encoder_ioctl(encoder, IOCTL_WRITER_RESET); /* Register twice to make sure that only one registration gets encoded */ @@ -207,7 +238,7 @@ int main(void) labcomm_signature_generated_encoding_V); labcomm_encoder_sample_ref_register(encoder, labcomm_signature_generated_encoding_V); - EXPECT({0x03, 0x06, -1, 0x01, 'V', 0x02, 0x11, 0x00}); + EXPECT({0x03, 0x06, VARIABLE(5), 0x01, 'V', 0x02, 0x11, 0x00}); labcomm_encoder_ioctl(encoder, IOCTL_WRITER_RESET); /* Register twice to make sure that only one registration gets encoded */ @@ -215,7 +246,7 @@ int main(void) labcomm_signature_generated_encoding_B); labcomm_encoder_sample_ref_register(encoder, labcomm_signature_generated_encoding_B); - EXPECT({0x03, 0x05, -1, 0x01, 'B', 0x01, 0x21}); + EXPECT({0x03, 0x05, VARIABLE(6), 0x01, 'B', 0x01, 0x21}); labcomm_encoder_ioctl(encoder, IOCTL_WRITER_RESET); /* Register twice to make sure that only one registration gets encoded */ @@ -223,16 +254,16 @@ int main(void) labcomm_signature_generated_encoding_R); labcomm_encoder_sample_ref_register(encoder, labcomm_signature_generated_encoding_R); - EXPECT({0x03, 0x08, -1, 0x01, 'R', 0x04, 0x10, 0x01, 0x04, 0x28}); + EXPECT({0x03, 0x08, VARIABLE(7), 0x01, 'R', 0x04, 0x10, 0x01, 0x04, 0x28}); labcomm_encoder_ioctl(encoder, IOCTL_WRITER_RESET); // was: labcomm_encode_generated_encoding_V(encoder, &V); labcomm_encode_generated_encoding_V(encoder); - EXPECT({-1, 0x00 }); + EXPECT({VARIABLE(10), 0x00 }); labcomm_encoder_ioctl(encoder, IOCTL_WRITER_RESET); labcomm_encode_generated_encoding_B(encoder, &B); - EXPECT({-1, 0x01, 1}); + EXPECT({VARIABLE(20), 0x01, 1}); labcomm_encoder_ioctl(encoder, IOCTL_WRITER_RESET); R.a[0] = labcomm_signature_generated_encoding_V; @@ -240,10 +271,10 @@ int main(void) R.a[2] = labcomm_signature_generated_encoding_UnusedE; R.a[3] = labcomm_signature_generated_encoding_R; labcomm_encode_generated_encoding_R(encoder, &R); - EXPECT({-1, 0x10, 0x00, 0x00, 0x00, -1, - 0x00, 0x00, 0x00, -1, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, -1}); + EXPECT({VARIABLE(4), 0x10, 0x00, 0x00, 0x00, VARIABLE(5), + 0x00, 0x00, 0x00, VARIABLE(6), + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, VARIABLE(7)}); return 0; } diff --git a/lib/c/Makefile b/lib/c/Makefile index c2b23ee9f9373497e4e1ae612a99ed1ee903110a..5d36fef53c20424e93bc83107bcf83be9d64f36c 100644 --- a/lib/c/Makefile +++ b/lib/c/Makefile @@ -6,8 +6,12 @@ all: for v in $(VERSIONS) ; do $(MAKE) -C $${v} $@ || exit 1 ; done +.PHONY: clean +clean: + for v in $(VERSIONS) ; do $(MAKE) -C $${v} $@ || exit 1 ; done + .PHONY: distclean -distclean: +distclean: for v in $(VERSIONS) ; do $(MAKE) -C $${v} $@ || exit 1 ; done rm -f *.o *.so *.so.1 *.a diff --git a/lib/c/os_compat.mk b/lib/c/os_compat.mk index 23b66f2faa2e425e1fb0be3eb0f8772cdd972d60..b916df333d7ef6023694e44cecbafccb13bd6685 100644 --- a/lib/c/os_compat.mk +++ b/lib/c/os_compat.mk @@ -10,15 +10,18 @@ ifeq ($(UNAME_S),Linux) LDLIBS=-llabcomm$(LIBVERSION) -lrt MAKESHARED=gcc -o $1 -shared -Wl,-soname,$2 $3 -lc -lrt else ifeq ($(UNAME_S),Darwin) - CC=$(CROSS_COMPILE)clang - LD=$(CROSS_COMPILE)ld + #CC=$(CROSS_COMPILE)clang + #LD=$(CROSS_COMPILE)ld + CC=$(CROSS_COMPILE)gcc + LD=$(CROSS_COMPILE)gcc CFLAGS=-g -Wall -Werror -O3 -I. -Itest \ -DLABCOMM_COMPAT=\"labcomm_compat_osx.h\" \ - -DLABCOMM_OS_DARWIN=1\ - -Wno-tautological-compare -Wno-unused-function - LDFLAGS=-L.. + -DLABCOMM_OS_DARWIN=1 +# -Wno-tautological-compare -Wno-unused-function + CFLAGS+=-std=c99 + LDFLAGS=-L.. LDLIBS=-llabcomm$(LIBVERSION) - MAKESHARED=clang -o $1 -shared -Wl,-install_name,$2 $3 -lc + MAKESHARED=clang -o $1 -shared -Wl,-install_name,$2 $3 -lc else ifneq ($(findstring CYGWIN,$(UNAME_S)),) CC=$(CROSS_COMPILE)gcc LD=$(CROSS_COMPILE)ld diff --git a/lib/csharp/se/lth/control/labcomm/Constant.cs b/lib/csharp/se/lth/control/labcomm/Constant.cs index 5b247f677c6f5c79c5ce288d3a681f629eec5248..37615448d0cec858190bbb16dd9a465677a8ccbb 100644 --- a/lib/csharp/se/lth/control/labcomm/Constant.cs +++ b/lib/csharp/se/lth/control/labcomm/Constant.cs @@ -11,6 +11,7 @@ namespace se.lth.control.labcomm { public const int SAMPLE_DEF = 0x02; public const int SAMPLE_REF = 0x03; public const int TYPE_DEF = 0x04; + public const int TYPE_BINDING = 0x05; public const int PRAGMA = 0x3f; public const int FIRST_USER_INDEX = 0x40; /* ..0xffffffff */ diff --git a/lib/csharp/se/lth/control/labcomm/DecoderChannel.cs b/lib/csharp/se/lth/control/labcomm/DecoderChannel.cs index aa8662172f6cd4ed00cafaba7b44dcd5a6aa1287..99e17fbac0f6065f3364c72dddfe1bce78808cb9 100644 --- a/lib/csharp/se/lth/control/labcomm/DecoderChannel.cs +++ b/lib/csharp/se/lth/control/labcomm/DecoderChannel.cs @@ -45,6 +45,12 @@ namespace se.lth.control.labcomm { ReadBytes(signature, signature_length); ref_registry.add(index, name, signature); } break; + case Constant.TYPE_DEF: + case Constant.TYPE_BINDING: { + for(int i=0; i<length;i++){ + decodeByte(); + } + } break; default: { DecoderRegistry.Entry e = def_registry.get(tag); if (e == null) { diff --git a/lib/java/Makefile b/lib/java/Makefile index 6fb82d9891cf44c94511bc6fe73be71fb059169d..c6a483daae99e03c8cebfab5239b40ddeabc5e67 100644 --- a/lib/java/Makefile +++ b/lib/java/Makefile @@ -10,28 +10,40 @@ MODULES=Constant \ SampleDispatcher \ SampleHandler \ SampleType \ + BuiltinType \ + TypeDef \ + TypeBinding \ + ASTbuilder \ + TypeDefParser \ Writer \ WriterWrapper all: labcomm.jar labcomm2014.jar labcomm2006.jar -labcomm.jar: gen/JAVAC +labcomm.jar: gen/JAVAC osgi-manifest-all.txt echo $@ - cd gen ; jar cfm ../$@ ../osgi-manifest.txt se/lth/control/labcomm/*.class se/lth/control/labcomm2006/*.class + cd gen ; jar cfm ../$@ ../osgi-manifest-all.txt \ + se/lth/control/labcomm/*.class \ + se/lth/control/labcomm2006/*.class -labcomm2014.jar: gen/JAVAC +labcomm2014.jar: gen/JAVAC osgi-manifest-2014.txt echo $@ - cd gen ; jar cfm ../$@ ../osgi-manifest.txt se/lth/control/labcomm/*.class + cd gen ; jar cfm ../$@ ../osgi-manifest-2014.txt \ + se/lth/control/labcomm/*.class -labcomm2006.jar: gen/JAVAC +labcomm2006.jar: gen/JAVAC osgi-manifest-2006.txt echo $@ - cd gen ; jar cfm ../$@ ../osgi-manifest.txt se/lth/control/labcomm2006/*.class + cd gen ; jar cfm ../$@ ../osgi-manifest-2006.txt \ + se/lth/control/labcomm2006/*.class gen: mkdir gen -gen/JAVAC: $(MODULES:%=se/lth/control/labcomm/%.java) $(MODULES:%=se/lth/control/labcomm2006/%.java) Makefile | gen - javac -d gen $(filter %.java, $^) +gen/JAVAC: $(MODULES:%=se/lth/control/labcomm/%.java) \ + $(MODULES:%=se/lth/control/labcomm2006/%.java) \ + Makefile | gen + javac -cp ../../compiler/labcomm_compiler.jar -d gen \ + $(filter %.java, $^) touch $@ @@ -40,5 +52,5 @@ clean: rm -rf gen .PHONY: distclean -distclean: +distclean: clean rm -rf labcomm.jar labcomm2006.jar labcomm2014.jar diff --git a/lib/java/osgi-manifest-2006.txt b/lib/java/osgi-manifest-2006.txt new file mode 100644 index 0000000000000000000000000000000000000000..4ef6bdac0f7ccc0b4fe0c729b46bb81d67d36dce --- /dev/null +++ b/lib/java/osgi-manifest-2006.txt @@ -0,0 +1,7 @@ +Bundle-Description: Provides Labcomm to bundles +Bundle-ManifestVersion: 2 +Bundle-Name: Labcomm OSGi +Bundle-SymbolicName: se.lth.control.labcomm2006 +Bundle-Vendor: LTH +Bundle-Version: 1.0.0 +Export-Package: se.lth.control.labcomm2006;version="1.0.0" diff --git a/lib/java/osgi-manifest-2014.txt b/lib/java/osgi-manifest-2014.txt new file mode 100644 index 0000000000000000000000000000000000000000..53d3954c8f022190a5163fedf2421fe8795ab77d --- /dev/null +++ b/lib/java/osgi-manifest-2014.txt @@ -0,0 +1,7 @@ +Bundle-Description: Provides Labcomm 2014 to bundles +Bundle-ManifestVersion: 2 +Bundle-Name: Labcomm OSGi +Bundle-SymbolicName: se.lth.control.labcomm2014 +Bundle-Vendor: LTH +Bundle-Version: 1.0.0 +Export-Package: se.lth.control.labcomm;version="1.0.0" diff --git a/lib/java/osgi-manifest-all.txt b/lib/java/osgi-manifest-all.txt new file mode 100644 index 0000000000000000000000000000000000000000..4a691e7fffa1ae585f7c245174645f61f2b605d7 --- /dev/null +++ b/lib/java/osgi-manifest-all.txt @@ -0,0 +1,8 @@ +Bundle-Description: Provides Labcomm 2006/2014 to bundles +Bundle-ManifestVersion: 2 +Bundle-Name: Labcomm OSGi +Bundle-SymbolicName: se.lth.control.labcomm-all +Bundle-Vendor: LTH +Bundle-Version: 1.0.0 +Export-Package: se.lth.control.labcomm2006;version="1.0.0", + se.lth.control.labcomm;version="1.0.0" diff --git a/lib/java/osgi-manifest.txt b/lib/java/osgi-manifest.txt deleted file mode 100644 index 49ca3d6cd68f2212c9ab0d74a709ed38c6a2c233..0000000000000000000000000000000000000000 --- a/lib/java/osgi-manifest.txt +++ /dev/null @@ -1,8 +0,0 @@ -Bundle-Description: Provides Labcomm to bundles -Bundle-ManifestVersion: 2 -Bundle-Name: Labcomm OSGi -Bundle-SymbolicName: se.lth.control.labcomm -Bundle-Vendor: LTH -Bundle-Version: 1.0.0 -Export-Package: se.lth.control.labcomm;version="1.0.0",se.lth.control.la - bcomm2006;version="1.0.0" diff --git a/lib/java/se/lth/control/labcomm/ASTbuilder.java b/lib/java/se/lth/control/labcomm/ASTbuilder.java new file mode 100644 index 0000000000000000000000000000000000000000..73bd171750c722c910a12549f535272eafc3b5a5 --- /dev/null +++ b/lib/java/se/lth/control/labcomm/ASTbuilder.java @@ -0,0 +1,177 @@ +package se.lth.control.labcomm; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; + +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.io.EOFException; + +import se.lth.control.labcomm.TypeDef; +import se.lth.control.labcomm.TypeDefParser; + +import se.lth.control.labcomm2014.compiler.LabComm; +import se.lth.control.labcomm2014.compiler.LabCommParser; + +import se.lth.control.labcomm2014.compiler.List; +import se.lth.control.labcomm2014.compiler.Program; +import se.lth.control.labcomm2014.compiler.Decl; +import se.lth.control.labcomm2014.compiler.TypeDecl; +import se.lth.control.labcomm2014.compiler.SampleDecl; +import se.lth.control.labcomm2014.compiler.Type; +import se.lth.control.labcomm2014.compiler.VoidType; +import se.lth.control.labcomm2014.compiler.PrimType; +import se.lth.control.labcomm2014.compiler.UserType; +import se.lth.control.labcomm2014.compiler.StructType; +import se.lth.control.labcomm2014.compiler.Field; +import se.lth.control.labcomm2014.compiler.ArrayType; +import se.lth.control.labcomm2014.compiler.VariableArrayType; +import se.lth.control.labcomm2014.compiler.FixedArrayType; +import se.lth.control.labcomm2014.compiler.Dim; +import se.lth.control.labcomm2014.compiler.Exp; +import se.lth.control.labcomm2014.compiler.IntegerLiteral; +import se.lth.control.labcomm2014.compiler.VariableSize; + + +/** A class for building a JastAdd AST from the parsed types + * created by a TypeDefParser. This class depends on the LabComm compiler. + */ +public class ASTbuilder implements TypeDefParser.ParsedSymbolVisitor { + + private LinkedList<Type> typeStack; + private LinkedList<Field> fieldStack; + + public ASTbuilder() { + this.typeStack = new LinkedList<Type>(); + this.fieldStack = new LinkedList<Field>(); + } + + private void assertStacksEmpty() throws RuntimeException { + if(!typeStack.isEmpty()) { + throw new RuntimeException("Error: type stack not empty"); + } + if(!fieldStack.isEmpty()) { + throw new RuntimeException("Error: field stack not empty"); + } + } + + public void visit(TypeDefParser.TypeSymbol s){ + throw new Error("not implemented? needed?"); + + } + public void visit(TypeDefParser.SampleSymbol s){ + throw new Error("not implemented? needed?"); + + } + public void visit(TypeDefParser.NameSymbol s){ + throw new Error("not implemented? needed?"); + } + + public void visit(TypeDefParser.PrimitiveType t){ + typeStack.push(new PrimType(t.getName(), t.getTag())); + } + +// SampleRefs are currently represented as primitive types, +// see comment in TypeDefParser +// public void visit(TypeDefParser.SampleRefType t){ +// typeStack.push(new SampleRefType()); +// } + + public void visit(TypeDefParser.ParsedStructType t){ + if(t.isVoid()) { + typeStack.push(new VoidType()); + } else { + List<Field> tmpF = new List<Field>(); + for( TypeDefParser.ParsedField f : t.getFields()) { + f.accept(this); + tmpF.add(fieldStack.pop()); + } + typeStack.push(new StructType(tmpF)); + } + } + public void visit(TypeDefParser.ParsedField t){ + t.getType().accept(this); + fieldStack.push(new Field(typeStack.pop(),t.getName())); + + } + public void visit(TypeDefParser.ArrayType t){ + boolean isFixed = true; + List<Exp> dim = new List<Exp>(); + for(int i : t.getIdx()) { + if(i == 0) { + dim.add(new VariableSize()); + isFixed = false; + } else { + dim.add(new IntegerLiteral(Integer.toString(i))); + } + } + t.getType().accept(this); + if(isFixed) { + typeStack.push(new FixedArrayType(typeStack.pop(), dim)); + } else { + typeStack.push(new VariableArrayType(typeStack.pop(), dim)); + } + + } + public void visit(TypeDefParser.ParsedUserType t){ + typeStack.push(new UserType(t.getName())); + } + + + public Decl makeDecl(TypeDefParser.ParsedTypeDef d) { + d.getType().accept(this); + Decl result = new TypeDecl(typeStack.pop(), d.getName()); + return result; + } + + private Program createAndCheckProgram(List<Decl> ds) { + Program p = new Program(ds); + LinkedList errors = new LinkedList(); + p.errorCheck(errors); + if(errors.isEmpty()) { + return p; + } else { + // This should not happen + // get errors and throw exception + StringBuilder sb = new StringBuilder(); + for (Iterator iter = errors.iterator(); iter.hasNext(); ) { + String s = (String)iter.next(); + sb.append(s); + } + throw new RuntimeException("Internal error: parsed labcomm declaration has errors: "+sb.toString()); + } + } + + public Program makeProgram(TypeDefParser.ParsedTypeDef d) { + assertStacksEmpty(); + List<Decl> ds = new List<Decl>(); + + ds.add(makeDecl(d)); + assertStacksEmpty(); + return createAndCheckProgram(ds); + } + + public Decl makeDecl(TypeDefParser.ParsedSampleDef d) { + d.getType().accept(this); + Decl result = new SampleDecl(typeStack.pop(), d.getName()); + return result; + } + public Program makeProgram(TypeDefParser.ParsedSampleDef d) { + assertStacksEmpty(); + List<Decl> ds = new List<Decl>(); + + Iterator<TypeDefParser.ParsedTypeDef> it = d.getDepIterator(); + while(it.hasNext()){ + ds.add(makeDecl(it.next())); + } + + ds.add(makeDecl(d)); + + assertStacksEmpty(); + return createAndCheckProgram(ds); + } + } + diff --git a/lib/java/se/lth/control/labcomm/BuiltinType.java b/lib/java/se/lth/control/labcomm/BuiltinType.java new file mode 100644 index 0000000000000000000000000000000000000000..adb8cd02f62a536f6291071155dcd6ee4dad3f2c --- /dev/null +++ b/lib/java/se/lth/control/labcomm/BuiltinType.java @@ -0,0 +1,5 @@ +package se.lth.control.labcomm; + +public interface BuiltinType extends SampleType{ + +} diff --git a/lib/java/se/lth/control/labcomm/Constant.java b/lib/java/se/lth/control/labcomm/Constant.java index fc52a2805a7089f3537bb379234e3dd680feb0fd..e109b30445c953abbe43347d5ba5a42d26cbb15f 100644 --- a/lib/java/se/lth/control/labcomm/Constant.java +++ b/lib/java/se/lth/control/labcomm/Constant.java @@ -35,5 +35,12 @@ public class Constant { public static final int FLOAT = 0x25; public static final int DOUBLE = 0x26; public static final int STRING = 0x27; + public static final int SAMPLE = 0x28; + + /* + * Other predefined symbols + */ + + public static final int TYPE_BIND_SELF = 0x00; } diff --git a/lib/java/se/lth/control/labcomm/DecoderChannel.java b/lib/java/se/lth/control/labcomm/DecoderChannel.java index dc25d2366ad4752d56660a2628d6f1c1219c396f..05382913ec659d7ed548f585884ecb4a097bcac5 100644 --- a/lib/java/se/lth/control/labcomm/DecoderChannel.java +++ b/lib/java/se/lth/control/labcomm/DecoderChannel.java @@ -35,26 +35,57 @@ public class DecoderChannel implements Decoder { } private void processTypeDef(int len) throws IOException { - System.err.println("Got TypeDef: skipping "+len+" bytes"); - for(int i=0; i<len; i++) { - decodeByte(); + try { + processSample(Constant.TYPE_DEF); + } catch(Exception ex) { + int idx = decodePacked32(); + String name = decodeString(); + int siglen = decodePacked32(); + for(int i=0; i<siglen; i++) { + byte b = decodeByte(); } + } } private void processTypeBinding(int len) throws IOException { - System.err.println("Got TypeBinding: skipping "+len+" bytes"); - for(int i=0; i<len; i++) { - decodeByte(); - } + try { + processSample(Constant.TYPE_BINDING); + } catch(Exception ex) { + for(int i=0; i<len; i++) { + decodeByte(); + } + } } private void processPragma(int len) throws IOException { - System.err.println("Got Pragma: skipping "+len+" bytes"); for(int i=0; i<len; i++) { decodeByte(); } } + private void processSample(int tag) throws IOException { + DecoderRegistry.Entry e = def_registry.get(tag); + if (e == null) { + throw new IOException("Unhandled tag " + tag); + } + SampleDispatcher d = e.getDispatcher(); + if (d == null) { + throw new IOException("No dispatcher for '" + e.getName() + "'"); + } + SampleHandler h = e.getHandler(); + if (h == null) { + throw new IOException("No handler for '" + e.getName() +"'"); + } + try { + //XXX why does decodeAndHandle throw Exception and not IOException? + d.decodeAndHandle(this, h); + } catch (IOException ex) { + throw ex; + } catch (Exception ex) { + ex.printStackTrace(); + } + } + public void runOne() throws Exception { boolean done = false; while (!done) { @@ -68,37 +99,26 @@ public class DecoderChannel implements Decoder { version + " != " + Constant.CURRENT_VERSION); } } break; - case Constant.SAMPLE_DEF: { - processSampleDef(); - } break; - case Constant.SAMPLE_REF: { - processSampleRef(); - } break; - case Constant.TYPE_DEF: { - processTypeDef(length); - } break; - case Constant.TYPE_BINDING: { - processTypeBinding(length); - } break; - case Constant.PRAGMA: { - processPragma(length); - } break; - default: { - DecoderRegistry.Entry e = def_registry.get(tag); - if (e == null) { - throw new IOException("Unhandled tag " + tag); - } - SampleDispatcher d = e.getDispatcher(); - if (d == null) { - throw new IOException("No dispatcher for '" + e.getName() + "'"); - } - SampleHandler h = e.getHandler(); - if (h == null) { - throw new IOException("No handler for '" + e.getName() +"'"); - } - d.decodeAndHandle(this, h); - done = true; - } + case Constant.SAMPLE_DEF: { + processSampleDef(); + } break; + case Constant.SAMPLE_REF: { + processSampleRef(); + } break; + case Constant.TYPE_DEF: { + processTypeDef(length); + } break; + case Constant.TYPE_BINDING: { + processTypeBinding(length); + } break; + case Constant.PRAGMA: { + processPragma(length); + } break; + default: { + processSample(tag); + done = true; + + } } } } @@ -196,5 +216,16 @@ public class DecoderChannel implements Decoder { } + /* Package visible methods for use from TypeDefParser */ + + String getSampleName(int idx) { + DecoderRegistry.Entry e = def_registry.get(idx); + return e.getName(); + } + + byte[] getSampleSignature(int idx) { + DecoderRegistry.Entry e = def_registry.get(idx); + return e.getSignature(); + } } diff --git a/lib/java/se/lth/control/labcomm/DecoderRegistry.java b/lib/java/se/lth/control/labcomm/DecoderRegistry.java index fdf8f591d646dad3680e7fbea48e2dcb9ed2ba15..79a78063a20f1eff1cfef28816b624e8ea326290 100644 --- a/lib/java/se/lth/control/labcomm/DecoderRegistry.java +++ b/lib/java/se/lth/control/labcomm/DecoderRegistry.java @@ -51,6 +51,11 @@ public class DecoderRegistry { return index; } + // protected, for TypeDefParser... + byte[] getSignature() { + return signature; + } + public void setIndex(int index) throws IOException { if (this.index != 0 && this.index != index) { throw new IOException("Index mismatch " + @@ -96,6 +101,20 @@ public class DecoderRegistry { public synchronized void add(SampleDispatcher dispatcher, SampleHandler handler) throws IOException{ + //XXX kludge: special handling of predefined types + if(dispatcher.getSampleClass() == TypeDef.class){ + Entry e = new Entry(dispatcher, handler); + e.setIndex(Constant.TYPE_DEF); + byClass.put(dispatcher.getSampleClass(), e); + byIndex.put(Integer.valueOf(Constant.TYPE_DEF), e); + //System.out.println("LCDecoderRegistry.add("+e.getName()+", "+e.getIndex()+")"); + } else if(dispatcher.getSampleClass() == TypeBinding.class){ + Entry e = new Entry(dispatcher, handler); + e.setIndex(Constant.TYPE_BINDING); + byClass.put(dispatcher.getSampleClass(), e); + byIndex.put(Integer.valueOf(Constant.TYPE_BINDING), e); + //System.out.println("LCDecoderRegistry.add("+e.getName()+", "+e.getIndex()+")"); + } else { Entry e = byClass.get(dispatcher.getSampleClass()); if (e != null) { e.check(dispatcher.getName(), dispatcher.getSignature()); @@ -114,6 +133,7 @@ public class DecoderRegistry { byClass.put(dispatcher.getSampleClass(), e); } } + } } public synchronized void add(int index, diff --git a/lib/java/se/lth/control/labcomm/Encoder.java b/lib/java/se/lth/control/labcomm/Encoder.java index 203366e850ec1bcaae73c09c15b1cd1e3b842a12..41901151c2efeab95c24d66ab85caa3e088dfc4f 100644 --- a/lib/java/se/lth/control/labcomm/Encoder.java +++ b/lib/java/se/lth/control/labcomm/Encoder.java @@ -6,8 +6,11 @@ public interface Encoder { public void register(SampleDispatcher dispatcher) throws IOException; public void registerSampleRef(SampleDispatcher dispatcher) throws IOException; - public void begin(Class<? extends Sample> c) throws IOException; - public void end(Class<? extends Sample> c) throws IOException; + public void begin(Class<? extends SampleType> c) throws IOException; + public void end(Class<? extends SampleType> c) throws IOException; + + public void begin(int t) throws IOException; + public int getTypeId(Class<? extends SampleType> c) throws IOException; public void encodeBoolean(boolean value) throws IOException; public void encodeByte(byte value) throws IOException; diff --git a/lib/java/se/lth/control/labcomm/EncoderChannel.java b/lib/java/se/lth/control/labcomm/EncoderChannel.java index 08f9c87074c6d675d3cb08fd397d481f708e1726..f429f94e7bf311ed57ae89b8cd7406b43ff07b2c 100644 --- a/lib/java/se/lth/control/labcomm/EncoderChannel.java +++ b/lib/java/se/lth/control/labcomm/EncoderChannel.java @@ -10,41 +10,117 @@ public class EncoderChannel implements Encoder { private Writer writer; private ByteArrayOutputStream bytes = new ByteArrayOutputStream(); private DataOutputStream data = new DataOutputStream(bytes); - private EncoderRegistry def_registry = new EncoderRegistry(); - private EncoderRegistry ref_registry = new EncoderRegistry(); - private int current_tag; + private EncoderRegistry sample_def_registry = new EncoderRegistry(); + private EncoderRegistry sample_ref_registry = new EncoderRegistry(); + private EncoderRegistry type_def_registry = new EncoderRegistry(); + private int current_tag; - public EncoderChannel(Writer writer) throws IOException { + private EncoderChannel(Writer writer, boolean emitVersion) throws IOException { this.writer = writer; - begin(Constant.VERSION); - encodeString(Constant.CURRENT_VERSION); - end(null); + if(emitVersion){ + begin(Constant.VERSION); + encodeString(Constant.CURRENT_VERSION); + end(null); + } + } + public EncoderChannel(Writer writer) throws IOException { + this(writer, true); } public EncoderChannel(OutputStream writer) throws IOException { - this(new WriterWrapper(writer)); + this(new WriterWrapper(writer), true); } - public void register(SampleDispatcher dispatcher) throws IOException { - if(dispatcher.getTypeDeclTag() == Constant.SAMPLE_DEF) { - int index = def_registry.add(dispatcher); - //begin(Constant.SAMPLE_DEF); + private EncoderChannel(OutputStream writer, boolean emitVersion) throws IOException { + this(new WriterWrapper(writer), emitVersion); + } + private void bindType(int sampleId, int typeId) throws IOException { + begin(Constant.TYPE_BINDING); + encodePacked32(sampleId); + encodePacked32(typeId); + end(null); + } + + private void registerSample(SampleDispatcher dispatcher) throws IOException { + int index = sample_def_registry.add(dispatcher); begin(dispatcher.getTypeDeclTag()); encodePacked32(index); encodeString(dispatcher.getName()); byte[] signature = dispatcher.getSignature(); encodePacked32(signature.length); for (int i = 0 ; i < signature.length ; i++) { - encodeByte(signature[i]); + encodeByte(signature[i]); } end(null); + int tindex; + if(dispatcher.hasDependencies()){ + tindex = registerTypeDef(dispatcher); + } else { + tindex = Constant.TYPE_BIND_SELF; + } + bindType(index, tindex); + + } + + private static class WrappedEncoder extends EncoderChannel{ + private Encoder wrapped; + + public WrappedEncoder(Encoder e, OutputStream s, boolean emitVersion) throws IOException { + super(s,emitVersion); + this.wrapped = e; + } + public int getTypeId(Class<? extends SampleType> c) throws IOException{ + return wrapped.getTypeId(c); + } + } + + + private int registerTypeDef(SampleDispatcher dispatcher) throws IOException { + // check if already registered + try { + return type_def_registry.getTag(dispatcher); + } catch (IOException e) { + //otherwise, add to the registry + int index = type_def_registry.add(dispatcher); + //wrap encoder to get encoded length of signature + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + EncoderChannel wrapped = new WrappedEncoder(this, baos, false); + dispatcher.encodeTypeDef(wrapped, index); + wrapped.flush(); + byte b[] = baos.toByteArray(); + + begin(Constant.TYPE_DEF); + encodePacked32(index); + encodeString(dispatcher.getName()); + encodePacked32(b.length); + for(int i = 0; i<b.length; i++) { + encodeByte(b[i]); + } + end(null); + + return index; + } + } + + public void register(SampleDispatcher dispatcher) throws IOException { + switch (dispatcher.getTypeDeclTag()) { + case Constant.SAMPLE_DEF: { + registerSample(dispatcher); + break; + } + case Constant.TYPE_DEF: { + registerTypeDef(dispatcher); + break; + } + default: + throw new Error("Unknown typeDeclTag: "+dispatcher.getTypeDeclTag()); } } public void registerSampleRef(SampleDispatcher dispatcher) throws IOException { System.err.println(dispatcher); - int index = ref_registry.add(dispatcher); + int index = sample_ref_registry.add(dispatcher); begin(Constant.SAMPLE_REF); encodePacked32(index); encodeString(dispatcher.getName()); @@ -56,16 +132,22 @@ public class EncoderChannel implements Encoder { end(null); } - private void begin(int tag) { + public void begin(int tag) { current_tag = tag; bytes.reset(); } - public void begin(Class<? extends Sample> c) throws IOException { - begin(def_registry.getTag(c)); + public void begin(Class<? extends SampleType> c) throws IOException { + begin(sample_def_registry.getTag(c)); } - public void end(Class<? extends Sample> c) throws IOException { + /* aux. method used to allow nesting encoders to find encoded size */ + private void flush() throws IOException{ + data.flush(); + writer.write(bytes.toByteArray()); + bytes.reset(); + } + public void end(Class<? extends SampleType> c) throws IOException { data.flush(); WritePacked32(writer, current_tag); WritePacked32(writer, bytes.size()); @@ -73,19 +155,26 @@ public class EncoderChannel implements Encoder { bytes.reset(); } + /** + * @return the id of a TYPE_DEF + */ + public int getTypeId(Class<? extends SampleType> c) throws IOException { + return type_def_registry.getTag(c); + } + private void WritePacked32(Writer s, long value) throws IOException { byte[] tmp1 = new byte[5]; byte[] tmp2 = new byte[1]; long v = value & 0xffffffff; int i; - + for (i = 0 ; i == 0 || v != 0 ; i++, v = (v >> 7)) { tmp1[i] = (byte)(v & 0x7f | (i!=0?0x80:0x00)); } for (i = i - 1 ; i >= 0 ; i--) { tmp2[0] = tmp1[i]; writer.write(tmp2); - } + } } public void encodeBoolean(boolean value) throws IOException{ @@ -117,17 +206,15 @@ public class EncoderChannel implements Encoder { } public void encodeString(String value) throws IOException { - //data.writeShort(0); // HACK... - //data.writeUTF(value); - - //kludge, to replace above hack with packed length ByteArrayOutputStream tmpb = new ByteArrayOutputStream(); DataOutputStream tmps = new DataOutputStream(tmpb); tmps.writeUTF(value); tmps.flush(); byte[] tmp = tmpb.toByteArray(); - + + //the two first bytes written by writeUTF is the length of + //the string, so we skip those encodePacked32(tmp.length-2); for (int i = 2 ; i < tmp.length ; i++) { encodeByte(tmp[i]); @@ -150,8 +237,9 @@ public class EncoderChannel implements Encoder { public void encodeSampleRef(Class value) throws IOException { int index = 0; try { - index = ref_registry.getTag(value); + index = sample_ref_registry.getTag(value); } catch (NullPointerException e) { + //we want to return 0 for unregistered ref types } data.writeInt(index); } diff --git a/lib/java/se/lth/control/labcomm/EncoderRegistry.java b/lib/java/se/lth/control/labcomm/EncoderRegistry.java index cd0cf72f5f45ed9ccc3cb6ce1902c9c2e37333bf..f990d1813920a0624c557b4a895cae1f64331a69 100644 --- a/lib/java/se/lth/control/labcomm/EncoderRegistry.java +++ b/lib/java/se/lth/control/labcomm/EncoderRegistry.java @@ -42,7 +42,11 @@ public class EncoderRegistry { return e.getIndex(); } - public int getTag(Class<? extends Sample> sample) throws IOException { + public int getTag(SampleDispatcher d) throws IOException { + return getTag(d.getSampleClass()); + } + + public int getTag(Class<? extends SampleType> sample) throws IOException { Entry e = byClass.get(sample); if (e == null) { throw new IOException("'" + @@ -52,4 +56,8 @@ public class EncoderRegistry { return e.index; } + public boolean contains(Class<? extends SampleType> sample) { + return byClass.containsKey(sample); + } + } diff --git a/lib/java/se/lth/control/labcomm/Sample.java b/lib/java/se/lth/control/labcomm/Sample.java index f86f486b4bae2276780f73e24b33d03717c95840..2dd432b878f509538aca71f0b7840ff8fe2513b2 100644 --- a/lib/java/se/lth/control/labcomm/Sample.java +++ b/lib/java/se/lth/control/labcomm/Sample.java @@ -1,6 +1,6 @@ package se.lth.control.labcomm; -public interface Sample { +public interface Sample extends SampleType { public SampleDispatcher getDispatcher(); diff --git a/lib/java/se/lth/control/labcomm/SampleDispatcher.java b/lib/java/se/lth/control/labcomm/SampleDispatcher.java index 58e3d1debdb47e31125088cf9bb6502d0ebc74b5..b2ed2fd98658f15461c6a8a60e8f4bb9df39418b 100644 --- a/lib/java/se/lth/control/labcomm/SampleDispatcher.java +++ b/lib/java/se/lth/control/labcomm/SampleDispatcher.java @@ -1,8 +1,10 @@ package se.lth.control.labcomm; -public interface SampleDispatcher { +import java.io.IOException; + +public interface SampleDispatcher <T extends SampleType>{ - public Class getSampleClass(); + public Class<T> getSampleClass(); public String getName(); @@ -11,6 +13,12 @@ public interface SampleDispatcher { public void decodeAndHandle(Decoder decoder, SampleHandler handler) throws Exception; + /** @return true if the type depends on one or more typedefs + */ + public boolean hasDependencies(); + + public void encodeTypeDef(Encoder e, int index) throws IOException; + /** return the tag SAMPLE_DEF or TYPE_DEF, for use * by encoder.register. * TODO: refactor types, moving this to a super-interface diff --git a/lib/java/se/lth/control/labcomm/TypeBinding.java b/lib/java/se/lth/control/labcomm/TypeBinding.java new file mode 100644 index 0000000000000000000000000000000000000000..1c0cd41345f1aa20470e0327570eb17413d6e811 --- /dev/null +++ b/lib/java/se/lth/control/labcomm/TypeBinding.java @@ -0,0 +1,125 @@ +package se.lth.control.labcomm; + +import java.io.IOException; +import java.io.ByteArrayOutputStream; +import java.io.ByteArrayInputStream; +import se.lth.control.labcomm.Decoder; +import se.lth.control.labcomm.DecoderChannel; +import se.lth.control.labcomm.SampleDispatcher; +import se.lth.control.labcomm.SampleHandler; + +public class TypeBinding implements BuiltinType { + private int sampleIndex; + private int typeIndex; + + public TypeBinding(int sampleIndex, int typeIndex) { + this.sampleIndex = sampleIndex; + this.typeIndex = typeIndex; + } + + public int getSampleIndex() { + return sampleIndex; + } + + public int getTypeIndex() { + return typeIndex; + } + + public boolean isSelfBinding() { + return typeIndex == Constant.TYPE_BIND_SELF; + } + + public interface Handler extends SampleHandler { + public void handle_TypeBinding(TypeBinding value) throws Exception; + } + + public static void register(Decoder d, Handler h) throws IOException { + d.register(Dispatcher.singleton(), h); + } + + public static void register(Encoder e) throws IOException { + register(e,false); + } + + public static void register(Encoder e, boolean sendMetaData) throws IOException { + throw new IOException("cannot send TypeDefs"); + } + + static class Dispatcher implements SampleDispatcher<TypeBinding> { + + private static Dispatcher singleton; + + public synchronized static Dispatcher singleton() { + if(singleton==null) singleton=new Dispatcher(); + return singleton; + } + + public Class<TypeBinding> getSampleClass() { + return TypeBinding.class; + } + + public String getName() { + return "TypeBinding"; + } + + public byte getTypeDeclTag() { + throw new Error("Should not be called"); + } + + public boolean isSample() { + throw new Error("Should not be called"); + } + public boolean hasStaticSignature() { + throw new Error("Should not be called"); + } + + public byte[] getSignature() { + return null; // not used for matching + } + + public void encodeTypeDef(Encoder e, int index) throws IOException{ + throw new Error("Should not be called"); + } + + public void decodeAndHandle(Decoder d, + SampleHandler h) throws Exception { + ((Handler)h).handle_TypeBinding(TypeBinding.decode(d)); + } + + public boolean hasDependencies() { + return false; + } + } + + public static void encode(Encoder e, TypeBinding value) throws IOException { + throw new Error("Should not be called"); + } + + /* HERE BE DRAGONS! + * This exposes (and relies on the stability of) indices that are + * internal to a decoder. + * + * The SAMPLE_DEF and TYPE_DEF must already have been received for the + * indices to be known, so this can be changed to instead return + * references to the SampleDispactcher corresponding to the sample type + * and the matching TypeDef. + * + * Sketch: + * + * SampleDispatcher sd = d.getDispatcherForId(sampleIndex); + * TypeDef td = d.getTypeDefForId(typeIndex); + * + * return new TypeBinding(sd, td); + * + * assuming that the Decoder keeps a registry for TypeDefs + */ + public static TypeBinding decode(Decoder d) throws IOException { + TypeBinding result; + int sampleIndex = d.decodePacked32(); + int typeIndex = d.decodePacked32(); + + result = new TypeBinding(sampleIndex, typeIndex); + return result; + } +} + diff --git a/lib/java/se/lth/control/labcomm/TypeDef.java b/lib/java/se/lth/control/labcomm/TypeDef.java new file mode 100644 index 0000000000000000000000000000000000000000..067c400e9b0a668ddff6786e231aa4ff3a9f9067 --- /dev/null +++ b/lib/java/se/lth/control/labcomm/TypeDef.java @@ -0,0 +1,132 @@ +package se.lth.control.labcomm; + +import java.io.IOException; +import java.io.ByteArrayOutputStream; +import java.io.ByteArrayInputStream; +import se.lth.control.labcomm.Decoder; +import se.lth.control.labcomm.DecoderChannel; +import se.lth.control.labcomm.SampleDispatcher; +import se.lth.control.labcomm.SampleHandler; + +public class TypeDef implements BuiltinType { + private int index; + private String name; + private byte signature[]; + + public int getIndex() { + return index; + } + + public String getName() { + return name; + } + + public String toString() { + return getName(); + } + + public byte[] getSignature() { + return signature; + } + + public void dump() { + System.out.print("=== TypeDef "+getName()+"( "+Integer.toHexString(getIndex())+") : "); + for (byte b : signature) { + System.out.print(String.format("0x%02X ", b)); + } + System.out.println(); + } + public interface Handler extends SampleHandler { + public void handle_TypeDef(TypeDef value) throws Exception; + } + + public static void register(Decoder d, Handler h) throws IOException { + d.register(Dispatcher.singleton(), h); + } + + public static void register(Encoder e) throws IOException { + register(e,false); + } + + public static void register(Encoder e, boolean sendMetaData) throws IOException { + throw new IOException("cannot send TypeDefs"); + } + + static class Dispatcher implements SampleDispatcher<TypeDef> { + + private static Dispatcher singleton; + + public synchronized static Dispatcher singleton() { + if(singleton==null) singleton=new Dispatcher(); + return singleton; + } + + public Class<TypeDef> getSampleClass() { + return TypeDef.class; + } + + public String getName() { + return "TypeDef"; + } + + public byte getTypeDeclTag() { + throw new Error("Should not be called"); + } + + public boolean isSample() { + throw new Error("Should not be called"); + } + public boolean hasStaticSignature() { + throw new Error("Should not be called"); + } + + /** return the flat signature. Intended use is on decoder side */ + public byte[] getSignature() { + return null; // not used for matching + } + + public void encodeTypeDef(Encoder e, int index) throws IOException{ + throw new Error("Should not be called"); + } + +// public boolean canDecodeAndHandle() { +// return true; +// } + + public void decodeAndHandle(Decoder d, + SampleHandler h) throws Exception { + ((Handler)h).handle_TypeDef(TypeDef.decode(d)); + } + + public boolean hasDependencies() { + return false; + } + } + + public static void encode(Encoder e, TypeDef value) throws IOException { + throw new Error("Should not be called"); + } + + protected TypeDef() { + } + + public TypeDef(int index, String name, byte sig[]) { + this.index = index; + this.name = name; + this.signature = sig; + } + + public static TypeDef decode(Decoder d) throws IOException { + TypeDef result; + int index = d.decodePacked32(); + String name = d.decodeString(); + int siglen= d.decodePacked32(); + byte sig[] = new byte[siglen]; + for(int i=0; i<siglen;i++){ + sig[i] = d.decodeByte(); + } + result = new TypeDef(index, name, sig); + return result; + } +} + diff --git a/lib/java/se/lth/control/labcomm/TypeDefParser.java b/lib/java/se/lth/control/labcomm/TypeDefParser.java new file mode 100644 index 0000000000000000000000000000000000000000..a72e96510e6ee1544f42aa39c548b637172c1cbd --- /dev/null +++ b/lib/java/se/lth/control/labcomm/TypeDefParser.java @@ -0,0 +1,663 @@ +package se.lth.control.labcomm; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; + +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.io.EOFException; + +import se.lth.control.labcomm.Decoder; +import se.lth.control.labcomm.DecoderChannel; +import se.lth.control.labcomm.TypeDef; +import se.lth.control.labcomm.TypeBinding; + +public class TypeDefParser implements TypeDef.Handler, TypeBinding.Handler { + + static class SelfBinding extends TypeDef { + + private int sampleIndex; + private Decoder decoder; + private byte[] dummy = new byte[0]; + public String toString() {return "self";} + public String getName() { + if(decoder instanceof DecoderChannel) { + DecoderChannel dc = (DecoderChannel) decoder; + return dc.getSampleName(sampleIndex); + } else { + return "self"; + } + } + public int getIndex() {return 0;} + public byte[] getSignature() { + if(decoder instanceof DecoderChannel) { + DecoderChannel dc = (DecoderChannel) decoder; + return dc.getSampleSignature(sampleIndex); + } else { + return dummy; + } + } + + public SelfBinding(int sampleIndex, Decoder decoder) { + super(); + this.sampleIndex = sampleIndex; + this.decoder = decoder; + } + } + + public interface TypeDefListener { + void onTypeDef(ParsedTypeDef d); + } + + private HashMap<Integer,TypeDef> typeDefs; + private HashMap<Integer,Integer> typeBindings; + private HashSet<TypeDefListener> listeners; + private LinkedList<ParsedSampleDef> sampleDefs; + private Decoder decoder; + + protected TypeDefParser(Decoder d) { + this.decoder = d; + typeDefs = new HashMap<Integer,TypeDef>(); + typeBindings = new HashMap<Integer,Integer>(); + listeners = new HashSet<TypeDefListener>(); + sampleDefs = new LinkedList<ParsedSampleDef>(); + } + + public void addListener(TypeDefListener l) { + listeners.add(l); + } + + + public Iterator<ParsedSampleDef> sampleDefIterator() { + return sampleDefs.iterator(); + } + + public void handle_TypeDef(TypeDef d) throws java.io.IOException { + typeDefs.put(d.getIndex(), d); + } + + public void handle_TypeBinding(TypeBinding d) throws java.io.IOException { + TypeDef td; + if(d.isSelfBinding()){ + td = new SelfBinding(d.getSampleIndex(), decoder); + } else { + typeBindings.put(d.getSampleIndex(), d.getTypeIndex()); + td = getTypeDefForIndex(d.getSampleIndex()); + } + ParsedSampleDef result = parseSignature(td); + + sampleDefs.add(result); + + Iterator<TypeDefListener> it = listeners.iterator(); + while(it.hasNext()){ + notifyListener(it.next(), result); + } + } + + private void notifyListener(TypeDefListener l, ParsedTypeDef d) { + l.onTypeDef(d); + if(d instanceof ParsedSampleDef) { + for(ParsedTypeDef dep : ((ParsedSampleDef)d).getDependencies()) { + //do we want to change ParseTypeDef to have dependencies, + //and do recursion here? + //if so, do notifyListener(l, dep); + l.onTypeDef(dep); + } + } + } + + private TypeDef getTypeDefForIndex(int sampleIndex) { + return typeDefs.get(typeBindings.get(sampleIndex)); + } + + + /** Factory method for use by application programs: + * registers a TypeDefParser for handling TypeDef and TypeBinding + * on the Decoder d. + * + * @return a new TypeDefParser registered on d + */ + public static TypeDefParser registerTypeDefParser(Decoder d) throws java.io.IOException { + + TypeDefParser res = new TypeDefParser(d); + + TypeDef.register(d,res); + TypeBinding.register(d,res); + + return res; + } + + public LinkedList<ParsedSymbol> symbolify() { + + LinkedList<ParsedSymbol> result = new LinkedList<ParsedSymbol>(); + + Iterator<ParsedSampleDef> sdi = sampleDefIterator(); + + while(sdi.hasNext()) { + ParsedSampleDef sd = sdi.next(); + result.add(new SampleSymbol()); + result.add(sd.getType()); + result.add(new NameSymbol(sd.getName())); + + Iterator<ParsedTypeDef> di = sd.getDepIterator(); + while(di.hasNext()) { + ParsedTypeDef d = di.next(); + result.add(new TypeSymbol()); + result.add(d.getType()); + result.add(new NameSymbol(d.getName())); + } + } + return result; + } + + public String symbolString() { + Iterator<ParsedSymbol> i = symbolify().iterator(); + + StringBuilder sb = new StringBuilder(); + + while(i.hasNext()) { + sb.append(i.next().toString()); + } + return sb.toString(); + } + + /* An interface for using Visitor pattern to traverse + * ParsedTypeDefs + */ + public interface ParsedSymbolVisitor { + void visit(TypeSymbol s); + void visit(SampleSymbol s); + void visit(NameSymbol s); + void visit(PrimitiveType t); + //sampleRefs are sent as primitive types + //Put this back if that is changed to SampleRefType + //void visit(SampleRefType t); + void visit(ParsedStructType t); + void visit(ParsedField t); + void visit(ArrayType t); + void visit(ParsedUserType t); + } + public abstract class ParsedSymbol{ + public abstract void accept(ParsedSymbolVisitor v); + } + + public class TypeSymbol extends ParsedSymbol { + public String toString() { + return "typedef "; + } + public void accept(ParsedSymbolVisitor v){ + v.visit(this); + } + } + + public class SampleSymbol extends ParsedSymbol { + public String toString() { + return "sample "; + } + public void accept(ParsedSymbolVisitor v){ + v.visit(this); + } + } + + public class NameSymbol extends ParsedSymbol { + private String name; + + public NameSymbol(String name) { + this.name = name; + } + + public String toString() { + return name; + } + public void accept(ParsedSymbolVisitor v){ + v.visit(this); + } + } + + public abstract class ParsedType extends ParsedSymbol{ + } + +// SampleRefType currently not sent, se above +// public class SampleRefType extends ParsedType { +// public void accept(ParsedSymbolVisitor v) { +// v.visit(this); +// } +// +// public String toString() { +// return "sample";} +// } + + public class PrimitiveType extends ParsedType { + private final String name; + private int tag; + + String getName() { + return name; + } + + int getTag() { + return tag; + } + PrimitiveType(int tag) { + this.tag = tag; + switch(tag) { + case Constant.BOOLEAN: + this.name = "boolean"; + break; + case Constant.BYTE: + this.name = "byte"; + break; + case Constant.SHORT: + this.name = "short"; + break; + case Constant.INT: + this.name = "int"; + break; + case Constant.LONG: + this.name = "long"; + break; + case Constant.FLOAT: + this.name = "float"; + break; + case Constant.DOUBLE: + this.name = "double"; + break; + case Constant.STRING: + this.name = "string"; + break; + case Constant.SAMPLE: + this.name = "sample"; + break; + default: + this.name = "??? unknown tag 0x"+Integer.toHexString(tag); + } + } + + public void accept(ParsedSymbolVisitor v) { + v.visit(this); + } + + public String toString() { + return name;} + } + + public class ParsedStructType extends ParsedType { + private ParsedField fields[]; + + ParsedStructType(int nParsedFields) { + this.fields = new ParsedField[nParsedFields]; + } + + public ParsedField[] getFields() { + return fields; + } + + void setParsedField(int idx, ParsedField f) { + fields[idx] = f; + } + + public boolean isVoid() { + return fields.length == 0; + } + + public String toString() { + if(isVoid()) { //void type is empty struct + return "void"; + } else { + StringBuilder sb = new StringBuilder(); + sb.append("struct {\n"); + for(ParsedField f : fields) { + sb.append(f.toString()); + sb.append(";\n"); + } + sb.append("}"); + return sb.toString(); + } + } + + public void accept(ParsedSymbolVisitor v) { + v.visit(this); + } + } + + public class ParsedField extends ParsedSymbol{ + private ParsedType type; + private String name; + + ParsedField(String name, ParsedType type) { + this.name = name; + this.type = type; + } + + public ParsedType getType() { + return type; + } + + public String getName() { + return name; + } + + public String toString() { + return type.toString() + " " + name; + } + + public void accept(ParsedSymbolVisitor v) { + v.visit(this); + } + } + + public class ArrayType extends ParsedType { + private int idx[]; + private ParsedType type; + + ArrayType(int idx[], ParsedType elementType) { + this.idx = idx; + this.type = elementType; + } + + public ParsedType getType() { + return type; + } + + public int[] getIdx() { + return idx; + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(type.toString()); + for(int i : idx) { + sb.append("["+(i>0 ? i : "_")+"]"); + } + return sb.toString(); + } + + public void accept(ParsedSymbolVisitor v) { + v.visit(this); + } + } + + public class ParsedUserType extends ParsedType { + private String name; + public String getName() { + return name; + } + + public String toString() { + return name; + } + + ParsedUserType(String name) { + this.name = name; + } + + public void accept(ParsedSymbolVisitor v) { + v.visit(this); + } + } + + public class ParsedTypeDef{ + private int idx; + private String name; + private ParsedType type; + + ParsedTypeDef(int idx, String name){ + this.idx = idx; + this.name = name; + } + + ParsedTypeDef(int idx, String name, ParsedType type) { + this(idx, name); + this.type = type; + } + + /** To be overridden in ParsedSampleDef + */ + public boolean isSampleDef() { + return false; + } + + void setType(ParsedType type) { + this.type = type; + } + + ParsedType getType() { + return type; + } + + int getIndex() { + return idx; + } + + public String getName() { + return name; + } + + public String toString() { + return type.toString(); + } + + public int hashCode() { + return name.hashCode(); + } + + public boolean equals(Object o) { + if(! (o instanceof ParsedTypeDef)){ + return false; + } else { + ParsedTypeDef other = (ParsedTypeDef) o; + return other.idx == idx && other.name.equals(name); + } + } + + public void accept(ParsedSymbolVisitor v) { + type.accept(v); + } + } + + public class ParsedSampleDef extends ParsedTypeDef{ + + private HashSet<ParsedTypeDef> deps; + ParsedSampleDef(ParsedTypeDef td) { + super(td.getIndex(), td.getName(), td.getType()); + this.deps = new HashSet<ParsedTypeDef>(); + } + + void addDependency(ParsedTypeDef d) { + deps.add(d); + } + + @Override + public boolean isSampleDef() { + return true; + } + private HashSet<ParsedTypeDef> getDependencies() { + return deps; + } + + Iterator<ParsedTypeDef> getDepIterator() { + return deps.iterator(); + } + } + + private class ParserState { + private ByteArrayInputStream bis; + private DataInputStream in; + private TypeDef current; + private ParsedTypeDef currentParsed; + + private LinkedList<TypeDef> typeStack; + + ParsedTypeDef newTypeDef() { + currentParsed =new ParsedTypeDef(getCurrentIndex(), getCurrentName()); + return currentParsed; + } + + private ParserState() { + typeStack = new LinkedList<TypeDef>(); + } + + ParserState(int typeIdx) { + this(); + pushType(typeIdx); + } + + ParserState(TypeDef td) { + this(); + pushType(td); + } + + ParserState(byte sig[]) { + this(); + bis= new ByteArrayInputStream(sig); + in = new DataInputStream(bis); + } + + void pushType(TypeDef td) { + if(!typeStack.contains(td)) { + typeStack.push(td); + } + } + void pushType(int typeIdx) { + if(typeIdx >= 0x40 && !typeStack.contains(typeIdx)) { + typeStack.push(typeDefs.get(typeIdx)); + } + } + + void popType() { + TypeDef td2 = typeStack.pop(); + current = td2; + bis =new ByteArrayInputStream(td2.getSignature()); + in = new DataInputStream(bis); + } + + boolean moreTypes() { + return !typeStack.isEmpty(); + } + + int getCurrentIndex() { + return current.getIndex(); + } + + String getCurrentName() { + return current.getName(); + } + + String decodeString() throws IOException { + int len = decodePacked32() & 0xffffffff; + byte[] chars = new byte[len]; + for(int i=0; i<len; i++) { + chars[i] = in.readByte(); + } + return new String(chars); + } + + int decodePacked32() throws IOException { + long res=0; + byte i=0; + boolean cont=true; + + do { + byte c = in.readByte(); + res = (res << 7) | (c & 0x7f); + cont = (c & 0x80) != 0; + i++; + } while(cont); + + return (int) (res & 0xffffffff); + } + } + + public ParsedSampleDef parseSignature(TypeDef td) throws IOException{ + ParserState s = new ParserState(td); + + ParsedSampleDef result=null; + try { + s.popType(); + result = parseSampleTypeDef(s); + while(s.moreTypes()) { + s.popType(); + result.addDependency(parseTypeDef(s)); + } + } catch(java.io.EOFException ex) { + System.out.println("EOF: self_binding"); + } + return result; + } + + private ArrayType parseArray(ParserState in) throws IOException { + int numIdx = in.decodePacked32(); + int idx[] = new int[numIdx]; + for(int i=0; i<numIdx; i++){ + idx[i] = in.decodePacked32(); + } + int type = in.decodePacked32(); + ParsedType elementType = lookupType(type, in); + ArrayType result = new ArrayType(idx, elementType); + for(int i=0; i<numIdx; i++){ + idx[i] = in.decodePacked32(); + } + return result; + } + + private ParsedStructType parseStruct(ParserState in) throws IOException { + int numParsedFields = in.decodePacked32(); + ParsedStructType result = new ParsedStructType(numParsedFields); + for(int i=0; i<numParsedFields; i++) { + result.setParsedField(i, parseParsedField(in)); + } + return result; + } + + private ParsedField parseParsedField(ParserState in) throws IOException { + String name = in.decodeString(); + return new ParsedField(name, parseType(in)); + } + + private ParsedType lookupType(int tag, ParserState in) { + ParsedType result; + if(tag >= Constant.FIRST_USER_INDEX) { + TypeDef td = typeDefs.get(tag); + result = new ParsedUserType(td.getName()); + in.pushType(tag); +// sampleRefs are sent as primitive types, see above +// } else if(tag == Constant.SAMPLE) { +// result = new SampleRefType(); + } else { + result = new PrimitiveType(tag); + } + return result; + } + + private ParsedSampleDef parseSampleTypeDef(ParserState in) throws IOException { + ParsedTypeDef td = parseTypeDef(in); + return new ParsedSampleDef(td); + } + private ParsedTypeDef parseTypeDef(ParserState in) throws IOException { + ParsedTypeDef result = in.newTypeDef(); + result.setType(parseType(in)); + return result; + } + private ParsedType parseType(ParserState in) throws IOException { + int tag = in.decodePacked32(); + ParsedType result = null; + switch(tag) { + case 0: + System.out.println("SELF"); + break; + case Constant.ARRAY: + result = parseArray(in); + break; + case Constant.STRUCT: + result = parseStruct(in); + break; + default: + result = lookupType(tag, in); + break; + } + return result; + } +} diff --git a/lib/java/se/lth/control/labcomm2006/ASTbuilder.java b/lib/java/se/lth/control/labcomm2006/ASTbuilder.java new file mode 100644 index 0000000000000000000000000000000000000000..a65e88738f5ed796591f10a00f63733aa17d8116 --- /dev/null +++ b/lib/java/se/lth/control/labcomm2006/ASTbuilder.java @@ -0,0 +1,4 @@ +package se.lth.control.labcomm2006; + +public class ASTbuilder { +} diff --git a/lib/java/se/lth/control/labcomm2006/BuiltinType.java b/lib/java/se/lth/control/labcomm2006/BuiltinType.java new file mode 100644 index 0000000000000000000000000000000000000000..ffcdc879cd4c727d112423d498603da897752f3e --- /dev/null +++ b/lib/java/se/lth/control/labcomm2006/BuiltinType.java @@ -0,0 +1,5 @@ +package se.lth.control.labcomm2006; + +public interface BuiltinType extends SampleType{ + +} diff --git a/lib/java/se/lth/control/labcomm2006/TypeBinding.java b/lib/java/se/lth/control/labcomm2006/TypeBinding.java new file mode 100644 index 0000000000000000000000000000000000000000..0a15ac99af8f32c711e621d667ee920cf14abd7b --- /dev/null +++ b/lib/java/se/lth/control/labcomm2006/TypeBinding.java @@ -0,0 +1,3 @@ +public class TypeBinding { + +} diff --git a/lib/java/se/lth/control/labcomm2006/TypeDef.java b/lib/java/se/lth/control/labcomm2006/TypeDef.java new file mode 100644 index 0000000000000000000000000000000000000000..32997dd75bc4b149eef5d885da7b046819e47b2c --- /dev/null +++ b/lib/java/se/lth/control/labcomm2006/TypeDef.java @@ -0,0 +1,3 @@ +public class TypeDef { + +} diff --git a/lib/java/se/lth/control/labcomm2006/TypeDefParser.java b/lib/java/se/lth/control/labcomm2006/TypeDefParser.java new file mode 100644 index 0000000000000000000000000000000000000000..2890eeec456346dbd786195991afcf1bfd21cdec --- /dev/null +++ b/lib/java/se/lth/control/labcomm2006/TypeDefParser.java @@ -0,0 +1,2 @@ +public class TypeDefParser { +} diff --git a/lib/python/labcomm/LabComm.py b/lib/python/labcomm/LabComm.py index 57172143d4c1716069edae6b971e87881a430ee9..3816c0f834cf6da92928a85cc6ee2caa868988bf 100644 --- a/lib/python/labcomm/LabComm.py +++ b/lib/python/labcomm/LabComm.py @@ -175,6 +175,8 @@ DEFAULT_VERSION = "LabComm2014" i_VERSION = 0x01 i_SAMPLE_DEF = 0x02 i_SAMPLE_REF = 0x03 +i_TYPE_DEF = 0x04 +i_TYPE_BINDING= 0x05 i_PRAGMA = 0x3f i_USER = 0x40 # ..0xffffffff @@ -847,6 +849,13 @@ class Decoder(Codec): for _ in xrange(length): self.decode_byte() + # kludge, should really check if the index exists in self.version + def skip_or_raise(self, length, index): + if usePacketLength(self.version): + self.skip(length) + else: + raise Exception("Invalid type index %d" % index) + def decode(self): while True: index = self.decode_type_number() @@ -865,6 +874,18 @@ class Decoder(Codec): elif index == i_SAMPLE_REF: decl = self.index_to_decl[index].decode_decl(self) value = None + elif index == i_TYPE_DEF: + self.skip_or_raise(length, index) + decl = None + value = None + elif index == i_TYPE_BINDING: + self.skip_or_raise(length, index) + decl = None + value = None + elif index == i_PRAGMA: + self.skip_or_raise(length, index) + decl = None + value = None elif index < i_USER: raise Exception("Invalid type index %d" % index) else: