Initial Contribution
diff --git a/Type.cpp b/Type.cpp
new file mode 100755
index 0000000..a44072d
--- /dev/null
+++ b/Type.cpp
@@ -0,0 +1,1228 @@
+#include "Type.h"
+
+Namespace NAMES;
+
+Type* VOID_TYPE;
+Type* BOOLEAN_TYPE;
+Type* BYTE_TYPE;
+Type* CHAR_TYPE;
+Type* INT_TYPE;
+Type* LONG_TYPE;
+Type* FLOAT_TYPE;
+Type* DOUBLE_TYPE;
+Type* STRING_TYPE;
+Type* CHAR_SEQUENCE_TYPE;
+Type* TEXT_UTILS_TYPE;
+Type* REMOTE_EXCEPTION_TYPE;
+Type* RUNTIME_EXCEPTION_TYPE;
+Type* IBINDER_TYPE;
+Type* IINTERFACE_TYPE;
+Type* BINDER_NATIVE_TYPE;
+Type* BINDER_PROXY_TYPE;
+Type* PARCEL_TYPE;
+Type* PARCELABLE_INTERFACE_TYPE;
+Type* MAP_TYPE;
+Type* LIST_TYPE;
+Type* CLASSLOADER_TYPE;
+
+Expression* NULL_VALUE;
+Expression* THIS_VALUE;
+Expression* SUPER_VALUE;
+Expression* TRUE_VALUE;
+Expression* FALSE_VALUE;
+
+void
+register_base_types()
+{
+    VOID_TYPE = new BasicType("void", "XXX", "XXX", "XXX", "XXX", "XXX");
+    NAMES.Add(VOID_TYPE);
+
+    BOOLEAN_TYPE = new BooleanType();
+    NAMES.Add(BOOLEAN_TYPE);
+
+    BYTE_TYPE = new BasicType("byte", "writeByte", "readByte",
+                "writeByteArray", "createByteArray", "readByteArray");
+    NAMES.Add(BYTE_TYPE);
+
+    CHAR_TYPE = new CharType();
+    NAMES.Add(CHAR_TYPE);
+
+    INT_TYPE = new BasicType("int", "writeInt", "readInt",
+                "writeIntArray", "createIntArray", "readIntArray");
+    NAMES.Add(INT_TYPE);
+
+    LONG_TYPE = new BasicType("long", "writeLong", "readLong",
+                "writeLongArray", "createLongArray", "readLongArray");
+    NAMES.Add(LONG_TYPE);
+
+    FLOAT_TYPE = new BasicType("float", "writeFloat", "readFloat",
+                "writeFloatArray", "createFloatArray", "readFloatArray");
+    NAMES.Add(FLOAT_TYPE);
+
+    DOUBLE_TYPE = new BasicType("double", "writeDouble", "readDouble",
+                "writeDoubleArray", "createDoubleArray", "readDoubleArray");
+    NAMES.Add(DOUBLE_TYPE);
+
+    STRING_TYPE = new StringType();
+    NAMES.Add(STRING_TYPE);
+
+    CHAR_SEQUENCE_TYPE = new CharSequenceType();
+    NAMES.Add(CHAR_SEQUENCE_TYPE);
+
+    MAP_TYPE = new MapType();
+    NAMES.Add(MAP_TYPE);
+
+    LIST_TYPE = new ListType();
+    NAMES.Add(LIST_TYPE);
+
+    TEXT_UTILS_TYPE = new Type("android.text", "TextUtils",
+                                    Type::BUILT_IN, false, false);
+    NAMES.Add(TEXT_UTILS_TYPE);
+
+    REMOTE_EXCEPTION_TYPE = new RemoteExceptionType();
+    NAMES.Add(REMOTE_EXCEPTION_TYPE);
+
+    RUNTIME_EXCEPTION_TYPE = new RuntimeExceptionType();
+    NAMES.Add(RUNTIME_EXCEPTION_TYPE);
+
+    IBINDER_TYPE = new IBinderType();
+    NAMES.Add(IBINDER_TYPE);
+
+    IINTERFACE_TYPE = new IInterfaceType();
+    NAMES.Add(IINTERFACE_TYPE);
+
+    BINDER_NATIVE_TYPE = new BinderType();
+    NAMES.Add(BINDER_NATIVE_TYPE);
+
+    BINDER_PROXY_TYPE = new BinderProxyType();
+    NAMES.Add(BINDER_PROXY_TYPE);
+
+    PARCEL_TYPE = new ParcelType();
+    NAMES.Add(PARCEL_TYPE);
+
+    PARCELABLE_INTERFACE_TYPE = new ParcelableInterfaceType();
+    NAMES.Add(PARCELABLE_INTERFACE_TYPE);
+
+    CLASSLOADER_TYPE = new ClassLoaderType();
+    NAMES.Add(CLASSLOADER_TYPE);
+
+    NULL_VALUE = new LiteralExpression("null");
+    THIS_VALUE = new LiteralExpression("this");
+    SUPER_VALUE = new LiteralExpression("super");
+    TRUE_VALUE = new LiteralExpression("true");
+    FALSE_VALUE = new LiteralExpression("false");
+
+    NAMES.AddGenericType("java.util", "List", 1);
+    NAMES.AddGenericType("java.util", "Map", 2);
+}
+
+static Type*
+make_generic_type(const string& package, const string& name,
+                    const vector<Type*>& args)
+{
+    if (package == "java.util" && name == "List") {
+        return new GenericListType("java.util", "List", args);
+    }
+    return NULL;
+    //return new GenericType(package, name, args);
+}
+
+// ================================================================
+
+Type::Type(const string& name, int kind, bool canWriteToParcel, bool canBeOut)
+    :m_package(),
+     m_name(name),
+     m_declFile(""),
+     m_declLine(-1),
+     m_kind(kind),
+     m_canWriteToParcel(canWriteToParcel),
+     m_canBeOut(canBeOut)
+{
+    m_qualifiedName = name;
+}
+
+Type::Type(const string& package, const string& name,
+            int kind, bool canWriteToParcel, bool canBeOut,
+            const string& declFile, int declLine)
+    :m_package(package),
+     m_name(name),
+     m_declFile(declFile),
+     m_declLine(declLine),
+     m_kind(kind),
+     m_canWriteToParcel(canWriteToParcel),
+     m_canBeOut(canBeOut)
+{
+    if (package.length() > 0) {
+        m_qualifiedName = package;
+        m_qualifiedName += '.';
+    }
+    m_qualifiedName += name;
+}
+
+Type::~Type()
+{
+}
+
+bool
+Type::CanBeArray() const
+{
+    return false;
+}
+
+string
+Type::ImportType() const
+{
+    return m_qualifiedName;
+}
+
+string
+Type::CreatorName() const
+{
+    return "";
+}
+
+string
+Type::InstantiableName() const
+{
+    return QualifiedName();
+}
+
+
+void
+Type::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%sn",
+            __FILE__, __LINE__, m_qualifiedName.c_str());
+    addTo->Add(new LiteralExpression("/* WriteToParcel error "
+                + m_qualifiedName + " */"));
+}
+
+void
+Type::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n",
+            __FILE__, __LINE__, m_qualifiedName.c_str());
+    addTo->Add(new LiteralExpression("/* CreateFromParcel error "
+                + m_qualifiedName + " */"));
+}
+
+void
+Type::ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n",
+            __FILE__, __LINE__, m_qualifiedName.c_str());
+    addTo->Add(new LiteralExpression("/* ReadFromParcel error "
+                + m_qualifiedName + " */"));
+}
+
+void
+Type::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n",
+            __FILE__, __LINE__, m_qualifiedName.c_str());
+    addTo->Add(new LiteralExpression("/* WriteArrayToParcel error "
+                + m_qualifiedName + " */"));
+}
+
+void
+Type::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
+                            Variable* parcel)
+{
+    fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n",
+            __FILE__, __LINE__, m_qualifiedName.c_str());
+    addTo->Add(new LiteralExpression("/* CreateArrayFromParcel error "
+                + m_qualifiedName + " */"));
+}
+
+void
+Type::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n",
+            __FILE__, __LINE__, m_qualifiedName.c_str());
+    addTo->Add(new LiteralExpression("/* ReadArrayFromParcel error "
+                + m_qualifiedName + " */"));
+}
+
+void
+Type::SetQualifiedName(const string& qualified)
+{
+    m_qualifiedName = qualified;
+}
+
+Expression*
+Type::BuildWriteToParcelFlags(int flags)
+{
+    if (flags == 0) {
+        return new LiteralExpression("0");
+    }
+    if ((flags&PARCELABLE_WRITE_RETURN_VALUE) != 0) {
+        return new FieldVariable(PARCELABLE_INTERFACE_TYPE,
+                "PARCELABLE_WRITE_RETURN_VALUE");
+    }
+    return new LiteralExpression("0");
+}
+
+// ================================================================
+
+BasicType::BasicType(const string& name, const string& marshallMethod,
+                     const string& unmarshallMethod,
+                     const string& writeArray, const string& createArray,
+                     const string& readArray)
+    :Type(name, BUILT_IN, true, false),
+     m_marshallMethod(marshallMethod),
+     m_unmarshallMethod(unmarshallMethod),
+     m_writeArrayMethod(writeArray),
+     m_createArrayMethod(createArray),
+     m_readArrayMethod(readArray)
+{
+}
+
+void
+BasicType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    addTo->Add(new MethodCall(parcel, m_marshallMethod, 1, v));
+}
+
+void
+BasicType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    addTo->Add(new Assignment(v, new MethodCall(parcel, m_unmarshallMethod)));
+}
+
+bool
+BasicType::CanBeArray() const
+{
+    return true;
+}
+
+void
+BasicType::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    addTo->Add(new MethodCall(parcel, m_writeArrayMethod, 1, v));
+}
+
+void
+BasicType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
+                            Variable* parcel)
+{
+    addTo->Add(new Assignment(v, new MethodCall(parcel, m_createArrayMethod)));
+}
+
+void
+BasicType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    addTo->Add(new MethodCall(parcel, m_readArrayMethod, 1, v));
+}
+
+
+// ================================================================
+
+BooleanType::BooleanType()
+    :Type("boolean", BUILT_IN, true, false)
+{
+}
+
+void
+BooleanType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    addTo->Add(new MethodCall(parcel, "writeInt", 1, 
+                new Ternary(v, new LiteralExpression("1"),
+                    new LiteralExpression("0"))));
+}
+
+void
+BooleanType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    addTo->Add(new Assignment(v, new Comparison(new LiteralExpression("0"),
+                    "!=", new MethodCall(parcel, "readInt"))));
+}
+
+bool
+BooleanType::CanBeArray() const
+{
+    return true;
+}
+
+void
+BooleanType::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    addTo->Add(new MethodCall(parcel, "writeBooleanArray", 1, v));
+}
+
+void
+BooleanType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
+                            Variable* parcel)
+{
+    addTo->Add(new Assignment(v, new MethodCall(parcel, "createBooleanArray")));
+}
+
+void
+BooleanType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    addTo->Add(new MethodCall(parcel, "readBooleanArray", 1, v));
+}
+
+
+// ================================================================
+
+CharType::CharType()
+    :Type("char", BUILT_IN, true, false)
+{
+}
+
+void
+CharType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    addTo->Add(new MethodCall(parcel, "writeInt", 1, 
+                    new Cast(INT_TYPE, v)));
+}
+
+void
+CharType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    addTo->Add(new Assignment(v, new MethodCall(parcel, "readInt"), this));
+}
+
+bool
+CharType::CanBeArray() const
+{
+    return true;
+}
+
+void
+CharType::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    addTo->Add(new MethodCall(parcel, "writeCharArray", 1, v));
+}
+
+void
+CharType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
+                            Variable* parcel)
+{
+    addTo->Add(new Assignment(v, new MethodCall(parcel, "createCharArray")));
+}
+
+void
+CharType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    addTo->Add(new MethodCall(parcel, "readCharArray", 1, v));
+}
+
+// ================================================================
+
+StringType::StringType()
+    :Type("java.lang", "String", BUILT_IN, true, false)
+{
+}
+
+string
+StringType::CreatorName() const
+{
+    return "android.os.Parcel.STRING_CREATOR";
+}
+
+void
+StringType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    addTo->Add(new MethodCall(parcel, "writeString", 1, v));
+}
+
+void
+StringType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    addTo->Add(new Assignment(v, new MethodCall(parcel, "readString")));
+}
+
+bool
+StringType::CanBeArray() const
+{
+    return true;
+}
+
+void
+StringType::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    addTo->Add(new MethodCall(parcel, "writeStringArray", 1, v));
+}
+
+void
+StringType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
+                            Variable* parcel)
+{
+    addTo->Add(new Assignment(v, new MethodCall(parcel, "createStringArray")));
+}
+
+void
+StringType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    addTo->Add(new MethodCall(parcel, "readStringArray", 1, v));
+}
+
+// ================================================================
+
+CharSequenceType::CharSequenceType()
+    :Type("java.lang", "CharSequence", BUILT_IN, true, false)
+{
+}
+
+string
+CharSequenceType::CreatorName() const
+{
+    return "android.os.Parcel.STRING_CREATOR";
+}
+
+void
+CharSequenceType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    // if (v != null) {
+    //     parcel.writeInt(1);
+    //     v.writeToParcel(parcel);
+    // } else {
+    //     parcel.writeInt(0);
+    // }
+    IfStatement* elsepart = new IfStatement();
+    elsepart->statements->Add(new MethodCall(parcel, "writeInt", 1,
+                                new LiteralExpression("0")));
+    IfStatement* ifpart = new IfStatement;
+    ifpart->expression = new Comparison(v, "!=", NULL_VALUE);
+    ifpart->elseif = elsepart;
+    ifpart->statements->Add(new MethodCall(parcel, "writeInt", 1,
+                                new LiteralExpression("1")));
+    ifpart->statements->Add(new MethodCall(TEXT_UTILS_TYPE, "writeToParcel",
+                                3, v, parcel, BuildWriteToParcelFlags(flags)));
+
+    addTo->Add(ifpart);
+}
+
+void
+CharSequenceType::CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                Variable* parcel)
+{
+    // if (0 != parcel.readInt()) {
+    //     v = TextUtils.createFromParcel(parcel)
+    // } else {
+    //     v = null;
+    // }
+    IfStatement* elsepart = new IfStatement();
+    elsepart->statements->Add(new Assignment(v, NULL_VALUE));
+
+    IfStatement* ifpart = new IfStatement();
+    ifpart->expression = new Comparison(new LiteralExpression("0"), "!=",
+                new MethodCall(parcel, "readInt"));
+    ifpart->elseif = elsepart;
+    ifpart->statements->Add(new Assignment(v,
+                new MethodCall(TEXT_UTILS_TYPE,
+                                    "CHAR_SEQUENCE_CREATOR.createFromParcel", 1, parcel)));
+
+    addTo->Add(ifpart);
+}
+
+
+// ================================================================
+
+RemoteExceptionType::RemoteExceptionType()
+    :Type("android.os", "RemoteException", BUILT_IN, false, false)
+{
+}
+
+void
+RemoteExceptionType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+void
+RemoteExceptionType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+// ================================================================
+
+RuntimeExceptionType::RuntimeExceptionType()
+    :Type("java.lang", "RuntimeException", BUILT_IN, false, false)
+{
+}
+
+void
+RuntimeExceptionType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+void
+RuntimeExceptionType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+
+// ================================================================
+
+IBinderType::IBinderType()
+    :Type("android.os", "IBinder", BUILT_IN, true, false)
+{
+}
+
+void
+IBinderType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    addTo->Add(new MethodCall(parcel, "writeStrongBinder", 1, v));
+}
+
+void
+IBinderType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    addTo->Add(new Assignment(v, new MethodCall(parcel, "readStrongBinder")));
+}
+
+void
+IBinderType::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    addTo->Add(new MethodCall(parcel, "writeBinderArray", 1, v));
+}
+
+void
+IBinderType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
+                            Variable* parcel)
+{
+    addTo->Add(new Assignment(v, new MethodCall(parcel, "createBinderArray")));
+}
+
+void
+IBinderType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    addTo->Add(new MethodCall(parcel, "readBinderArray", 1, v));
+}
+
+
+// ================================================================
+
+IInterfaceType::IInterfaceType()
+    :Type("android.os", "IInterface", BUILT_IN, false, false)
+{
+}
+
+void
+IInterfaceType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+void
+IInterfaceType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+
+// ================================================================
+
+BinderType::BinderType()
+    :Type("android.os", "Binder", BUILT_IN, false, false)
+{
+}
+
+void
+BinderType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+void
+BinderType::CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel)
+{
+    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+
+// ================================================================
+
+BinderProxyType::BinderProxyType()
+    :Type("android.os", "BinderProxy", BUILT_IN, false, false)
+{
+}
+
+void
+BinderProxyType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+void
+BinderProxyType::CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel)
+{
+    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+
+// ================================================================
+
+ParcelType::ParcelType()
+    :Type("android.os", "Parcel", BUILT_IN, false, false)
+{
+}
+
+void
+ParcelType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+void
+ParcelType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+// ================================================================
+
+ParcelableInterfaceType::ParcelableInterfaceType()
+    :Type("android.os", "Parcelable", BUILT_IN, false, false)
+{
+}
+
+void
+ParcelableInterfaceType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+void
+ParcelableInterfaceType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+// ================================================================
+
+MapType::MapType()
+    :Type("java.util", "Map", BUILT_IN, true, true)
+{
+}
+
+void
+MapType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    addTo->Add(new MethodCall(parcel, "writeMap", 1, v));
+}
+
+void
+MapType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    Variable *cl = new Variable(CLASSLOADER_TYPE, "cl");
+    addTo->Add(new VariableDeclaration(cl,
+        new LiteralExpression("this.getClass().getClassLoader()"),
+        CLASSLOADER_TYPE));
+    addTo->Add(new Assignment(v, new MethodCall(parcel, "readHashMap", 1, cl)));
+}
+
+void
+MapType::ReadFromParcel(StatementBlock* addTo, Variable* v,
+                    Variable* parcel)
+{
+    Variable *cl = new Variable(CLASSLOADER_TYPE, "cl");
+    addTo->Add(new VariableDeclaration(cl, 
+        new LiteralExpression("this.getClass().getClassLoader()"),
+        CLASSLOADER_TYPE));
+    addTo->Add(new MethodCall(parcel, "readMap", 2, v, cl));
+}
+
+
+// ================================================================
+
+ListType::ListType()
+    :Type("java.util", "List", BUILT_IN, true, true)
+{
+}
+
+string
+ListType::InstantiableName() const
+{
+    return "java.util.ArrayList";
+}
+
+void
+ListType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    addTo->Add(new MethodCall(parcel, "writeList", 1, v));
+}
+
+void
+ListType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    Variable *cl = new Variable(CLASSLOADER_TYPE, "cl");
+    addTo->Add(new VariableDeclaration(cl, 
+        new LiteralExpression("this.getClass().getClassLoader()"),
+        CLASSLOADER_TYPE));
+    addTo->Add(new Assignment(v, new MethodCall(parcel, "readArrayList", 1, cl)));
+}
+
+void
+ListType::ReadFromParcel(StatementBlock* addTo, Variable* v,
+                    Variable* parcel)
+{
+    Variable *cl = new Variable(CLASSLOADER_TYPE, "cl");
+    addTo->Add(new VariableDeclaration(cl, 
+        new LiteralExpression("this.getClass().getClassLoader()"),
+        CLASSLOADER_TYPE));
+    addTo->Add(new MethodCall(parcel, "readList", 2, v, cl));
+}
+
+
+// ================================================================
+
+ParcelableType::ParcelableType(const string& package, const string& name,
+                        bool builtIn, const string& declFile, int declLine)
+    :Type(package, name, builtIn ? BUILT_IN : PARCELABLE, true, true,
+            declFile, declLine)
+{
+}
+
+string
+ParcelableType::CreatorName() const
+{
+    return QualifiedName() + ".CREATOR";
+}
+
+void
+ParcelableType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    // if (v != null) {
+    //     parcel.writeInt(1);
+    //     v.writeToParcel(parcel);
+    // } else {
+    //     parcel.writeInt(0);
+    // }
+    IfStatement* elsepart = new IfStatement();
+    elsepart->statements->Add(new MethodCall(parcel, "writeInt", 1,
+                                new LiteralExpression("0")));
+    IfStatement* ifpart = new IfStatement;
+    ifpart->expression = new Comparison(v, "!=", NULL_VALUE);
+    ifpart->elseif = elsepart;
+    ifpart->statements->Add(new MethodCall(parcel, "writeInt", 1,
+                                new LiteralExpression("1")));
+    ifpart->statements->Add(new MethodCall(v, "writeToParcel", 2,
+                                parcel, BuildWriteToParcelFlags(flags)));
+
+    addTo->Add(ifpart);
+}
+
+void
+ParcelableType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    // if (0 != parcel.readInt()) {
+    //     v = CLASS.CREATOR.createFromParcel(parcel)
+    // } else {
+    //     v = null;
+    // }
+    IfStatement* elsepart = new IfStatement();
+    elsepart->statements->Add(new Assignment(v, NULL_VALUE));
+
+    IfStatement* ifpart = new IfStatement();
+    ifpart->expression = new Comparison(new LiteralExpression("0"), "!=",
+                new MethodCall(parcel, "readInt"));
+    ifpart->elseif = elsepart;
+    ifpart->statements->Add(new Assignment(v,
+                new MethodCall(v->type, "CREATOR.createFromParcel", 1, parcel)));
+
+    addTo->Add(ifpart);
+}
+
+void
+ParcelableType::ReadFromParcel(StatementBlock* addTo, Variable* v,
+                    Variable* parcel)
+{
+    // TODO: really, we don't need to have this extra check, but we
+    // don't have two separate marshalling code paths
+    // if (0 != parcel.readInt()) {
+    //     v.readFromParcel(parcel)
+    // }
+    IfStatement* ifpart = new IfStatement();
+    ifpart->expression = new Comparison(new LiteralExpression("0"), "!=",
+                new MethodCall(parcel, "readInt"));
+    ifpart->statements->Add(new MethodCall(v, "readFromParcel", 1, parcel));
+    addTo->Add(ifpart);
+}
+
+bool
+ParcelableType::CanBeArray() const
+{
+    return true;
+}
+
+void
+ParcelableType::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    addTo->Add(new MethodCall(parcel, "writeTypedArray", 2, v,
+                BuildWriteToParcelFlags(flags)));
+}
+
+void
+ParcelableType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
+                            Variable* parcel)
+{
+    string creator = v->type->QualifiedName() + ".CREATOR";
+    addTo->Add(new Assignment(v, new MethodCall(parcel,
+                "createTypedArray", 1, new LiteralExpression(creator))));
+}
+
+void
+ParcelableType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    string creator = v->type->QualifiedName() + ".CREATOR";
+    addTo->Add(new MethodCall(parcel, "readTypedArray", 2,
+                    v, new LiteralExpression(creator)));
+}
+
+
+// ================================================================
+
+InterfaceType::InterfaceType(const string& package, const string& name,
+                        bool builtIn, bool oneway,
+                        const string& declFile, int declLine)
+    :Type(package, name, builtIn ? BUILT_IN : INTERFACE, true, false,
+                        declFile, declLine)
+    ,m_oneway(oneway)
+{
+}
+
+bool
+InterfaceType::OneWay() const
+{
+    return m_oneway;
+}
+
+void
+InterfaceType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    // parcel.writeStrongBinder(v != null ? v.asBinder() : null);
+    addTo->Add(new MethodCall(parcel, "writeStrongBinder", 1, 
+                new Ternary(
+                    new Comparison(v, "!=", NULL_VALUE),
+                    new MethodCall(v, "asBinder"),
+                    NULL_VALUE)));
+}
+
+void
+InterfaceType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    // v = Interface.asInterface(parcel.readStrongBinder());
+    string type = v->type->QualifiedName();
+    type += ".Stub";
+    addTo->Add(new Assignment(v,
+                new MethodCall( NAMES.Find(type), "asInterface", 1,
+                    new MethodCall(parcel, "readStrongBinder"))));
+}
+
+
+// ================================================================
+
+GenericType::GenericType(const string& package, const string& name,
+                         const vector<Type*>& args)
+    :Type(package, name, BUILT_IN, true, true)
+{
+    m_args = args;
+
+    m_importName = package + '.' + name;
+
+    string gen = "<";
+    int N = args.size();
+    for (int i=0; i<N; i++) {
+        Type* t = args[i];
+        gen += t->QualifiedName();
+        if (i != N-1) {
+            gen += ',';
+        }
+    }
+    gen += '>';
+    m_genericArguments = gen;
+    SetQualifiedName(m_importName + gen);
+}
+
+string
+GenericType::GenericArguments() const
+{
+    return m_genericArguments;
+}
+
+string
+GenericType::ImportType() const
+{
+    return m_importName;
+}
+
+void
+GenericType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    fprintf(stderr, "implement GenericType::WriteToParcel\n");
+}
+
+void
+GenericType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    fprintf(stderr, "implement GenericType::CreateFromParcel\n");
+}
+
+void
+GenericType::ReadFromParcel(StatementBlock* addTo, Variable* v,
+                            Variable* parcel)
+{
+    fprintf(stderr, "implement GenericType::ReadFromParcel\n");
+}
+
+
+// ================================================================
+
+GenericListType::GenericListType(const string& package, const string& name,
+                         const vector<Type*>& args)
+    :GenericType(package, name, args),
+     m_creator(args[0]->CreatorName())
+{
+}
+
+string
+GenericListType::CreatorName() const
+{
+    return "android.os.Parcel.arrayListCreator";
+}
+
+string
+GenericListType::InstantiableName() const
+{
+    return "java.util.ArrayList" + GenericArguments();
+}
+
+void
+GenericListType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    if (m_creator == STRING_TYPE->CreatorName()) {
+        addTo->Add(new MethodCall(parcel, "writeStringList", 1, v));
+    } else if (m_creator == IBINDER_TYPE->CreatorName()) {
+        addTo->Add(new MethodCall(parcel, "writeBinderList", 1, v));
+    } else {
+        // parcel.writeTypedListXX(arg);
+        addTo->Add(new MethodCall(parcel, "writeTypedList", 1, v));
+    }
+}
+
+void
+GenericListType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    if (m_creator == STRING_TYPE->CreatorName()) {
+        addTo->Add(new Assignment(v,
+                   new MethodCall(parcel, "createStringArrayList", 0)));
+    } else if (m_creator == IBINDER_TYPE->CreatorName()) {
+        addTo->Add(new Assignment(v,
+                   new MethodCall(parcel, "createBinderArrayList", 0)));
+    } else {
+        // v = _data.readTypedArrayList(XXX.creator);
+        addTo->Add(new Assignment(v,
+                   new MethodCall(parcel, "createTypedArrayList", 1,
+                   new LiteralExpression(m_creator))));
+    }
+}
+
+void
+GenericListType::ReadFromParcel(StatementBlock* addTo, Variable* v,
+                            Variable* parcel)
+{
+    if (m_creator == STRING_TYPE->CreatorName()) {
+        addTo->Add(new MethodCall(parcel, "readStringList", 1, v));
+    } else if (m_creator == IBINDER_TYPE->CreatorName()) {
+        addTo->Add(new MethodCall(parcel, "readBinderList", 1, v));
+    } else {
+        // v = _data.readTypedList(v, XXX.creator);
+        addTo->Add(new MethodCall(parcel, "readTypedList", 2,
+                       v,
+                       new LiteralExpression(m_creator)));
+    }
+}
+
+// ================================================================
+
+ClassLoaderType::ClassLoaderType()
+    :Type("java.lang", "ClassLoader", BUILT_IN, false, false)
+{
+}
+
+
+// ================================================================
+
+Namespace::Namespace()
+{
+}
+
+Namespace::~Namespace()
+{
+    int N = m_types.size();
+    for (int i=0; i<N; i++) {
+        delete m_types[i];
+    }
+}
+
+void
+Namespace::Add(Type* type)
+{
+    Type* t = Find(type->QualifiedName());
+    if (t == NULL) {
+        m_types.push_back(type);
+    }
+}
+
+void
+Namespace::AddGenericType(const string& package, const string& name, int args)
+{
+    Generic g;
+        g.package = package;
+        g.name = name;
+        g.qualified = package + '.' + name;
+        g.args = args;
+    m_generics.push_back(g);
+}
+
+Type*
+Namespace::Find(const string& name) const
+{
+    int N = m_types.size();
+    for (int i=0; i<N; i++) {
+        if (m_types[i]->QualifiedName() == name) {
+            return m_types[i];
+        }
+    }
+    return NULL;
+}
+
+Type*
+Namespace::Find(const char* package, const char* name) const
+{
+    string s;
+    if (package != NULL) {
+        s += package;
+        s += '.';
+    }
+    s += name;
+    return Find(s);
+}
+
+static string
+normalize_generic(const string& s)
+{
+    string r;
+    int N = s.size();
+    for (int i=0; i<N; i++) {
+        char c = s[i];
+        if (!isspace(c)) {
+            r += c;
+        }
+    }
+    return r;
+}
+
+Type*
+Namespace::Search(const string& name)
+{
+    // an exact match wins
+    Type* result = Find(name);
+    if (result != NULL) {
+        return result;
+    }
+
+    // try the class names
+    // our language doesn't allow you to not specify outer classes
+    // when referencing an inner class.  that could be changed, and this
+    // would be the place to do it, but I don't think the complexity in
+    // scoping rules is worth it.
+    int N = m_types.size();
+    for (int i=0; i<N; i++) {
+        if (m_types[i]->Name() == name) {
+            return m_types[i];
+        }
+    }
+
+    // we got to here and it's not a generic, give up
+    if (name.find('<') == name.npos) {
+        return NULL;
+    }
+
+    // remove any whitespace
+    string normalized = normalize_generic(name);
+
+    // find the part before the '<', find a generic for it
+    ssize_t baseIndex = normalized.find('<');
+    string base(normalized.c_str(), baseIndex);
+    const Generic* g = search_generic(base);
+    if (g == NULL) {
+        return NULL;
+    }
+
+    // For each of the args, do a recursive search on it.  We don't allow
+    // generics within generics like Java does, because we're really limiting
+    // them to just built-in container classes, at least for now.  Our syntax
+    // ensures this right now as well.
+    vector<Type*> args;
+    size_t start = baseIndex + 1;
+    size_t end = start;
+    while (normalized[start] != '\0') {
+        end = normalized.find(',', start);
+        if (end == normalized.npos) {
+            end = normalized.find('>', start);
+        }
+        string s(normalized.c_str()+start, end-start);
+        Type* t = this->Search(s);
+        if (t == NULL) {
+            // maybe we should print a warning here?
+            return NULL;
+        }
+        args.push_back(t);
+        start = end+1;
+    }
+
+    // construct a GenericType, add it to our name set so they always get
+    // the same object, and return it.
+    result = make_generic_type(g->package, g->name, args);
+    if (result == NULL) {
+        return NULL;
+    }
+
+    this->Add(result);
+    return this->Find(result->QualifiedName());
+}
+
+const Namespace::Generic*
+Namespace::search_generic(const string& name) const
+{
+    int N = m_generics.size();
+
+    // first exact match
+    for (int i=0; i<N; i++) {
+        const Generic& g = m_generics[i];
+        if (g.qualified == name) {
+            return &g;
+        }
+    }
+
+    // then name match
+    for (int i=0; i<N; i++) {
+        const Generic& g = m_generics[i];
+        if (g.name == name) {
+            return &g;
+        }
+    }
+
+    return NULL;
+}
+
+void
+Namespace::Dump() const
+{
+    int n = m_types.size();
+    for (int i=0; i<n; i++) {
+        Type* t = m_types[i];
+        printf("type: package=%s name=%s qualifiedName=%s\n",
+                t->Package().c_str(), t->Name().c_str(),
+                t->QualifiedName().c_str());
+    }
+}