From 59a4985519ce3100226928f163b7d5e3497a3591 Mon Sep 17 00:00:00 2001
From: Sven Gestegard Robertz <sven.robertz@cs.lth.se>
Date: Thu, 13 Nov 2014 17:08:13 +0100
Subject: [PATCH] pruned and grafted the refactored compiler from the metadata
 branch. Tests run, but code needs cleanup

---
 compiler/CS_CodeGen.jrag                      | 292 +++++++++++-
 compiler/C_CodeGen.jrag                       | 290 ++++++++++--
 compiler/DeclNames.jrag                       |   7 +
 compiler/FlatSignature.jrag                   | 115 +++++
 compiler/Java_CodeGen.jrag                    | 445 +++++++++++++-----
 compiler/LabComm.ast                          |  17 +-
 compiler/LabComm.java                         |   1 +
 compiler/LabCommTokens.jrag                   |  19 +
 compiler/LabCommmTokens.jrag                  |  18 -
 compiler/NameAnalysis.jrag                    |   6 +-
 compiler/PrettyPrint.jrag                     |   4 +
 compiler/Python_CodeGen.jrag                  |  18 +-
 compiler/RAPID_CodeGen.jrag                   |  32 +-
 compiler/Signature.jrag                       | 256 +++++-----
 compiler/TypeCheck.jrag                       |   8 +-
 compiler/TypeReferences.jrag                  |  46 ++
 compiler/build.xml                            |   4 +-
 lib/c/labcomm_private.h                       |  30 +-
 lib/csharp/se/lth/control/labcomm/Constant.cs |   4 +-
 .../se/lth/control/labcomm/DecoderChannel.cs  |   2 +-
 .../se/lth/control/labcomm/EncoderChannel.cs  |   2 +-
 .../lth/control/labcomm/SampleDispatcher.java |   2 +-
 22 files changed, 1271 insertions(+), 347 deletions(-)
 create mode 100644 compiler/FlatSignature.jrag
 create mode 100644 compiler/LabCommTokens.jrag
 delete mode 100644 compiler/LabCommmTokens.jrag
 create mode 100644 compiler/TypeReferences.jrag

diff --git a/compiler/CS_CodeGen.jrag b/compiler/CS_CodeGen.jrag
index a4a42e0..2790335 100644
--- a/compiler/CS_CodeGen.jrag
+++ b/compiler/CS_CodeGen.jrag
@@ -9,11 +9,15 @@ aspect CS_CodeGenEnv {
   public class CS_env {
 
     public final int version;
+    public final String verStr;
     private int indent;
     private int depth;
     private CS_printer printer;
     private HashMap unique = new HashMap();
 
+//    public boolean versionHasMetaData() {
+//      return version != 2006;
+//    }
     final private static class CS_printer {
       
       private boolean newline = true;
@@ -80,6 +84,7 @@ aspect CS_CodeGenEnv {
       this.version = version;
       this.indent = indent;
       this.printer = printer;
+      this.verStr = (version == 2006) ? "2006" : "";
     }
 
     public CS_env(File f, int version) {
@@ -107,6 +112,9 @@ aspect CS_CodeGenEnv {
 
     public void unindent(int amount) {
       indent -= amount;
+      if (indent < 0) {
+        throw new Error("Negative indent level");
+      }
     }
 
     public void unindent() {
@@ -188,6 +196,7 @@ aspect CS_StructName {
 aspect CS_Void {
 
   syn boolean Decl.CS_isVoid() = getType().CS_isVoid();
+  syn boolean UserType.CS_isVoid() = decl().CS_isVoid();
   syn boolean Type.CS_isVoid() = false;
   syn boolean VoidType.CS_isVoid() = true;
 
@@ -261,6 +270,84 @@ aspect CS_Class {
 		    " not declared");
   }
 
+  public void Decl.CS_emitDeclPP(CS_env env){
+	env.println("/* ");
+	pp(env.getPrintStream());
+	
+	CS_emitUserTypeDeps(env,null,false);
+	CS_emitUserTypeRefs(env,null,false);
+	env.println("*/");
+  
+  }
+  
+  public void Decl.CS_emitUserTypeDeps(CS_env env, String via, boolean outputCode){
+//	if(env.versionHasMetaData() && hasDependencies() || isReferenced() ) {
+//	if(env.versionHasMetaData() && isSampleDecl() && outputCode) {
+//	   env.println("if(sendMetaData){");
+//	   env.indent();
+//	}
+//	Iterator<Decl> it = type_dependencies().iterator();
+//	while(it.hasNext()) {
+//	    Decl t = it.next();
+//
+//	    t.CS_emitUserTypeDeps(env, t.getName(), outputCode);
+//	    if( outputCode && t.getType().isUserType() ) {
+//               //env.println("/* FIXME: " + t.getName() + " does not exist");
+//	       env.println(t.getName()+".register(e, sendMetaData);");
+//               //env.println("*/");
+//	    } else {  // Just output a comment
+//		String refpath = (via == null) ? "directly" : "indirectly via "+via;
+//	       //env.println(" //Depends ("+refpath+") on "+t.getName() + " (" + t +") " );
+//	       //env.println(" //Depends ("+refpath+") on "+t.getName() );
+//	       env.println(" //Depends ("+refpath+") on "+t.getName()+" -- "+t.getType() );
+//	    }
+//	}
+//	if(env.versionHasMetaData() && isSampleDecl() && outputCode) {
+//	   env.unindent();
+//	   env.println("}");
+//	}
+//    }
+  }
+  
+  public void Decl.CS_emitUserTypeRefs(CS_env env, String via, boolean outputCode){
+     if( isReferenced() ) {
+        Iterator<Decl> it = type_references().iterator();
+        while(it.hasNext()) {
+            Decl t = it.next();
+
+            t.CS_emitUserTypeRefs(env, t.getName(), outputCode);
+            if(outputCode) {
+               env.println(t.getName()+".register(e);");
+            } else {  // Just output a comment
+	        String refpath = (via == null) ? "directly" : "indirectly via "+via;
+	       env.println(" //Is referenced ("+refpath+")  by "+t.getName() );
+            }
+        }
+    }
+  }
+  
+  public void Decl.CS_emitRegisterEncoder(CS_env env) {
+    env.println("public static void register(Encoder e){");
+    env.indent();
+    env.println("e.register(Dispatcher.singleton());");
+    env.unindent();
+    env.println("}");
+
+//    env.println();
+//    env.println("public static void register(Encoder e, bool sendMetaData){");
+//    env.indent();
+//
+//    CS_emitUserTypeDeps(env, null, true);
+//    if(env.versionHasMetaData()) {
+//        env.println("e.register(Dispatcher.singleton(), sendMetaData);");
+//    } else {
+//        env.println("e.register(Dispatcher.singleton());");
+//    }
+//    env.unindent();
+//    env.println("}");
+//    env.println();
+  }
+  
   public void TypeDecl.CS_emitClass(CS_env env) {
     if (getType().CS_needInstance()) {
       // Hackish prettyprint preamble
@@ -272,6 +359,11 @@ aspect CS_Class {
       env.println();
       env.indent();
       getType().CS_emitInstance(env);
+      if( isReferenced()) {
+        CS_emitRegisterEncoder(env);
+	CS_emitDispatcher(env,false);
+      }
+      CS_emitSignature(env);
       CS_emitEncoder(env);
       CS_emitDecoder(env);
       env.unindent();
@@ -303,15 +395,17 @@ aspect CS_Class {
     env.unindent();
     env.println("}");
     env.println();
-
+/*
     env.println("public static void register(Encoder e) {");
     env.indent();
     env.println("e.register(new Dispatcher());");
     env.unindent();
     env.println("}");
-    env.println(); 
+    env.println(); */
+    
+    CS_emitRegisterEncoder(env);
 
-    env.println("private class Dispatcher : SampleDispatcher {");
+    /*env.println("private class Dispatcher : LabCommDispatcher {");
     env.indent();
     env.println(); 
     env.println("public Type getSampleClass() {");
@@ -345,19 +439,20 @@ aspect CS_Class {
     env.println("");
     env.unindent();
     env.println("}");
-    env.println("");
+    env.println("");*/
+    CS_emitDispatcher(env,true);
 
     CS_emitEncoder(env);
     CS_emitDecoder(env);
-    env.println("private static byte[] signature = new byte[] {");
+    /*env.println("private static byte[] signature = new byte[] {");
     env.indent();
-    SignatureList signature = signature(env.version);
+    SignatureList signature = flatSignature(env.version);
     for (int i = 0 ; i < signature.size() ; i++) {
       String comment = signature.getComment(i);
       if (comment != null) {
         env.println(signature.getIndent(i) + "// " + comment);
       }
-      byte[] data = signature.getData(i);
+      byte[] data = signature.getData(i, env.version);
       if (data != null) {
         env.print(signature.getIndent(i));
         for (int j = 0 ; j < data.length ; j++) {
@@ -369,10 +464,148 @@ aspect CS_Class {
     env.unindent();
     env.println("};");
     env.unindent();
-    env.println();
+    env.println();*/
+    CS_emitSignature(env);
     env.println("}");
   }
 
+  public void Decl.CS_emitSignature(CS_env env) {
+    //always emit the flat signature, as it is needed
+    //for matching at the decoder side (which cannot know
+    //the type_ids of dependent types. Therefore, flat sigs
+    //are used for matching
+    CS_emitFlatSignature(env);
+//    if(isReferenced() || isSampleDecl()){
+//      Signature signature = getSignature();
+//      signature.CS_emitSignature(env, !isSampleDecl());
+//    }
+  }
+
+  public void Decl.CS_emitFlatSignature(CS_env env){
+    env.println("private static byte[] signature = new byte[] {");
+    env.indent();
+    SignatureList signature = flatSignature(env.version);
+    for (int i = 0 ; i < signature.size() ; i++) {
+      String comment = signature.getComment(i);
+      if (comment != null) {
+        env.println(signature.getIndent(i) + "// " + comment);
+      }
+      byte[] data = signature.getData(i, env.version);
+      if (data != null) {
+        env.print(signature.getIndent(i));
+        for (int j = 0 ; j < data.length ; j++) {
+          env.print(data[j] + ", ");
+        }
+        env.println();
+      }
+    }
+    env.unindent();
+    env.println("};");
+    env.println();
+  }
+
+  //XXX TODO: refactor: split into a static class ("TypeDefSingleton"?)and a (smaller) dispatcher
+  public void Decl.CS_emitDispatcher(CS_env env, boolean isSample) {
+    String genericStr = ""; //env.versionHasMetaData()?"<"+getName()+">":""; 
+    env.println("private class Dispatcher : SampleDispatcher{");
+    env.indent();
+    env.println();
+    env.println("private static Dispatcher single;");
+    env.println();
+    env.println("public static Dispatcher singleton() {");
+    env.indent();
+    env.println("lock(typeof(Dispatcher)) {");
+    env.indent();
+    env.println("if( single == null ) single = new Dispatcher();");
+    env.println("return single;");
+    env.unindent();
+    env.println("}");
+    env.unindent();
+    env.println("}");
+    env.println();
+    env.println("public Type getSampleClass() {");
+    env.indent();
+    env.println("return typeof(" + getName() + ");");
+    env.unindent();
+    env.println("}");
+    env.println();
+    env.println("public String getName() {");
+    env.indent();
+    env.println("return \"" + getName() + "\";");
+    env.unindent();
+    env.println("}");
+    env.println();
+    env.println("public byte getTypeDeclTag() {");
+    env.indent();
+    if(isSample) {
+      env.println("return Constant.SAMPLE_DEF;");
+    } else {
+      env.println("return Constant.TYPE_DEF;");
+    }
+    env.unindent();
+    env.println("}");
+    env.println();
+    env.println("public bool isSample() {");
+    env.indent();
+    env.println("return "+isSample+";");
+    env.unindent();
+    env.println("}");
+    env.println("public bool hasStaticSignature() {");
+    env.indent();
+    env.println("return "+!hasDependencies()+";");
+    env.unindent();
+    env.println("}");
+    env.println();
+    env.println("/** return the flat signature. Intended use is on decoder side */");
+    env.println("public byte[] getSignature() {");
+    env.indent();
+    env.println("return signature;");
+    env.unindent();
+    env.println("}");
+    env.println();
+//    env.println("public void encodeSignature(Encoder e) throws IOException{");
+//    env.indent();
+//    env.println("emitSignature(e);");
+//    env.unindent();
+//    env.println("}");
+//    env.println();
+//  env.println("public void encodeSignatureMetadata(Encoder e, int index){");
+//  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 bool canDecodeAndHandle() {");
+    env.indent();
+    env.println("return "+isSample+";");
+    env.unindent();
+    env.println("}");
+    env.println();
+    env.println("public void decodeAndHandle(Decoder d,");
+    env.println("                            SampleHandler h) {");
+    env.indent();
+    if( isSample) {
+        if (isVoid()) {
+          env.println(getName() + ".decode(d);");
+          env.println("((Handler)h).handle();");
+        } else {
+          env.println("((Handler)h).handle(" + getName() + ".decode(d));");
+        }
+    } else {
+        env.println("throw new Exception(\"A typedef has no handler, the corresponding method on the sample class should be called.\");");
+    }
+    env.unindent();
+    env.println("}");
+    env.println("");
+    env.unindent();
+    env.println("}");
+    env.println("");
+
+ } //TODO, fix above method
+  
   public void TypeDecl.CS_emitEncoder(CS_env env) {
     env.print("public static void encode(Encoder e");
     if (!isVoid()) {
@@ -754,6 +987,48 @@ aspect CS_Class {
 
 }
 
+aspect CS_Signature {
+    public void Signature.CS_emitSignature(CS_env env, boolean decl){
+ 
+      SignatureList sl = getSignatureList();
+      sl.CS_emitSignature(env, decl);
+    }
+
+    public abstract void SignatureLine.CS_emitSignature(CS_env env, boolean decl);
+
+    public void TypeRefSignatureLine.CS_emitSignature(CS_env env, boolean isDecl){
+      env.print(getIndentString());
+      env.println("e.encodePacked32(e.getTypeId( typeof("+decl.getName()+")));");
+    }
+
+    public void DataSignatureLine.CS_emitSignature(CS_env env, boolean decl){
+        byte[] data = getData(env.version);
+          if (data != null) {
+              env.print(getIndentString());
+              for (int j = 0 ; j < data.length ; j++) {
+                  //env.print("e.encodeByte((byte)"+data[j]+");");
+                  env.print("e.encodeByte((byte)"+ String.format("0x%02X ", data[j]) +"); ");
+              }
+              env.println();
+          }
+  }
+    public void SignatureList.CS_emitSignature(CS_env env, boolean decl) {
+      env.println("private static void emitSignature(Encoder e){");
+      env.indent();
+      for (int i = 0 ; i < size() ; i++) {
+        String comment = getComment(i);
+        if (comment != null && comment.length() > 0) {
+            env.println(getIndent(i) + "// " + comment);
+        }
+        SignatureLine l = getSignatureLine(i);
+        l.CS_emitSignature(env, decl);
+      }
+      env.println("}");
+      env.unindent();
+  }
+
+}
+
 aspect CS_Info {
 
   public void Program.CS_info(PrintStream out, String namespace, int version) {
@@ -789,3 +1064,4 @@ aspect CS_Info {
   }
 
 }
+
diff --git a/compiler/C_CodeGen.jrag b/compiler/C_CodeGen.jrag
index 9064f53..bf70105 100644
--- a/compiler/C_CodeGen.jrag
+++ b/compiler/C_CodeGen.jrag
@@ -47,6 +47,10 @@ aspect C_CodeGenEnv {
     private boolean rootIsPointer;
     private int rootLevel;
 
+    public boolean versionHasMetaData() {
+      return version != 2006;
+    }
+
     private C_env(String qualid, String lcName, String rawPrefix, 
 		  int indent, int depth, C_printer printer,
                   int nestedLevel, int version)
@@ -107,6 +111,10 @@ aspect C_CodeGenEnv {
       printer.print(this, s);
     }
 
+    public void println() {
+      printer.println(this, "");
+    }
+
     public void println(String s) {
       printer.println(this, s);
     }
@@ -392,7 +400,7 @@ aspect C_Declarations {
   
   public void Decl.C_emitEncoderDeclaration(C_env env) {
   }
-
+//
   public void SampleDecl.C_emitEncoderDeclaration(C_env env) {
     env.println("int labcomm"+env.verStr+"_encoder_register_" + 
 		env.prefix + getName() + "(");
@@ -978,13 +986,13 @@ aspect C_DecoderIoctl {
 aspect C_Encoder {
 
   public void Decl.C_emitEncoder(C_env env) {
-    throw new Error(this.getClass().getName() + 
-		    ".C_emitEncoder()" + 
-		    " not declared");
+  //XXX  throw new Error(this.getClass().getName() + 
+//		    ".C_emitEncoder()" + 
+//		    " not declared");
   }
 
-  public void TypeDecl.C_emitEncoder(C_env env) {
-  }
+//  public void TypeDecl.C_emitEncoder(C_env env) {
+//  }
 
   public void SampleDecl.C_emitEncoder(C_env env) {
     env = env.nestStruct("(*v)");
@@ -1091,14 +1099,15 @@ aspect C_Encoder {
   }
 
   public void Decl.C_emitEncoderRegisterHandler(C_env env) {
-    throw new Error(this.getClass().getName() + 
-		    ".C_emitEncoderRegisterHandler(C_env env)" + 
-		    " not declared");
-  }
-
-  public void TypeDecl.C_emitEncoderRegisterHandler(C_env env) {
-  }
-
+  //XXX
+  //  throw new Error(this.getClass().getName() + 
+  //		    ".C_emitEncoderRegisterHandler(C_env env)" + 
+  //		    " not declared");
+  }
+  //
+  //public void TypeDecl.C_emitEncoderRegisterHandler(C_env env) {
+  //}
+  //
   public void SampleDecl.C_emitEncoderRegisterHandler(C_env env) {
     env.println("int labcomm"+env.verStr+"_encoder_register_" + 
 		env.prefix + getName() + "(");
@@ -1108,6 +1117,9 @@ aspect C_Encoder {
     env.println(")");
     env.println("{");
     env.indent();
+    C_emitUserTypeDeps(env, null, false); //XXX HERE BE DRAGONS
+                                          //set to false to turn off
+                                          //outputting of code
     env.println("return labcomm"+env.verStr+"_internal_encoder_register(");
     env.indent();
     env.println("e,");
@@ -1158,6 +1170,43 @@ aspect C_EncoderIoctl {
 
 }
 
+aspect C_TypeDependencies {
+  public void Decl.C_emitUserTypeDeps(C_env env, String via, boolean outputCode) {
+    if( hasDependencies() ) {
+        Iterator<Decl> it = type_dependencies().iterator();
+        while(it.hasNext()) {
+            Decl t = it.next();
+
+            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);");
+            } else {  // Just output a comment
+	        String refpath = (via == null) ? "directly" : "indirectly via "+via;
+	       //env.println(" //Depends ("+refpath+") on "+t.getName() + " (" + t +") " );
+	       env.println(" //Depends ("+refpath+") on "+t.getName() );
+            }
+        }
+    } 
+  }
+  public void Decl.C_emitUserTypeRefs(C_env env, String via, boolean outputCode) {
+    if( isReferenced() ) {
+        Iterator<Decl> it = type_references().iterator();
+        while(it.hasNext()) {
+            Decl t = it.next();
+
+            t.C_emitUserTypeRefs(env, t.getName(), outputCode);
+            if(outputCode) {
+               env.println("labcomm"+env.verStr+"_encoder_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() );
+            }
+        }
+    } 
+  }
+}
+
 aspect C_Signature {
 
   public void ASTNode.C_emitSignature(C_env env) {
@@ -1166,19 +1215,56 @@ aspect C_Signature {
 		    " not declared");
   }
 
+  syn String Decl.C_DeclTypeString();
+  eq SampleDecl.C_DeclTypeString() = "LABCOMM_SAMPLE";
+  eq TypeDecl.C_DeclTypeString() = "LABCOMM_TYPEDEF";
+
   public void Decl.C_emitSignature(C_env env) {
+    //always emit the flat signature, as it is needed
+    //for matching at the decoder side (which cannot know
+    //the type_ids of dependent types. Therefore, flat sigs
+    //are used for matching
+    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(env.versionHasMetaData()) { 
+      if(isReferenced() || isSampleDecl()){
+          env.println("(int (*)(void *))labcomm"+env.verStr+"_signature_" + 
+  	 	env.prefix + getName() + "_emit_signature");
+      } else {
+          env.println("NULL");  // HERE BE DRAGONS! Is it worth the size saving to skip emitting the emit_signature function for unused types?
+                                //                  The code won't likely end up in a target system anyway?
+      }
+    }
+    env.unindent();
+    env.println(" };");
+*/
+  }
+
+  public void ASTNode.C_emitFlatSignature(C_env env) {
+    throw new Error(this.getClass().getName() + 
+                    ".C_emitFlatSignature(C_env env)" + 
+                    " not declared");
   }
 
-  public void SampleDecl.C_emitSignature(C_env env) {
+  public void Decl.C_emitFlatSignature(C_env env) {
+  }
+
+  public void SampleDecl.C_emitFlatSignature(C_env env){
     env.println("static unsigned char signature_bytes_" + 
-		       env.prefix + getName() + "[] = {");
-    SignatureList signature = signature(env.version);
+  	        env.prefix + getName() + "[] = {");
+    SignatureList signature = flatSignature(env.version);
     for (int i = 0 ; i < signature.size() ; i++) {
       String comment = signature.getComment(i);
       if (comment != null) {
         env.println(signature.getIndent(i) + "// " + comment);
       }
-      byte[] data = signature.getData(i);
+      byte[] data = signature.getData(i, env.version);
       if (data != null) {
         env.print(signature.getIndent(i));
         for (int j = 0 ; j < data.length ; j++) {
@@ -1188,9 +1274,10 @@ aspect C_Signature {
       }
     }
     env.println("};");
+
     C_emitSizeofValue(env);
     env.println("struct labcomm"+env.verStr+"_signature labcomm"+env.verStr+"_signature_" + 
-		env.prefix + getName() + " = {");
+        env.prefix + getName() + " = {");
     env.indent();
     env.println("\"" + getName() + "\",");
     env.println("sizeof_" + env.prefix + getName() + ",");
@@ -1201,6 +1288,109 @@ aspect C_Signature {
     env.println(" };");
   }
 
+    public void Signature.C_emitSignature(C_env env, boolean decl){
+      getSignatureList().C_emitSignature(env, decl);
+    }
+
+    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() +"),");
+    }
+
+    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("\"),");
+       // }
+    }
+/*
+
+        byte[] data = getData(env.version);
+          if (data != null) {
+              for (int j = 0 ; j < data.length ; j++) {
+                  env.print(getIndentString());
+                  //env.print("printf(\"labcomm"+env.verStr+"_write_byte( w, (unsigned char)"+ String.format("0x%02X ", data[j]) +")\\n\"); ");
+                  env.print("labcomm"+env.verStr+"_write_byte( w, (unsigned char)"+ String.format("0x%02X ", data[j]) +"); ");
+                  env.println("if (result != 0) { return result; }");
+              }
+              env.println();
+          }
+*/
+  //}
+/**
+static int encode_test_twoLines(
+struct labcomm_writer *w
+, test_twoLines *v
+)
+{
+result = labcomm_write_int(w, (*v).l1.start.x.val);
+**/
+  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();
+  }
+
+
+
+//  public void SampleDecl.C_emitSignature(C_env env) {
+//    env.println("static unsigned char signature_bytes_" + 
+//		       env.prefix + getName() + "[] = {");
+//    SignatureList signature = signature(env.version);
+//    for (int i = 0 ; i < signature.size() ; i++) {
+//      String comment = signature.getComment(i);
+//      if (comment != null) {
+//        env.println(signature.getIndent(i) + "// " + comment);
+//      }
+//      byte[] data = signature.getData(i);
+//      if (data != null) {
+//        env.print(signature.getIndent(i));
+//        for (int j = 0 ; j < data.length ; j++) {
+//          env.print(data[j] + ", ");
+//        }
+//        env.println("");
+//      }
+//    }
+//    env.println("};");
+//    env.println("struct labcomm"+env.verStr+"_signature labcomm"+env.verStr+"_signature_" + 
+//		env.prefix + getName() + " = {");
+//    env.indent();
+//    env.println("LABCOMM_SAMPLE, \"" + getName() + "\",");
+//    env.println("(int (*)(struct labcomm"+env.verStr+"_signature *, void *))labcomm"+env.verStr+"_sizeof_" + 
+//		env.prefix + getName() + ",");
+//    env.println("sizeof(signature_bytes_" + env.prefix + getName() + "),");
+//    env.println("signature_bytes_" + env.prefix + getName() + ",");
+//    env.println("0");
+//    env.unindent();
+//    env.println(" };");
+//  }
+
+}
+aspect C_Constructor {
   public void ASTNode.C_emitConstructor(C_env env) {
     throw new Error(this.getClass().getName() + 
 		    ".C_emitConstructor(C_env env)" + 
@@ -1227,7 +1417,7 @@ aspect C_Signature {
 
   public void Decl.C_emitConstructor(C_env env) {
   }
-
+//XXX
   public void SampleDecl.C_emitConstructor(C_env env) {
     env.println("labcomm"+env.verStr+"_set_local_index(&labcomm"+env.verStr+"_signature_" + 
 		env.prefix + getName() + ");");
@@ -1247,13 +1437,12 @@ aspect C_Signature {
 }
 
 aspect C_Sizeof {
-
-  public void Decl.C_emitSizeofDeclaration(C_env env) {
+ public void Decl.C_emitSizeofDeclaration(C_env env) {
   }
 
   public void SampleDecl.C_emitSizeofDeclaration(C_env env) {
     env.println("extern int labcomm"+env.verStr+"_sizeof_" + env.prefix + getName() +
-		"(" + env.prefix + getName() + " *v);");
+        "(" + env.prefix + getName() + " *v);");
   }
 
   public int Decl.C_fixedSizeof() {
@@ -1266,7 +1455,7 @@ aspect C_Sizeof {
   public void SampleDecl.C_emitSizeof(C_env env) {
     env = env.nestStruct("(*v)");
     env.println("int labcomm"+env.verStr+"_sizeof_" + env.prefix + getName() +
-		"(" + env.prefix + getName() + " *v)");
+        "(" + env.prefix + getName() + " *v)");
     env.println("{");
     env.indent();
     env.println("return labcomm"+env.verStr+"_internal_sizeof(" +
@@ -1278,8 +1467,8 @@ aspect C_Sizeof {
 
   public int Type.C_fixedSizeof() {
     throw new Error(this.getClass().getName() + 
-		    ".C_fixedSizeof()" + 
-		    " not declared");
+            ".C_fixedSizeof()" + 
+            " not declared");
   }
 
   public int VoidType.C_fixedSizeof() {
@@ -1296,9 +1485,9 @@ aspect C_Sizeof {
       case LABCOMM_FLOAT: { return 4; }
       case LABCOMM_DOUBLE: { return 8; }
       default: { 
-	throw new Error(this.getClass().getName() + 
-			".C_fixedSizeof()" + 
-			" unknown size (" + getName() + ")"); 
+    throw new Error(this.getClass().getName() + 
+            ".C_fixedSizeof()" + 
+            " unknown size (" + getName() + ")"); 
       } 
     }
   }
@@ -1346,20 +1535,20 @@ aspect C_Sizeof {
 
   public void Type.C_emitSizeof(C_env env) {
     throw new Error(this.getClass().getName() + 
-		    ".C_emitSizeof(C_env env)" + 
-		    " not declared");
+            ".C_emitSizeof(C_env env)" + 
+            " not declared");
   }
 
   public void PrimType.C_emitSizeof(C_env env) {
     switch (getToken()) {
       case LABCOMM_STRING: { 
         env.print("{ int l = strlen(" + env.qualid + "); ");
-	env.println("result += labcomm"+env.verStr+"_size_packed32(l) + l; }"); 
+    env.println("result += labcomm"+env.verStr+"_size_packed32(l) + l; }"); 
       } break;
       default: { 
-	throw new Error(this.getClass().getName() + 
-			".C_emitSizeof(C_env env)" + 
-			" known size (" + getName() + ")"); 
+    throw new Error(this.getClass().getName() + 
+            ".C_emitSizeof(C_env env)" + 
+            " known size (" + getName() + ")"); 
       } 
     }
   }
@@ -1372,10 +1561,10 @@ aspect C_Sizeof {
     int fixed = 0;
     for (int i = 0 ; i < getNumField() ; i++) {
       if (getField(i).getType().C_isDynamic()) {
-	getField(i).getType().C_emitSizeof(
-	  env.nestStruct("." + getField(i).getName()));
+    getField(i).getType().C_emitSizeof(
+      env.nestStruct("." + getField(i).getName()));
       } else {
-	fixed += getField(i).getType().C_fixedSizeof();
+    fixed += getField(i).getType().C_fixedSizeof();
       }
     }
     if (fixed > 0) {
@@ -1389,35 +1578,34 @@ aspect C_Sizeof {
       env.indent();
       C_emitLoopVariables(env);
       for (int i = 0 ; i < getNumExp() ; i++) {
-	String iterator = "i_" + env.depth + "_" + i;
-	env.println("for (" + iterator + " = 0" +
-		    " ; " +
-		    iterator + " < " + getExp(i).C_getLimit(env, i) +
-		    " ; " +
-		    iterator + "++) {");
-	env.indent();
+    String iterator = "i_" + env.depth + "_" + i;
+    env.println("for (" + iterator + " = 0" +
+            " ; " +
+            iterator + " < " + getExp(i).C_getLimit(env, i) +
+            " ; " +
+            iterator + "++) {");
+    env.indent();
       }
       C_emitCalcIndex(env);
       getType().C_emitSizeof(C_Nest(env));
       for (int i = 0 ; i < getNumExp() ; i++) {
-	env.unindent();
-	env.println("}");
+    env.unindent();
+    env.println("}");
       }
       env.unindent();
       env.println("}");
     } else {
       for (int i = 0 ; i < getNumExp() ; i++) {
-      	env.println("result += labcomm"+env.verStr+"_size_packed32(" + 
-	            getExp(i).C_getLimit(env, i) + ");");
+        env.println("result += labcomm"+env.verStr+"_size_packed32(" + 
+                getExp(i).C_getLimit(env, i) + ");");
       }
       env.print("result += " + getType().C_fixedSizeof());
       for (int i = 0 ; i < getNumExp() ; i++) {
-	env.print(" * " + getExp(i).C_getLimit(env, i));
+    env.print(" * " + getExp(i).C_getLimit(env, i));
       }
       env.println(";");      
     }
   }
-
 }
 
 aspect C_forAll {
diff --git a/compiler/DeclNames.jrag b/compiler/DeclNames.jrag
index 4e58087..042739b 100644
--- a/compiler/DeclNames.jrag
+++ b/compiler/DeclNames.jrag
@@ -4,4 +4,11 @@ aspect DeclNames {
 
 	inh String Field.declName();
 	eq StructType.getField(int i).declName() = declName();
+    
+        //TODO: aspect should be renamed to parent-something
+
+        inh Decl Type.parentDecl();
+        inh Decl Field.parentDecl();
+        eq Decl.getType().parentDecl() = this;
+        eq StructType.getField(int i).parentDecl() = parentDecl();
 }
diff --git a/compiler/FlatSignature.jrag b/compiler/FlatSignature.jrag
new file mode 100644
index 0000000..b0bbe57
--- /dev/null
+++ b/compiler/FlatSignature.jrag
@@ -0,0 +1,115 @@
+import java.util.*;
+
+aspect FlatSignature {  
+
+  public SignatureList Decl.flatSignature(int version) {
+    SignatureList result = getSignature().getFlatSignatureList();
+    return result;
+  }
+  
+  public void ASTNode.flatSignature(SignatureList list) {
+    throw new Error(this.getClass().getName() + 
+                    ".flatSignature(SignatureList list)" + 
+                    " not declared");
+  }
+
+  public void TypeDecl.flatSignature(SignatureList list) {
+    getType().flatSignature(list);
+  }
+
+  public void SampleDecl.flatSignature(SignatureList list) {
+    getType().flatSignature(list);
+  }
+
+  public void VoidType.flatSignature(SignatureList list) {
+    list.addInt(LABCOMM_STRUCT, "void");
+    list.addInt(0, null);
+  }
+
+  public void PrimType.flatSignature(SignatureList list) {
+    list.addInt(getToken(), null);
+  }
+
+  public void UserType.flatSignature(SignatureList list) {
+    lookupType(getName()).flatSignature(list);
+  }
+
+  public void ArrayType.flatSignature(SignatureList list) {
+    list.addInt(LABCOMM_ARRAY, signatureComment());
+    list.indent();
+    list.addInt(getNumExp(), null);
+    for (int i = 0 ; i < getNumExp() ; i++) {
+      getExp(i).flatSignature(list);
+    }
+    getType().flatSignature(list);
+    list.unindent();
+    list.add(null, "}");
+  }
+
+  public void StructType.flatSignature(SignatureList list) {
+    list.addInt(LABCOMM_STRUCT, "struct { " + getNumField() + " fields");
+    list.indent();
+    list.addInt(getNumField(), null);
+    for (int i = 0 ; i < getNumField() ; i++) {
+      getField(i).flatSignature(list);
+    }
+    list.unindent();
+    list.add(null, "}");
+  }
+
+  public void Field.flatSignature(SignatureList list) {
+    list.addString(getName(), signatureComment());
+    getType().flatSignature(list);
+  }
+
+  public void IntegerLiteral.flatSignature(SignatureList list) {
+    list.addInt(Integer.parseInt(getValue()), null);
+  }
+
+  public void VariableSize.flatSignature(SignatureList list) {
+    list.addInt(0, null);
+  }
+
+  public String ArrayType.signatureComment() {
+    StringBuffer result = new StringBuffer("array [");
+    for (int i = 0 ; i < getNumExp() ; i++) {
+      if (i > 0) {
+	result.append(", ");
+      }
+      result.append(getExp(i).signatureComment());
+    }
+    result.append("]");
+    return result.toString();
+  }
+
+  public String ASTNode.signatureComment() {
+    throw new Error(this.getClass().getName() + 
+                    ".signatureComment()" + 
+                    " not declared");
+  }
+
+  public String Field.signatureComment() {
+    return getType().signatureComment() + " '" + getName() +"'";
+  }
+
+  public String PrimType.signatureComment() {
+    return getName();
+  }
+
+  public String UserType.signatureComment() {
+    return getName();
+  }
+
+  public String StructType.signatureComment() {
+    return "struct";
+  }
+
+  public String IntegerLiteral.signatureComment() {
+    return getValue();
+  }
+
+  public String VariableSize.signatureComment() {
+    return "_";
+  }
+
+}
diff --git a/compiler/Java_CodeGen.jrag b/compiler/Java_CodeGen.jrag
index c21260b..92ec31a 100644
--- a/compiler/Java_CodeGen.jrag
+++ b/compiler/Java_CodeGen.jrag
@@ -4,7 +4,7 @@ import java.util.*;
 aspect Java_CodeGenEnv {
 
   // Environment wrapper for Java-code generation
-  // handles indentation, file writing, 
+  // handles indentation, file writing,
 
   public class Java_env {
 
@@ -15,13 +15,17 @@ aspect Java_CodeGenEnv {
     private Java_printer printer;
     private HashMap unique = new HashMap();
 
+    public boolean versionHasMetaData() {
+      return version != 2006;
+    }
+
     final private class Java_printer {
-      
+
       private boolean newline = true;
       private File file;
       private PrintStream out;
       private IOException exception;
-      
+
 
       public Java_printer(File f) {
   	file = f;
@@ -78,7 +82,7 @@ aspect Java_CodeGenEnv {
     }
 
     private Java_env(int version, int indent) {
-      this.version = version; 
+      this.version = version;
       this.verStr = (version == 2006) ? "2006" : "";
       this.indent = indent;
     }
@@ -234,13 +238,10 @@ aspect Java_CodeGen {
     }
   }
 
-  /** Experimental method for generating code to a map <classname, source> 
+  /** Experimental method for generating code to a map <classname, source>
     */
   public void Program.J_gen(Map<String,String> src, String pack, int version) throws IOException {
     Java_env env;
-/*
-    // Registration class was commented out, so got removed in this copy
-*/
     for (int i = 0; i < getNumDecl(); i++) {
       Decl d = getDecl(i);
       try {
@@ -256,68 +257,159 @@ aspect Java_CodeGen {
       }
     }
   }
+
 }
 
 aspect Java_Class {
 
   public void Decl.Java_emitClass(Java_env env, String pack) {
-    throw new Error(this.getClass().getName() + 
-		    ".Java_emitClass(Java_env env, String pack)" + 
+    throw new Error(this.getClass().getName() +
+		    ".Java_emitClass(Java_env env, String pack)" +
 		    " not declared");
   }
 
-  public void TypeDecl.Java_emitClass(Java_env env, String pack) {
-    if (getType().Java_needInstance()) {
+  public void Decl.Java_emitDeclPP(Java_env env) {
       // Hackish prettyprint preamble
       env.println("/* ");
       pp(env.getPrintStream());
+
+      Java_emitUserTypeDeps(env, null, false);
+      Java_emitUserTypeRefs(env, null, false);
       env.println("*/");
 
+  }
+
+  public void Decl.Java_emitUserTypeDeps(Java_env env, String via, boolean outputCode) {
+  // XXX TODO will generate unnecessary recursion for types. fix this per commented out code
+  // XXX      but ensure that types with references actually register themselves.. (i.e., add "nested" argument)
+  //public abstract void Decl.Java_emitUserTypeDeps(Java_env env, String via, boolean outputCode);
+
+  //public void TypeDecl.Java_emitUserTypeDeps(Java_env env, String via, boolean outputCode) {
+  //  // do nothing for type decls; sampledecl iterates over all dependencies and outputs
+  //  // all type decls
+  //}
+  //public void SampleDecl.Java_emitUserTypeDeps(Java_env env, String via, boolean outputCode) {
+    if(env.versionHasMetaData() && hasDependencies() || isReferenced() ) {
+        if(env.versionHasMetaData() && isSampleDecl() && outputCode) {
+           env.println("if(sendMetaData){");
+           env.indent();
+        }
+        Iterator<Decl> it = type_dependencies().iterator();
+        while(it.hasNext()) {
+            Decl t = it.next();
+
+            t.Java_emitUserTypeDeps(env, t.getName(), outputCode);
+            if( outputCode){// && t.getType().isUserType() ) {
+               env.println(t.getName()+".register(e);");
+            } else {  // Just output a comment
+	        String refpath = (via == null) ? "directly" : "indirectly via "+via;
+	       //env.println(" //Depends ("+refpath+") on "+t.getName() + " (" + t +") " );
+	       //env.println(" //Depends ("+refpath+") on "+t.getName() );
+	       env.println(" //Depends ("+refpath+") on "+t.getName()+" -- "+t.getType() );
+            }
+        }
+        if(env.versionHasMetaData() && isSampleDecl() && outputCode) {
+           env.unindent();
+           env.println("}");
+        }
+    }
+  }
+  public void Decl.Java_emitUserTypeRefs(Java_env env, String via, boolean outputCode) {
+    if( isReferenced() ) {
+        Iterator<Decl> it = type_references().iterator();
+        while(it.hasNext()) {
+            Decl t = it.next();
+
+            t.Java_emitUserTypeRefs(env, t.getName(), outputCode);
+            if(outputCode) {
+               env.println(t.getName()+".register(e);");
+            } else {  // Just output a comment
+	        String refpath = (via == null) ? "directly" : "indirectly via "+via;
+	       env.println(" //Is referenced ("+refpath+")  by "+t.getName() );
+            }
+        }
+    }
+ }
+
+
+  public void Decl.Java_emitRegisterEncoder(Java_env env) {
+    env.println("public static void register(Encoder e) throws IOException {");
+    env.indent();
+    env.println("register(e, true);");
+    env.unindent();
+    env.println("}");
+
+    env.println();
+    env.println("public static void register(Encoder e, boolean sendMetaData) throws IOException {");
+    env.indent();
+
+    Java_emitUserTypeDeps(env, null, true);
+    if(env.versionHasMetaData()) {
+        env.println("e.register(Dispatcher.singleton());");
+    } else {
+        env.println("e.register(Dispatcher.singleton());");
+    }
+    env.unindent();
+    env.println("}");
+    env.println();
+  }
+
+  public void TypeDecl.Java_emitClass(Java_env env, String pack) {
+      Java_emitDeclPP(env);
       if (pack != null && pack.length() > 0) {
-        env.println("package " + pack + ";");
+          env.println("package " + pack + ";");
       }
 
-      env.println("import java.io.IOException;");
+      env.println("import se.lth.control.labcomm"+env.verStr+".Constant;");
       env.println("import se.lth.control.labcomm"+env.verStr+".SampleType;");
-      env.println("import se.lth.control.labcomm"+env.verStr+".Encoder;");
-      env.println("import se.lth.control.labcomm"+env.verStr+".Decoder;");
-      env.println();
+
+      if (getType().Java_needInstance() || hasDependencies() || isReferenced()) {
+          env.println("import se.lth.control.labcomm"+env.verStr+".Encoder;");
+          env.println("import se.lth.control.labcomm"+env.verStr+".SampleDispatcher;");
+          env.println("import se.lth.control.labcomm"+env.verStr+".SampleHandler;");
+//          env.println();
+//      }
+//
+//      if (getType().Java_needInstance()) {
+          env.println("import java.io.IOException;");
+          env.println("import se.lth.control.labcomm"+env.verStr+".Decoder;");
+      }
+      // For types without type_dependencies and not needing an instance,
+      // currently just an empty class is generated
+
       env.println("public class " + getName() + " implements SampleType {");
       env.println();
+
       env.indent();
-      getType().Java_emitInstance(env);
-      Java_emitEncoder(env);
-      Java_emitDecoder(env);
-      env.unindent();
+      if (getType().Java_needInstance()) {
+        getType().Java_emitInstance(env);
+        Java_emitEncoder(env);
+        Java_emitDecoder(env);
+      }
+
+      //if(hasDependencies() || isReferenced()) {
+      //if( getType().isUserType() && isReferenced()) {
+      if( isReferenced()) {
+        Java_emitRegisterEncoder(env);
+        Java_emitDispatcher(env, false);
+      }
+      Java_emitSignature(env);
+
       env.println("}");
-    }
+      env.unindent();
+      env.println();
   }
 
-//  TODO: ?
-//  Code snippet for making samples of user types extend their type 
-//  currently commented out. Is this a good idea?
-//
-//  syn String Type.getTypeName();
-//  eq Type.getTypeName() = getClass().getName();
-//  eq PrimType.getTypeName() = getName();
-//  eq UserType.getTypeName() = getName();
-
-//  syn boolean Type.isUserType();
-//  eq Type.isUserType() = false;
-//  eq UserType.isUserType() = true;
-//
-// plus use some lines down
 
   public void SampleDecl.Java_emitClass(Java_env env, String pack) {
-    env.println("/* ");
-    pp(env.getPrintStream());
-    env.println("*/");
+    Java_emitDeclPP(env);
 
     if (pack != null && pack.length() > 0) {
       env.println("package " + pack + ";");
     }
 
     env.println("import java.io.IOException;");
+    env.println("import se.lth.control.labcomm"+env.verStr+".Constant;");
     env.println("import se.lth.control.labcomm"+env.verStr+".Decoder;");
     env.println("import se.lth.control.labcomm"+env.verStr+".SampleDispatcher;");
     env.println("import se.lth.control.labcomm"+env.verStr+".Encoder;");
@@ -325,6 +417,10 @@ aspect Java_Class {
     env.println("import se.lth.control.labcomm"+env.verStr+".Sample;");
     env.println();
     env.print("public class " + getName());
+//  TODO: ?
+//  Code for making samples of user types extend their type
+//  currently commented out. Is this a good idea or not?
+//
 //    if(getType().isUserType()) {
 //        env.print(" extends "+getType().getTypeName());
 //    }
@@ -341,49 +437,162 @@ aspect Java_Class {
     env.println(") throws Exception;");
     env.println("}");
     env.println();
-    env.println("public static void register(Decoder d, SampleHandler h) throws IOException {");
+    env.println("public static void register(Decoder d, Handler h) throws IOException {");
     env.indent();
-    env.println("d.register(new Dispatcher(), h);");
+    env.println("d.register(Dispatcher.singleton(), h);");
     env.unindent();
     env.println("}");
     env.println();
 
-    env.println("public static void register(Encoder e) throws IOException {");
-    env.indent();
-    env.println("e.register(new Dispatcher());");
+
+    Java_emitRegisterEncoder(env);
+    Java_emitDispatcher(env, true);
+    Java_emitEncoder(env);
+    Java_emitDecoder(env);
+
+    Java_emitSignature(env);
     env.unindent();
     env.println("}");
-    env.println(); 
+    env.println();
+  }
+
+  //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
+    //for matching at the decoder side (which cannot know
+    //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());
+    //}
+  }
+
+  public void Decl.Java_emitFlatSignature(Java_env env){
+    env.println("private static byte[] signature = new byte[] {");
+      env.indent();
+      SignatureList signature = flatSignature(env.version);
+      for (int i = 0 ; i < signature.size() ; i++) {
+        String comment = signature.getComment(i);
+        if (comment != null) {
+          env.println(signature.getIndent(i) + "// " + comment);
+        }
+        byte[] data = signature.getData(i, env.version);
+        if (data != null) {
+          env.print(signature.getIndent(i));
+          for (int j = 0 ; j < data.length ; j++) {
+          env.print(data[j] + ", ");
+        }
+        env.println();
+      }
+    }
+    env.unindent();
+    env.println("};");
+    env.unindent();
+    env.println();
+  }
 
-    env.println("private static class Dispatcher implements SampleDispatcher {");
+  //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()+">":""; 
+    env.println("private static class Dispatcher implements SampleDispatcher "+genericStr+"{");
+    env.indent();
+    env.println();
+    env.println("private static Dispatcher singleton;");
+    env.println();
+    env.println("public synchronized static Dispatcher singleton() {");
     env.indent();
-    env.println(); 
-    env.println("public Class getSampleClass() {");
+    env.println("if(singleton==null) singleton=new Dispatcher();");
+    env.println("return singleton;");
+    env.unindent();
+    env.println("}");
+    env.println();
+    env.println("public Class"+genericStr+" getSampleClass() {");
     env.indent();
     env.println("return " + getName() + ".class;");
     env.unindent();
     env.println("}");
-    env.println(); 
+    env.println();
     env.println("public String getName() {");
     env.indent();
     env.println("return \"" + getName() + "\";");
     env.unindent();
     env.println("}");
-    env.println(); 
+    env.println();
+    env.println("public byte getTypeDeclTag() {");
+    env.indent();
+    if(env.version == 2006) {
+      if(isSample) {
+        env.println("return Constant.SAMPLE;");
+      } else {
+        env.println("return Constant.TYPEDEF;");
+      }
+    } else {
+      if(isSample) {
+        env.println("return Constant.SAMPLE_DEF;");
+      } else {
+        env.println("return Constant.TYPE_DEF;");
+      }
+    }
+    env.unindent();
+    env.println("}");
+    env.println();
+    env.println("public boolean isSample() {");
+    env.indent();
+    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();
+    env.println("/** return the flat signature. Intended use is on decoder side */");
     env.println("public byte[] getSignature() {");
     env.indent();
     env.println("return signature;");
     env.unindent();
     env.println("}");
-    env.println(); 
+    env.println();
+//    env.println("public void encodeSignature(Encoder e) throws IOException{");
+//    env.indent();
+//    env.println("emitSignature(e);");
+//    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 boolean canDecodeAndHandle() {");
+    env.indent();
+    env.println("return "+isSample+";");
+    env.unindent();
+    env.println("}");
+    env.println();
     env.println("public void decodeAndHandle(Decoder d,");
     env.println("                            SampleHandler h) throws Exception {");
     env.indent();
-    if (isVoid()) {
-      env.println(getName() + ".decode(d);");
-      env.println("((Handler)h).handle_" + getName() + "();"); 
+    if( isSample) {
+        if (isVoid()) {
+          env.println(getName() + ".decode(d);");
+          env.println("((Handler)h).handle_" + getName() + "();");
+        } else {
+          env.println("((Handler)h).handle_" + getName() + "(" + getName() + ".decode(d));");
+        }
     } else {
-      env.println("((Handler)h).handle_" + getName() + "(" + getName() + ".decode(d));"); 
+        env.println("throw new Exception(\"A typedef has no handler, the corresponding method on the sample class should be called.\");");
     }
     env.unindent();
     env.println("}");
@@ -392,31 +601,8 @@ aspect Java_Class {
     env.println("}");
     env.println("");
 
-    Java_emitEncoder(env);
-    Java_emitDecoder(env);
-    env.println("private static byte[] signature = new byte[] {");
-    env.indent();
-    SignatureList signature = signature(env.version);
-    for (int i = 0 ; i < signature.size() ; i++) {
-      String comment = signature.getComment(i);
-      if (comment != null) {
-        env.println(signature.getIndent(i) + "// " + comment);
-      }
-      byte[] data = signature.getData(i);
-      if (data != null) {
-        env.print(signature.getIndent(i));
-        for (int j = 0 ; j < data.length ; j++) {
-	  env.print(data[j] + ", ");
-        }
-        env.println();
-      }
-    }
-    env.unindent();
-    env.println("};");
-    env.unindent();
-    env.println();
-    env.println("}");
-  }
+ }
+
 
   public void TypeDecl.Java_emitEncoder(Java_env env) {
     env.print("public static void encode(Encoder e");
@@ -451,8 +637,8 @@ aspect Java_Class {
   }
 
   public void Type.Java_emitEncoder(Java_env env, String name) {
-    throw new Error(this.getClass().getName() + 
-		    ".Java_emitEncoder(Java_env env, String name)" + 
+    throw new Error(this.getClass().getName() +
+		    ".Java_emitEncoder(Java_env env, String name)" +
 		    " not declared");
   }
 
@@ -492,10 +678,10 @@ aspect Java_Class {
       env.print_block_end();
     }
   }
-  
+
   public String Exp.Java_emitEncoder(Java_env env, String name) {
-    throw new Error(this.getClass().getName() + 
-		    ".Java_emitEncoder(Java_env env, String name)" + 
+    throw new Error(this.getClass().getName() +
+		    ".Java_emitEncoder(Java_env env, String name)" +
 		    " not declared");
   }
 
@@ -540,8 +726,8 @@ aspect Java_Class {
   }
 
   public void Type.Java_emitDecoder(Java_env env, String name) {
-    throw new Error(this.getClass().getName() + 
-		    ".Java_emitDecoder(Java_env env, String name)" + 
+    throw new Error(this.getClass().getName() +
+		    ".Java_emitDecoder(Java_env env, String name)" +
 		    " not declared");
   }
 
@@ -573,7 +759,7 @@ aspect Java_Class {
     }
     for (int i = 0 ; i < getNumExp() ; i++) {
       String limit = "i_" + (baseDepth + i) + "_max";
-      env.print(name + " = "); 
+      env.print(name + " = ");
       Java_emitNew(env, limit, getNumExp() - i);
       env.println(";");
       name = name + env.print_for_begin(limit);
@@ -587,8 +773,8 @@ aspect Java_Class {
   }
 
   public void Exp.Java_emitDecoder(Java_env env) {
-    throw new Error(this.getClass().getName() + 
-		    ".Java_emitDecoder(Java_env env)" + 
+    throw new Error(this.getClass().getName() +
+		    ".Java_emitDecoder(Java_env env)" +
 		    " not declared");
   }
 
@@ -619,8 +805,8 @@ aspect Java_Class {
   }
 
   public void Type.Java_emitNew(Java_env env, String size) {
-    throw new Error(this.getClass().getName() + 
-		    ".Java_emitNew(Java_env env, String size)" + 
+    throw new Error(this.getClass().getName() +
+		    ".Java_emitNew(Java_env env, String size)" +
 		    " not declared");
   }
 
@@ -635,8 +821,8 @@ aspect Java_Class {
   }
 
   public void Type.Java_emitTypePrefix(Java_env env) {
-    throw new Error(this.getClass().getName() + 
-		    ".Java_emitTypePrefix(Java_env env)" + 
+    throw new Error(this.getClass().getName() +
+		    ".Java_emitTypePrefix(Java_env env)" +
 		    " not declared");
   }
 
@@ -652,7 +838,7 @@ aspect Java_Class {
       env.print(getName());
     } else {
       decl().getType().Java_emitTypePrefix(env);
-    } 
+    }
   }
 
   public void ArrayType.Java_emitTypePrefix(Java_env env){
@@ -669,7 +855,7 @@ aspect Java_Class {
   public void UserType.Java_emitTypeSuffix(Java_env env) {
     if (! Java_needInstance()) {
       decl().getType().Java_emitTypeSuffix(env);
-    } 
+    }
   }
 
   public void ArrayType.Java_emitTypeSuffix(Java_env env){
@@ -680,8 +866,8 @@ aspect Java_Class {
   }
 
   public boolean Type.Java_needInstance() {
-    throw new Error(this.getClass().getName() + 
-		    ".Java_needInstance()" + 
+    throw new Error(this.getClass().getName() +
+		    ".Java_needInstance()" +
 		    " not declared");
   }
 
@@ -714,8 +900,8 @@ aspect Java_Class {
   }
 
   public void Type.Java_emitInstance(Java_env env) {
-    throw new Error(this.getClass().getName() + 
-		    ".Java_emitInstance(Java_env env)" + 
+    throw new Error(this.getClass().getName() +
+		    ".Java_emitInstance(Java_env env)" +
 		    " not declared");
   }
 
@@ -753,12 +939,12 @@ aspect Java_Class {
   public void Field.Java_emitField(Java_env env) {
     env.print("public ");
     getType().Java_emitType(env);
-    env.println(" " + getName() + ";");    
+    env.println(" " + getName() + ";");
   }
 
   public void Type.Java_emitType(Java_env env) {
-    throw new Error(this.getClass().getName() + 
-		    ".Java_emitType(Java_env env)" + 
+    throw new Error(this.getClass().getName() +
+		    ".Java_emitType(Java_env env)" +
 		    " not declared");
   }
 
@@ -787,6 +973,53 @@ aspect Java_Class {
   public void StructType.Java_emitType(Java_env env){
     env.print(Java_structName());
   }
+}
+
+aspect Java_Signature {
+    public void Signature.Java_emitSignature(Java_env env, boolean decl){
+      // XXX should sendOnlyFlatSignatures be kept somewhere?
+      //SignatureList sl = (parentDecl().sendOnlyFlatSignatures(env)) ? getFlatSignatureList() : getSignatureList();
+      SignatureList sl = getSignatureList();
+      sl.Java_emitSignature(env, decl);
+    }
+
+//    public void Signature.Java_emitHierarchicalSignature(Java_env env, boolean decl){
+//      SignatureList sl = getSignatureList();
+//      sl.Java_emitSignature(env, decl);
+//    }
+//
+    public abstract void SignatureLine.Java_emitSignature(Java_env env, boolean decl);
+
+    public void TypeRefSignatureLine.Java_emitSignature(Java_env env, boolean isDecl){
+      env.print(getIndentString());
+      env.println("e.encodePacked32(e.getTypeId("+decl.getName()+".class));");
+    }
+
+    public void DataSignatureLine.Java_emitSignature(Java_env env, boolean decl){
+        byte[] data = getData(env.version);
+          if (data != null) {
+              env.print(getIndentString());
+              for (int j = 0 ; j < data.length ; j++) {
+                  //env.print("e.encodeByte((byte)"+data[j]+");");
+                  env.print("e.encodeByte((byte)"+ String.format("0x%02X ", data[j]) +"); ");
+              }
+              env.println();
+          }
+  }
+    public void SignatureList.Java_emitSignature(Java_env env, boolean decl) {
+      env.println("private static void emitSignature(Encoder e) throws IOException{");
+      env.indent();
+      for (int i = 0 ; i < size() ; i++) {
+        String comment = getComment(i);
+        if (comment != null && comment.length() > 0) {
+            env.println(getIndent(i) + "// " + comment);
+        }
+        SignatureLine l = getSignatureLine(i);
+        l.Java_emitSignature(env, decl);
+      }
+      env.println("}");
+      env.unindent();
+  }
 
 }
 
@@ -800,14 +1033,14 @@ aspect Java_Info {
   }
 
   public void Decl.Java_info(Java_env env) {
-    throw new Error(this.getClass().getName() + 
-		    ".Java_info(Java_env env)" + 
+    throw new Error(this.getClass().getName() +
+		    ".Java_info(Java_env env)" +
 		    " not declared");
   }
 
   public void TypeDecl.Java_info(Java_env env) {
     env.print(",Java,typedef," + getName() + ",");
-    getType().Java_emitType(env); 
+    getType().Java_emitType(env);
     env.print(",not_applicable_for_Java");
     env.println();
   }
diff --git a/compiler/LabComm.ast b/compiler/LabComm.ast
index 6f290e5..95151dd 100644
--- a/compiler/LabComm.ast
+++ b/compiler/LabComm.ast
@@ -1,6 +1,21 @@
 Program ::= Decl*;
 
-abstract Decl ::= Type <Name:String>;
+//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;
 SampleDecl : Decl;
 
diff --git a/compiler/LabComm.java b/compiler/LabComm.java
index a2250d9..6337301 100644
--- a/compiler/LabComm.java
+++ b/compiler/LabComm.java
@@ -78,6 +78,7 @@ public class LabComm {
   }
 
   private static void genCS(Program p, String csName, String csNamespace, int ver) {
+//      throw new Error("C# generation currently disabled");
     try {
       p.CS_gen(csName, csNamespace, ver);
     } catch (IOException e) {
diff --git a/compiler/LabCommTokens.jrag b/compiler/LabCommTokens.jrag
new file mode 100644
index 0000000..7b7b2e3
--- /dev/null
+++ b/compiler/LabCommTokens.jrag
@@ -0,0 +1,19 @@
+aspect LabCommTokens {
+
+  public static final int ASTNode.LABCOMM_VERSION   =  0x01;  
+  public static final int ASTNode.LABCOMM_SAMPLE    =  0x02;  // The flat signature
+  public static final int ASTNode.LABCOMM_TYPE_DEF  =  0x03;  // and type declarations, hierarchically
+
+  public static final int ASTNode.LABCOMM_ARRAY =      0x10;
+  public static final int ASTNode.LABCOMM_STRUCT =     0x11;
+
+  public static final int ASTNode.LABCOMM_BOOLEAN =    0x20; 
+  public static final int ASTNode.LABCOMM_BYTE =       0x21;
+  public static final int ASTNode.LABCOMM_SHORT =      0x22;
+  public static final int ASTNode.LABCOMM_INT =        0x23;
+  public static final int ASTNode.LABCOMM_LONG =       0x24;
+  public static final int ASTNode.LABCOMM_FLOAT =      0x25;
+  public static final int ASTNode.LABCOMM_DOUBLE =     0x26;
+  public static final int ASTNode.LABCOMM_STRING =     0x27;
+
+}
diff --git a/compiler/LabCommmTokens.jrag b/compiler/LabCommmTokens.jrag
deleted file mode 100644
index 351e5b4..0000000
--- a/compiler/LabCommmTokens.jrag
+++ /dev/null
@@ -1,18 +0,0 @@
-aspect LabCommTokens {
-
-  public static final int ASTNode.LABCOMM_TYPEDEF = 0x01;
-  public static final int ASTNode.LABCOMM_SAMPLE =  0x02;
-
-  public static final int ASTNode.LABCOMM_ARRAY =   0x10;
-  public static final int ASTNode.LABCOMM_STRUCT =  0x11;
-
-  public static final int ASTNode.LABCOMM_BOOLEAN = 0x20; 
-  public static final int ASTNode.LABCOMM_BYTE =    0x21;
-  public static final int ASTNode.LABCOMM_SHORT =   0x22;
-  public static final int ASTNode.LABCOMM_INT =     0x23;
-  public static final int ASTNode.LABCOMM_LONG =    0x24;
-  public static final int ASTNode.LABCOMM_FLOAT =   0x25;
-  public static final int ASTNode.LABCOMM_DOUBLE =  0x26;
-  public static final int ASTNode.LABCOMM_STRING =  0x27;
-
-}
\ No newline at end of file
diff --git a/compiler/NameAnalysis.jrag b/compiler/NameAnalysis.jrag
index e77264a..bf06055 100644
--- a/compiler/NameAnalysis.jrag
+++ b/compiler/NameAnalysis.jrag
@@ -34,7 +34,11 @@ aspect NameAnalysis {
     return null;
   }
 
-  syn TypeDecl UserType.decl() = lookupType(getName());
+  //syn TypeDecl UserType.decl() = lookupType(getName());
+  syn TypeDecl Type.decl(); 
+  eq Type.decl() = null;
+  eq UserType.decl() = lookupType(getName());
+  eq PrimType.decl() = null; //HERE BE DRAGONS XXX
   
   
   public void ASTNode.nameCheck() {
diff --git a/compiler/PrettyPrint.jrag b/compiler/PrettyPrint.jrag
index 371a76c..405bee3 100644
--- a/compiler/PrettyPrint.jrag
+++ b/compiler/PrettyPrint.jrag
@@ -68,6 +68,10 @@ aspect PrettyPrint {
     out.print("void");
   }
 
+  public String PrimType.toString() {
+    return getName();
+  }
+
   public void PrimType.ppPrefix(PrintStream out) { 
     out.print(getName());
   }
diff --git a/compiler/Python_CodeGen.jrag b/compiler/Python_CodeGen.jrag
index 7a41813..4d19724 100644
--- a/compiler/Python_CodeGen.jrag
+++ b/compiler/Python_CodeGen.jrag
@@ -81,17 +81,16 @@ aspect Python_CodeGen {
     env.println("# Auto generated " + baseName);
     env.println();
     env.println("import labcomm");
+    env.println("import StringIO");
     env.println();
     Python_genTypes(env);
-/* Typedefs curenntly disabled
-    env.println("typedef = [");
-    env.indent();
-    for (int i = 0 ; i < getNumDecl() ; i++) {
-      getDecl(i).Python_genTypedefListEntry(env);
-    }
-    env.unindent();
-    env.println("]");
-*/
+    //env.println("typedef = [");
+    //env.indent();
+    //for (int i = 0 ; i < getNumDecl() ; i++) {
+    //  getDecl(i).Python_genTypedefListEntry(env);
+    //}
+    //env.unindent();
+    //env.println("]");
     env.println("sample = [");
     env.indent();
     for (int i = 0 ; i < getNumDecl() ; i++) {
@@ -229,3 +228,4 @@ aspect PythonTypes {
   }
 
 }
+
diff --git a/compiler/RAPID_CodeGen.jrag b/compiler/RAPID_CodeGen.jrag
index 5e49e26..b367ee5 100644
--- a/compiler/RAPID_CodeGen.jrag
+++ b/compiler/RAPID_CodeGen.jrag
@@ -97,19 +97,21 @@ aspect RAPID_CodeGen {
 		throw new UnsupportedOperationException("RAPID code generation (currently) does not support "+getClass().getSimpleName());
 	}
 
-	public void SampleDecl.RAPID_gen(RAPID_env env) {
-		// Add type declarations
-		String fullName = getType().RAPID_AddType(env, getName());
-		// Add signature constants
-		String sig_len_name = "signature_len_" + getName();
-		String sig_name = "signature_" + getName();
-		SignatureList sig = signature(env.version);
+	public void TypeDecl.RAPID_gen(RAPID_env env) {
+		System.out.println("***WARNING! TypeDecl.RapidGen(.) a NOP after sig reorganization.");
+		System.out.println("            (Tell a developer to) remove this warning when tested");
+	}
+
+	public void Decl.RAPID_emitFlatSignature(RAPID_env env, String sig_len_name, String sig_name) {
+		System.out.println("***WARNING! Code not tested after reorganization of signatures.");
+		System.out.println("            (Tell a developer to) remove this warning when tested");
+		SignatureList sig = flatSignature(env.version);
 		StringBuilder sb = new StringBuilder();
 		sb.append("[");
 		byte[] d = null;
 		int sig_len = 0;
 		for (int i = 0; i < sig.size(); i++) {
-			d = sig.getData(i);
+			d = sig.getData(i, env.version);
 			for (int j = 0; d != null && j < d.length; j++) {
 				sb.append(d[j] + ",");
 				sig_len++;
@@ -119,8 +121,18 @@ aspect RAPID_CodeGen {
 		sb.append("]");
 		env.addConstant("num", sig_len_name, "" + sig_len);
 		env.addConstant("byte", sig_name + "{" + sig_len_name + "}",
-			sb.toString());
-		
+		sb.toString());
+	} 
+
+	public void SampleDecl.RAPID_gen(RAPID_env env) {
+		// Add type declarations
+		String fullName = getType().RAPID_AddType(env, getName());
+		// Add signature constants
+		String sig_len_name = "signature_len_" + getName();
+		String sig_name = "signature_" + getName();
+
+		RAPID_emitFlatSignature(env, sig_len_name, sig_name);
+
 		// Add decode procedures
 		ArrayList<String> params = new ArrayList<String>();
 		ArrayList<String> stmts = new ArrayList<String>();
diff --git a/compiler/Signature.jrag b/compiler/Signature.jrag
index 8004f2f..5bb5907 100644
--- a/compiler/Signature.jrag
+++ b/compiler/Signature.jrag
@@ -2,54 +2,92 @@ import java.util.*;
 
 aspect Signature {  
 
-  public class SignatureLine {
-  
-    private int indent;
-    private byte[] data;
-    private String comment;
+  syn boolean Decl.isSampleDecl();
+  eq TypeDecl.isSampleDecl() = false;
+  eq SampleDecl.isSampleDecl() = true;
 
-    public SignatureLine(int indent, byte[] data, String comment) {
-      this.indent = indent;
-      this.data = data;
-      this.comment = comment;
-    }
+  syn boolean Decl.sendOnlyFlatSignatures(Java_env env) = (env.version==2006);
+
+  eq Decl.getSignature().parentDecl() = this;
+  eq Signature.getSignatureList().parentDecl() = parentDecl();
+
+  inh Decl Signature.parentDecl();
+  inh Decl SignatureList.parentDecl();
+
+
+  syn nta Signature Decl.getSignature() { 
+    SignatureList sl = new SignatureList();
+    genSigLineForDecl(sl, true);
+    SignatureList fsl = new SignatureList();
+    flatSignature(fsl);
+    Signature sig = new Signature();
+    sig.setSignatureList(sl);
+    sig.setFlatSignatureList(fsl);
+    // HERE BE DRAGONS. Is this correct for a NTA?
+    setSignature(sig);
+    return sig;
+  }
+
+  //syn nta SignatureList Signature.getSignatureList() {
+  //  SignatureList result = new SignatureList();
+  //  genSigLineForDecl(result, true);
+  //  return result;
+  //}
 
-    public int getIndent() {
-      return indent;
+    public String SignatureLine.getIndentString() {
+      StringBuffer result = new StringBuffer();
+      int indent = getIndent();
+      for (int i = 0 ; i < indent ; i++) {
+        result.append("  ");
+      }
+      return result.toString();
     }
 
-    public byte[] getData() {
-      return data;
+    //Very temporary kludge: the flat signature generation 
+    //predates the SignatureLine class hierarchy. This hack
+    //returns size zero arrays, which doesn't break the sig
+    //generation
+    //public byte[] getData() {
+    syn byte[] SignatureLine.getData(int version) {
+      return new byte[0];
     }
 
-    public String getComment() {
-      return comment;
+    private Decl TypeRefSignatureLine.decl;
+    public TypeRefSignatureLine.TypeRefSignatureLine(int indent, Decl decl, String comment) {
+      super(indent, comment);
+      this.decl = decl;
+    }
+    public void SignatureList.addTypeRef(Decl type, String comment) {
+        addSignatureLine(new TypeRefSignatureLine(indent, type, comment));
     }
 
-  }
+    public ByteArraySignatureLine.ByteArraySignatureLine(int indent, byte[] data, String comment) {
+      super(indent, comment);
+      setData(data);
+    }
 
-  public class SignatureList {
+    public IntSignatureLine.IntSignatureLine(int indent, int data, String comment) {
+      super(indent, comment);
+      setData(data);
+    }
 
-    private int indent;
-    private final int ver;
-    private ArrayList list = new ArrayList();
-    
-    public SignatureList(int version) {
-      this.ver = version; 
+    public void SignatureList.add(byte[] data, String comment) {
+      addSignatureLine(new ByteArraySignatureLine(indent, data, comment));
     }
 
-    public void add(byte[] data, String comment) {
-      list.add(new SignatureLine(indent, data, comment));
+    public void SignatureList.addInt(int data, String comment) {
+      addSignatureLine(new IntSignatureLine(indent, data, comment));
     }
 
-    public void addInt(int value, String comment) {
-      switch(ver) {
+    protected byte[] DataSignatureLine.getIntBytes(int value, int version) {
+      byte data[];
+      switch(version) {
         case 2006:             // Use old encoding with 32 bit integers
-	    byte[] data = new byte[4];
+	    data = new byte[4];
 	    for (int i = 0 ; i < 4 ; i++) {
 	        data[3 - i] = (byte)((value >> (8 * i)) & 0xff);
 	    }
-	    add(data, comment);
+	    //add(data, comment);
         break;
         case 2013:             // Use new encoding with varints
 	    byte[] tmp = new byte[5];
@@ -62,162 +100,146 @@ aspect Signature {
             for (i = i - 1, j = 0 ; i >= 0 ; i--, j++) {
 		packed[j] = (byte)(tmp[i] | (i!=0?0x80:0x00));
             }
-	    add(packed, comment);
+	    //add(packed, comment);
+            data = packed;
         break;
         default: 
-            throw new RuntimeException("Version = "+ver+". This should never happen.");
+            throw new RuntimeException("Unsupported version = "+version+". This should never happen.");
       }
+      return data;
     }
 
-    public void addString(String value, String comment) {
-      addInt(value.length(), comment);
-      byte[] data = new byte[value.length()];
-      for (int i = 0 ; i < value.length() ; i++) {
-        data[i] = (byte)(value.charAt(i) & 0xff);
+    eq IntSignatureLine.getData(int version) {
+      return getIntBytes(getData(), version);
+    }
+
+    public void SignatureList.addString(String data, String comment) {
+      addSignatureLine(new StringSignatureLine(indent, comment, data));
+    }
+    eq StringSignatureLine.getData(int version) {
+      byte[] lenBytes = getIntBytes(getData().length(), version);
+      byte[] data = new byte[lenBytes.length+getData().length()];
+
+      // first add the encoded length
+      for (int i = 0 ; i < lenBytes.length ; i++) {
+        data[i] = lenBytes[i];
+      }
+      // and then the actual chars
+      for (int i = 0 ; i < getData().length() ; i++) {
+        int idx = lenBytes.length + i;
+        data[idx] = (byte)(getData().charAt(i) & 0xff);
       }
-      add(data, null);
+      return data;
     }
 
-    public int size() {
-      return list.size();
+    public int SignatureList.size() {
+      return getNumSignatureLine();
     }
 
-    public String getIndent(int i) {
+    public String SignatureList.getIndent(int i) {
       StringBuffer result = new StringBuffer();
-      int indent = ((SignatureLine)list.get(i)).getIndent();
+      int indent = getSignatureLine(i).getIndent();
       for (i = 0 ; i < indent ; i++) {
         result.append("  ");
       }
       return result.toString();
     }
 
-    public byte[] getData(int i) {
-      return ((SignatureLine)list.get(i)).getData();
+    public byte[] SignatureList.getData(int i, int version) {
+      return getSignatureLine(i).getData(version);
     }
 
-    public String getComment(int i) {
-      return ((SignatureLine)list.get(i)).getComment();
+    public String SignatureList.getComment(int i) {
+      return getSignatureLine(i).getComment();
     }
 
-    public void indent() {
+    private int SignatureList.indent;
+
+    public void SignatureList.indent() {
       indent++;
     }
 
-    public void unindent() {
+    public void SignatureList.unindent() {
       indent--;
     }
 
-  }
 
-  public SignatureList Decl.signature(int version) {
-    SignatureList result = new SignatureList(version);
-    flatSignature(result);
-    return result;
-  }
-
-  public void ASTNode.flatSignature(SignatureList list) {
+  public void ASTNode.genSigLineForDecl(SignatureList list, boolean decl) {
     throw new Error(this.getClass().getName() + 
-                    ".flatSignature(SignatureList list)" + 
+                    ".genSigLineForDecl(SignatureList list)" + 
                     " not declared");
   }
 
-  public void TypeDecl.flatSignature(SignatureList list) {
-    getType().flatSignature(list);
+  public void TypeDecl.genSigLineForDecl(SignatureList list, boolean decl) {
+     System.out.println("************ TypeDecl.genSigLine("+decl+").... for "+getName());
+    if(decl){
+      getType().genSigLineForDecl(list, decl);
+    }else{
+      list.addTypeRef(this, "//TODO (from list.addTypeRef)");
+    }
   }
 
-  public void SampleDecl.flatSignature(SignatureList list) {
-    getType().flatSignature(list);
+  public void SampleDecl.genSigLineForDecl(SignatureList list, boolean decl) {
+     System.out.println("************ SampleDecl.genSigLine("+decl+").... for "+getName());
+    getType().genSigLineForDecl(list, decl);
   }
 
-  public void VoidType.flatSignature(SignatureList list) {
+  public void VoidType.genSigLineForDecl(SignatureList list, boolean decl) {
     list.addInt(LABCOMM_STRUCT, "void");
     list.addInt(0, null);
   }
 
-  public void PrimType.flatSignature(SignatureList list) {
+  public void PrimType.genSigLineForDecl(SignatureList list, boolean decl) {
     list.addInt(getToken(), null);
   }
 
-  public void UserType.flatSignature(SignatureList list) {
-    lookupType(getName()).flatSignature(list);
+  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.flatSignature(SignatureList list) {
+  public void ArrayType.genSigLineForDecl(SignatureList list, boolean decl) {
     list.addInt(LABCOMM_ARRAY, signatureComment());
     list.indent();
     list.addInt(getNumExp(), null);
     for (int i = 0 ; i < getNumExp() ; i++) {
-      getExp(i).flatSignature(list);
+      getExp(i).genSigLineForDecl(list, false);
     }
-    getType().flatSignature(list);
+    getType().genSigLineForDecl(list, false);
     list.unindent();
     list.add(null, "}");
   }
 
-  public void StructType.flatSignature(SignatureList list) {
+  public void StructType.genSigLineForDecl(SignatureList list, boolean decl) {
     list.addInt(LABCOMM_STRUCT, "struct { " + getNumField() + " fields");
     list.indent();
     list.addInt(getNumField(), null);
     for (int i = 0 ; i < getNumField() ; i++) {
-      getField(i).flatSignature(list);
+      getField(i).genSigLineForDecl(list, false);
     }
     list.unindent();
     list.add(null, "}");
   }
 
-  public void Field.flatSignature(SignatureList list) {
+  public void Field.genSigLineForDecl(SignatureList list, boolean decl) {
     list.addString(getName(), signatureComment());
-    getType().flatSignature(list);
+    getType().genSigLineForDecl(list, decl);
   }
 
-  public void IntegerLiteral.flatSignature(SignatureList list) {
+  public void IntegerLiteral.genSigLineForDecl(SignatureList list, boolean decl) {
     list.addInt(Integer.parseInt(getValue()), null);
   }
 
-  public void VariableSize.flatSignature(SignatureList list) {
+  public void VariableSize.genSigLineForDecl(SignatureList list, boolean decl) {
     list.addInt(0, null);
   }
-
-  public String ArrayType.signatureComment() {
-    StringBuffer result = new StringBuffer("array [");
-    for (int i = 0 ; i < getNumExp() ; i++) {
-      if (i > 0) {
-	result.append(", ");
-      }
-      result.append(getExp(i).signatureComment());
-    }
-    result.append("]");
-    return result.toString();
-  }
-
-  public String ASTNode.signatureComment() {
-    throw new Error(this.getClass().getName() + 
-                    ".signatureComment()" + 
-                    " not declared");
-  }
-
-  public String Field.signatureComment() {
-    return getType().signatureComment() + " '" + getName() +"'";
-  }
-
-  public String PrimType.signatureComment() {
-    return getName();
-  }
-
-  public String UserType.signatureComment() {
-    return getName();
-  }
-
-  public String StructType.signatureComment() {
-    return "struct";
-  }
-
-  public String IntegerLiteral.signatureComment() {
-    return getValue();
-  }
-
-  public String VariableSize.signatureComment() {
-    return "_";
-  }
-
 }
diff --git a/compiler/TypeCheck.jrag b/compiler/TypeCheck.jrag
index a61224b..a640ace 100644
--- a/compiler/TypeCheck.jrag
+++ b/compiler/TypeCheck.jrag
@@ -9,13 +9,7 @@ aspect TypeCheck {
   syn boolean Type.isNull();
   eq Type.isNull() = false;
   eq VoidType.isNull() = true;
-  eq UserType.isNull()  {
-    if (decl() != null) {
-      return decl().isNull();
-    } else {
-      return false;
-    }
-  }
+  eq UserType.isNull() = decl().isNull();
 
   syn boolean TypeDecl.isNull();
   eq TypeDecl.isNull() = getType().isNull();
diff --git a/compiler/TypeReferences.jrag b/compiler/TypeReferences.jrag
new file mode 100644
index 0000000..0a7cd9b
--- /dev/null
+++ b/compiler/TypeReferences.jrag
@@ -0,0 +1,46 @@
+aspect User_Types {
+  syn String Type.getTypeName();
+  eq Type.getTypeName() = getClass().getName();
+  eq PrimType.getTypeName() = getName();
+  eq UserType.getTypeName() = getName();
+
+  syn boolean Type.isUserType();
+  eq Type.isUserType() = false;
+  eq UserType.isUserType() = true;
+}
+
+aspect Type_References {
+ 
+  // The dependencies on other type declarations for a Decl.
+  coll Set<Decl> Decl.type_dependencies() [new HashSet<Decl>()] with add;
+
+  Field contributes ((UserType)getType()).decl()   
+  when parentDecl() != null && getType().isUserType()
+  to Decl.type_dependencies() 
+  for parentDecl();
+
+  UserType contributes decl()   
+  when parentDecl() != null 
+  to Decl.type_dependencies() 
+  for parentDecl();
+  /*
+  Field contributes getType().decl()   
+  when parentDecl() != null && getType().isLeafType()
+  to Decl.type_dependencies() 
+  for parentDecl();
+  */
+
+
+  // The references from other type declarations to a Decl.
+  coll Set<Decl> Decl.type_references() [new HashSet<Decl>()] with add;
+
+  Decl contributes this
+  to Decl.type_references()
+  for each type_dependencies();
+
+  syn boolean Decl.hasDependencies();
+  eq Decl.hasDependencies() = !type_dependencies().isEmpty();
+
+  syn boolean Decl.isReferenced();
+  eq Decl.isReferenced() = !type_references().isEmpty();
+}
diff --git a/compiler/build.xml b/compiler/build.xml
index b7e3035..5c80942 100644
--- a/compiler/build.xml
+++ b/compiler/build.xml
@@ -29,7 +29,9 @@ classpath="tools/jastadd2.jar"/>
 <!-- compile sources -->
 <target name="build" depends="gen">
 	<javac debug="true" nowarn="true" srcdir="." includes="**/*.java" excludes="test/** examples/**" classpath=".:${tools}/beaver-rt.jar:${tools}/junit.jar"
-   fork="true" memoryMaximumSize="128M"/>
+   fork="true" memoryMaximumSize="128M">
+                 <!-- compilerarg value="-Xlint"/ -->
+        </javac>
 </target>
 	
 
diff --git a/lib/c/labcomm_private.h b/lib/c/labcomm_private.h
index 1ba35c7..d42c24c 100644
--- a/lib/c/labcomm_private.h
+++ b/lib/c/labcomm_private.h
@@ -39,29 +39,31 @@
 /*
  * Allowed packet tags
  */
-#define LABCOMM_VERSION  0x01
-#define LABCOMM_SAMPLE   0x02
-#define LABCOMM_PRAGMA   0x3f
-#define LABCOMM_USER     0x40 /* ..0xffffffff */
+#define LABCOMM_VERSION     0x01
+#define LABCOMM_SAMPLE      0x02
+#define LABCOMM_TYPEDEF     0x03
+#define LABCOMM_TYPEBINDING 0x04
+#define LABCOMM_PRAGMA      0x3f
+#define LABCOMM_USER        0x40 /* ..0xffffffff */
 
 
 /*
  * Predefined aggregate type indices
  */
-#define LABCOMM_ARRAY    0x10
-#define LABCOMM_STRUCT   0x11
+#define LABCOMM_ARRAY       0x10
+#define LABCOMM_STRUCT      0x11
 
 /*
  * Predefined primitive type indices
  */
-#define LABCOMM_BOOLEAN  0x20 
-#define LABCOMM_BYTE     0x21
-#define LABCOMM_SHORT    0x22
-#define LABCOMM_INT      0x23
-#define LABCOMM_LONG     0x24
-#define LABCOMM_FLOAT    0x25
-#define LABCOMM_DOUBLE   0x26
-#define LABCOMM_STRING   0x27
+#define LABCOMM_BOOLEAN     0x20 
+#define LABCOMM_BYTE        0x21
+#define LABCOMM_SHORT       0x22
+#define LABCOMM_INT         0x23
+#define LABCOMM_LONG        0x24
+#define LABCOMM_FLOAT       0x25
+#define LABCOMM_DOUBLE      0x26
+#define LABCOMM_STRING      0x27
 
 
 /*
diff --git a/lib/csharp/se/lth/control/labcomm/Constant.cs b/lib/csharp/se/lth/control/labcomm/Constant.cs
index 170cb55..cc7deac 100644
--- a/lib/csharp/se/lth/control/labcomm/Constant.cs
+++ b/lib/csharp/se/lth/control/labcomm/Constant.cs
@@ -8,7 +8,9 @@ namespace se.lth.control.labcomm {
      * Allowed packet tags
      */
     public const int VERSION          = 0x01;
-    public const int SAMPLE           = 0x02;
+    public const int SAMPLE_DEF       = 0x02;
+    public const int TYPE_DEF         = 0x03;
+    public const int TYPE_BINDING     = 0x04;
     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 19e4e0d..60e94b1 100644
--- a/lib/csharp/se/lth/control/labcomm/DecoderChannel.cs
+++ b/lib/csharp/se/lth/control/labcomm/DecoderChannel.cs
@@ -28,7 +28,7 @@ namespace se.lth.control.labcomm {
 			          version + " != " + Constant.CURRENT_VERSION);
           }
         } break;
-        case Constant.SAMPLE: {
+        case Constant.SAMPLE_DEF: {
           int index = decodePacked32();
           String name = decodeString();
           int signature_length = decodePacked32();
diff --git a/lib/csharp/se/lth/control/labcomm/EncoderChannel.cs b/lib/csharp/se/lth/control/labcomm/EncoderChannel.cs
index ca717d5..7ecd506 100644
--- a/lib/csharp/se/lth/control/labcomm/EncoderChannel.cs
+++ b/lib/csharp/se/lth/control/labcomm/EncoderChannel.cs
@@ -23,7 +23,7 @@ namespace se.lth.control.labcomm {
 
     public void register(SampleDispatcher dispatcher) {
       int index = registry.add(dispatcher);
-      begin(Constant.SAMPLE);
+      begin(Constant.SAMPLE_DEF);
       encodePacked32(index);
       encodeString(dispatcher.getName());
       byte[] signature = dispatcher.getSignature();
diff --git a/lib/java/se/lth/control/labcomm/SampleDispatcher.java b/lib/java/se/lth/control/labcomm/SampleDispatcher.java
index 8051296..a878828 100644
--- a/lib/java/se/lth/control/labcomm/SampleDispatcher.java
+++ b/lib/java/se/lth/control/labcomm/SampleDispatcher.java
@@ -1,6 +1,6 @@
 package se.lth.control.labcomm;
 
-public interface SampleDispatcher {
+public interface SampleDispatcher <T> {
     
   public Class getSampleClass();
     
-- 
GitLab