Revert "Move frameworks/base/tools/ to frameworks/tools/"

This reverts commit 9f6a119c8aa276432ece4fe2118bd8a3c9b1067e.
diff --git a/AST.cpp b/AST.cpp
new file mode 100644
index 0000000..bfa6765
--- /dev/null
+++ b/AST.cpp
@@ -0,0 +1,912 @@
+#include "AST.h"
+#include "Type.h"
+
+void
+WriteModifiers(FILE* to, int mod, int mask)
+{
+    int m = mod & mask;
+
+    if (m & OVERRIDE) {
+        fprintf(to, "@Override ");
+    }
+
+    if ((m & SCOPE_MASK) == PUBLIC) {
+        fprintf(to, "public ");
+    }
+    else if ((m & SCOPE_MASK) == PRIVATE) {
+        fprintf(to, "private ");
+    }
+    else if ((m & SCOPE_MASK) == PROTECTED) {
+        fprintf(to, "protected ");
+    }
+
+    if (m & STATIC) {
+        fprintf(to, "static ");
+    }
+    
+    if (m & FINAL) {
+        fprintf(to, "final ");
+    }
+
+    if (m & ABSTRACT) {
+        fprintf(to, "abstract ");
+    }
+}
+
+void
+WriteArgumentList(FILE* to, const vector<Expression*>& arguments)
+{
+    size_t N = arguments.size();
+    for (size_t i=0; i<N; i++) {
+        arguments[i]->Write(to);
+        if (i != N-1) {
+            fprintf(to, ", ");
+        }
+    }
+}
+
+ClassElement::ClassElement()
+{
+}
+
+ClassElement::~ClassElement()
+{
+}
+
+Field::Field()
+    :ClassElement(),
+     modifiers(0),
+     variable(NULL)
+{
+}
+
+Field::Field(int m, Variable* v)
+    :ClassElement(),
+     modifiers(m),
+     variable(v)
+{
+}
+
+Field::~Field()
+{
+}
+
+void
+Field::GatherTypes(set<Type*>* types) const
+{
+    types->insert(this->variable->type);
+}
+
+void
+Field::Write(FILE* to)
+{
+    if (this->comment.length() != 0) {
+        fprintf(to, "%s\n", this->comment.c_str());
+    }
+    WriteModifiers(to, this->modifiers, SCOPE_MASK | STATIC | FINAL | OVERRIDE);
+    fprintf(to, "%s %s", this->variable->type->QualifiedName().c_str(),
+            this->variable->name.c_str());
+    if (this->value.length() != 0) {
+        fprintf(to, " = %s", this->value.c_str());
+    }
+    fprintf(to, ";\n");
+}
+
+Expression::~Expression()
+{
+}
+
+LiteralExpression::LiteralExpression(const string& v)
+    :value(v)
+{
+}
+
+LiteralExpression::~LiteralExpression()
+{
+}
+
+void
+LiteralExpression::Write(FILE* to)
+{
+    fprintf(to, "%s", this->value.c_str());
+}
+
+StringLiteralExpression::StringLiteralExpression(const string& v)
+    :value(v)
+{
+}
+
+StringLiteralExpression::~StringLiteralExpression()
+{
+}
+
+void
+StringLiteralExpression::Write(FILE* to)
+{
+    fprintf(to, "\"%s\"", this->value.c_str());
+}
+
+Variable::Variable()
+    :type(NULL),
+     name(),
+     dimension(0)
+{
+}
+
+Variable::Variable(Type* t, const string& n)
+    :type(t),
+     name(n),
+     dimension(0)
+{
+}
+
+Variable::Variable(Type* t, const string& n, int d)
+    :type(t),
+     name(n),
+     dimension(d)
+{
+}
+
+Variable::~Variable()
+{
+}
+
+void
+Variable::GatherTypes(set<Type*>* types) const
+{
+    types->insert(this->type);
+}
+
+void
+Variable::WriteDeclaration(FILE* to)
+{
+    string dim;
+    for (int i=0; i<this->dimension; i++) {
+        dim += "[]";
+    }
+    fprintf(to, "%s%s %s", this->type->QualifiedName().c_str(), dim.c_str(),
+            this->name.c_str());
+}
+
+void
+Variable::Write(FILE* to)
+{
+    fprintf(to, "%s", name.c_str());
+}
+
+FieldVariable::FieldVariable(Expression* o, const string& n)
+    :object(o),
+     clazz(NULL),
+     name(n)
+{
+}
+
+FieldVariable::FieldVariable(Type* c, const string& n)
+    :object(NULL),
+     clazz(c),
+     name(n)
+{
+}
+
+FieldVariable::~FieldVariable()
+{
+}
+
+void
+FieldVariable::Write(FILE* to)
+{
+    if (this->object != NULL) {
+        this->object->Write(to);
+    }
+    else if (this->clazz != NULL) {
+        fprintf(to, "%s", this->clazz->QualifiedName().c_str());
+    }
+    fprintf(to, ".%s", name.c_str());
+}
+
+
+Statement::~Statement()
+{
+}
+
+StatementBlock::StatementBlock()
+{
+}
+
+StatementBlock::~StatementBlock()
+{
+}
+
+void
+StatementBlock::Write(FILE* to)
+{
+    fprintf(to, "{\n");
+    int N = this->statements.size();
+    for (int i=0; i<N; i++) {
+        this->statements[i]->Write(to);
+    }
+    fprintf(to, "}\n");
+}
+
+void
+StatementBlock::Add(Statement* statement)
+{
+    this->statements.push_back(statement);
+}
+
+void
+StatementBlock::Add(Expression* expression)
+{
+    this->statements.push_back(new ExpressionStatement(expression));
+}
+
+ExpressionStatement::ExpressionStatement(Expression* e)
+    :expression(e)
+{
+}
+
+ExpressionStatement::~ExpressionStatement()
+{
+}
+
+void
+ExpressionStatement::Write(FILE* to)
+{
+    this->expression->Write(to);
+    fprintf(to, ";\n");
+}
+
+Assignment::Assignment(Variable* l, Expression* r)
+    :lvalue(l),
+     rvalue(r),
+     cast(NULL)
+{
+}
+
+Assignment::Assignment(Variable* l, Expression* r, Type* c)
+    :lvalue(l),
+     rvalue(r),
+     cast(c)
+{
+}
+
+Assignment::~Assignment()
+{
+}
+
+void
+Assignment::Write(FILE* to)
+{
+    this->lvalue->Write(to);
+    fprintf(to, " = ");
+    if (this->cast != NULL) {
+        fprintf(to, "(%s)", this->cast->QualifiedName().c_str());
+    }
+    this->rvalue->Write(to);
+}
+
+MethodCall::MethodCall(const string& n)
+    :obj(NULL),
+     clazz(NULL),
+     name(n)
+{
+}
+
+MethodCall::MethodCall(const string& n, int argc = 0, ...)
+    :obj(NULL),
+     clazz(NULL),
+     name(n)
+{
+  va_list args;
+  va_start(args, argc);
+  init(argc, args);
+  va_end(args);
+}
+
+MethodCall::MethodCall(Expression* o, const string& n)
+    :obj(o),
+     clazz(NULL),
+     name(n)
+{
+}
+
+MethodCall::MethodCall(Type* t, const string& n)
+    :obj(NULL),
+     clazz(t),
+     name(n)
+{
+}
+
+MethodCall::MethodCall(Expression* o, const string& n, int argc = 0, ...)
+    :obj(o),
+     clazz(NULL),
+     name(n)
+{
+  va_list args;
+  va_start(args, argc);
+  init(argc, args);
+  va_end(args);
+}
+
+MethodCall::MethodCall(Type* t, const string& n, int argc = 0, ...)
+    :obj(NULL),
+     clazz(t),
+     name(n)
+{
+  va_list args;
+  va_start(args, argc);
+  init(argc, args);
+  va_end(args);
+}
+
+MethodCall::~MethodCall()
+{
+}
+
+void
+MethodCall::init(int n, va_list args)
+{
+    for (int i=0; i<n; i++) {
+        Expression* expression = (Expression*)va_arg(args, void*);
+        this->arguments.push_back(expression);
+    }
+}
+
+void
+MethodCall::Write(FILE* to)
+{
+    if (this->obj != NULL) {
+        this->obj->Write(to);
+        fprintf(to, ".");
+    }
+    else if (this->clazz != NULL) {
+        fprintf(to, "%s.", this->clazz->QualifiedName().c_str());
+    }
+    fprintf(to, "%s(", this->name.c_str());
+    WriteArgumentList(to, this->arguments);
+    fprintf(to, ")");
+}
+
+Comparison::Comparison(Expression* l, const string& o, Expression* r)
+    :lvalue(l),
+     op(o),
+     rvalue(r)
+{
+}
+
+Comparison::~Comparison()
+{
+}
+
+void
+Comparison::Write(FILE* to)
+{
+    fprintf(to, "(");
+    this->lvalue->Write(to);
+    fprintf(to, "%s", this->op.c_str());
+    this->rvalue->Write(to);
+    fprintf(to, ")");
+}
+
+NewExpression::NewExpression(Type* t)
+    :type(t)
+{
+}
+
+NewExpression::NewExpression(Type* t, int argc = 0, ...)
+    :type(t)
+{
+  va_list args;
+  va_start(args, argc);
+  init(argc, args);
+  va_end(args);
+}
+
+NewExpression::~NewExpression()
+{
+}
+
+void
+NewExpression::init(int n, va_list args)
+{
+    for (int i=0; i<n; i++) {
+        Expression* expression = (Expression*)va_arg(args, void*);
+        this->arguments.push_back(expression);
+    }
+}
+
+void
+NewExpression::Write(FILE* to)
+{
+    fprintf(to, "new %s(", this->type->InstantiableName().c_str());
+    WriteArgumentList(to, this->arguments);
+    fprintf(to, ")");
+}
+
+NewArrayExpression::NewArrayExpression(Type* t, Expression* s)
+    :type(t),
+     size(s)
+{
+}
+
+NewArrayExpression::~NewArrayExpression()
+{
+}
+
+void
+NewArrayExpression::Write(FILE* to)
+{
+    fprintf(to, "new %s[", this->type->QualifiedName().c_str());
+    size->Write(to);
+    fprintf(to, "]");
+}
+
+Ternary::Ternary()
+    :condition(NULL),
+     ifpart(NULL),
+     elsepart(NULL)
+{
+}
+
+Ternary::Ternary(Expression* a, Expression* b, Expression* c)
+    :condition(a),
+     ifpart(b),
+     elsepart(c)
+{
+}
+
+Ternary::~Ternary()
+{
+}
+
+void
+Ternary::Write(FILE* to)
+{
+    fprintf(to, "((");
+    this->condition->Write(to);
+    fprintf(to, ")?(");
+    this->ifpart->Write(to);
+    fprintf(to, "):(");
+    this->elsepart->Write(to);
+    fprintf(to, "))");
+}
+
+Cast::Cast()
+    :type(NULL),
+     expression(NULL)
+{
+}
+
+Cast::Cast(Type* t, Expression* e)
+    :type(t),
+     expression(e)
+{
+}
+
+Cast::~Cast()
+{
+}
+
+void
+Cast::Write(FILE* to)
+{
+    fprintf(to, "((%s)", this->type->QualifiedName().c_str());
+    expression->Write(to);
+    fprintf(to, ")");
+}
+
+VariableDeclaration::VariableDeclaration(Variable* l, Expression* r, Type* c)
+    :lvalue(l),
+     cast(c),
+     rvalue(r)
+{
+}
+
+VariableDeclaration::VariableDeclaration(Variable* l)
+    :lvalue(l),
+     cast(NULL),
+     rvalue(NULL)
+{
+}
+
+VariableDeclaration::~VariableDeclaration()
+{
+}
+
+void
+VariableDeclaration::Write(FILE* to)
+{
+    this->lvalue->WriteDeclaration(to);
+    if (this->rvalue != NULL) {
+        fprintf(to, " = ");
+        if (this->cast != NULL) {
+            fprintf(to, "(%s)", this->cast->QualifiedName().c_str());
+        }
+        this->rvalue->Write(to);
+    }
+    fprintf(to, ";\n");
+}
+
+IfStatement::IfStatement()
+    :expression(NULL),
+     statements(new StatementBlock),
+     elseif(NULL)
+{
+}
+
+IfStatement::~IfStatement()
+{
+}
+
+void
+IfStatement::Write(FILE* to)
+{
+    if (this->expression != NULL) {
+        fprintf(to, "if (");
+        this->expression->Write(to);
+        fprintf(to, ") ");
+    }
+    this->statements->Write(to);
+    if (this->elseif != NULL) {
+        fprintf(to, "else ");
+        this->elseif->Write(to);
+    }
+}
+
+ReturnStatement::ReturnStatement(Expression* e)
+    :expression(e)
+{
+}
+
+ReturnStatement::~ReturnStatement()
+{
+}
+
+void
+ReturnStatement::Write(FILE* to)
+{
+    fprintf(to, "return ");
+    this->expression->Write(to);
+    fprintf(to, ";\n");
+}
+
+TryStatement::TryStatement()
+    :statements(new StatementBlock)
+{
+}
+
+TryStatement::~TryStatement()
+{
+}
+
+void
+TryStatement::Write(FILE* to)
+{
+    fprintf(to, "try ");
+    this->statements->Write(to);
+}
+
+CatchStatement::CatchStatement(Variable* e)
+    :statements(new StatementBlock),
+     exception(e)
+{
+}
+
+CatchStatement::~CatchStatement()
+{
+}
+
+void
+CatchStatement::Write(FILE* to)
+{
+    fprintf(to, "catch ");
+    if (this->exception != NULL) {
+        fprintf(to, "(");
+        this->exception->WriteDeclaration(to);
+        fprintf(to, ") ");
+    }
+    this->statements->Write(to);
+}
+
+FinallyStatement::FinallyStatement()
+    :statements(new StatementBlock)
+{
+}
+
+FinallyStatement::~FinallyStatement()
+{
+}
+
+void
+FinallyStatement::Write(FILE* to)
+{
+    fprintf(to, "finally ");
+    this->statements->Write(to);
+}
+
+Case::Case()
+    :statements(new StatementBlock)
+{
+}
+
+Case::Case(const string& c)
+    :statements(new StatementBlock)
+{
+    cases.push_back(c);
+}
+
+Case::~Case()
+{
+}
+
+void
+Case::Write(FILE* to)
+{
+    int N = this->cases.size();
+    if (N > 0) {
+        for (int i=0; i<N; i++) {
+            string s = this->cases[i];
+            if (s.length() != 0) {
+                fprintf(to, "case %s:\n", s.c_str());
+            } else {
+                fprintf(to, "default:\n");
+            }
+        }
+    } else {
+        fprintf(to, "default:\n");
+    }
+    statements->Write(to);
+}
+
+SwitchStatement::SwitchStatement(Expression* e)
+    :expression(e)
+{
+}
+
+SwitchStatement::~SwitchStatement()
+{
+}
+
+void
+SwitchStatement::Write(FILE* to)
+{
+    fprintf(to, "switch (");
+    this->expression->Write(to);
+    fprintf(to, ")\n{\n");
+    int N = this->cases.size();
+    for (int i=0; i<N; i++) {
+        this->cases[i]->Write(to);
+    }
+    fprintf(to, "}\n");
+}
+
+Break::Break()
+{
+}
+
+Break::~Break()
+{
+}
+
+void
+Break::Write(FILE* to)
+{
+    fprintf(to, "break;\n");
+}
+
+Method::Method()
+    :ClassElement(),
+     modifiers(0),
+     returnType(NULL), // (NULL means constructor)
+     returnTypeDimension(0),
+     statements(NULL)
+{
+}
+
+Method::~Method()
+{
+}
+
+void
+Method::GatherTypes(set<Type*>* types) const
+{
+    size_t N, i;
+
+    if (this->returnType) {
+        types->insert(this->returnType);
+    }
+
+    N = this->parameters.size();
+    for (i=0; i<N; i++) {
+        this->parameters[i]->GatherTypes(types);
+    }
+
+    N = this->exceptions.size();
+    for (i=0; i<N; i++) {
+        types->insert(this->exceptions[i]);
+    }
+}
+
+void
+Method::Write(FILE* to)
+{
+    size_t N, i;
+
+    if (this->comment.length() != 0) {
+        fprintf(to, "%s\n", this->comment.c_str());
+    }
+
+    WriteModifiers(to, this->modifiers, SCOPE_MASK | STATIC | ABSTRACT | FINAL | OVERRIDE);
+
+    if (this->returnType != NULL) {
+        string dim;
+        for (i=0; i<this->returnTypeDimension; i++) {
+            dim += "[]";
+        }
+        fprintf(to, "%s%s ", this->returnType->QualifiedName().c_str(),
+                dim.c_str());
+    }
+   
+    fprintf(to, "%s(", this->name.c_str());
+
+    N = this->parameters.size();
+    for (i=0; i<N; i++) {
+        this->parameters[i]->WriteDeclaration(to);
+        if (i != N-1) {
+            fprintf(to, ", ");
+        }
+    }
+
+    fprintf(to, ")");
+
+    N = this->exceptions.size();
+    for (i=0; i<N; i++) {
+        if (i == 0) {
+            fprintf(to, " throws ");
+        } else {
+            fprintf(to, ", ");
+        }
+        fprintf(to, "%s", this->exceptions[i]->QualifiedName().c_str());
+    }
+
+    if (this->statements == NULL) {
+        fprintf(to, ";\n");
+    } else {
+        fprintf(to, "\n");
+        this->statements->Write(to);
+    }
+}
+
+Class::Class()
+    :modifiers(0),
+     what(CLASS),
+     type(NULL),
+     extends(NULL)
+{
+}
+
+Class::~Class()
+{
+}
+
+void
+Class::GatherTypes(set<Type*>* types) const
+{
+    int N, i;
+
+    types->insert(this->type);
+    if (this->extends != NULL) {
+        types->insert(this->extends);
+    }
+
+    N = this->interfaces.size();
+    for (i=0; i<N; i++) {
+        types->insert(this->interfaces[i]);
+    }
+
+    N = this->elements.size();
+    for (i=0; i<N; i++) {
+        this->elements[i]->GatherTypes(types);
+    }
+}
+
+void
+Class::Write(FILE* to)
+{
+    size_t N, i;
+
+    if (this->comment.length() != 0) {
+        fprintf(to, "%s\n", this->comment.c_str());
+    }
+
+    WriteModifiers(to, this->modifiers, ALL_MODIFIERS);
+
+    if (this->what == Class::CLASS) {
+        fprintf(to, "class ");
+    } else {
+        fprintf(to, "interface ");
+    }
+
+    string name = this->type->Name();
+    size_t pos = name.rfind('.');
+    if (pos != string::npos) {
+        name = name.c_str() + pos + 1;
+    }
+
+    fprintf(to, "%s", name.c_str());
+
+    if (this->extends != NULL) {
+        fprintf(to, " extends %s", this->extends->QualifiedName().c_str());
+    }
+
+    N = this->interfaces.size();
+    if (N != 0) {
+        if (this->what == Class::CLASS) {
+            fprintf(to, " implements");
+        } else {
+            fprintf(to, " extends");
+        }
+        for (i=0; i<N; i++) {
+            fprintf(to, " %s", this->interfaces[i]->QualifiedName().c_str());
+        }
+    }
+
+    fprintf(to, "\n");
+    fprintf(to, "{\n");
+
+    N = this->elements.size();
+    for (i=0; i<N; i++) {
+        this->elements[i]->Write(to);
+    }
+
+    fprintf(to, "}\n");
+
+}
+
+Document::Document()
+{
+}
+
+Document::~Document()
+{
+}
+
+static string
+escape_backslashes(const string& str)
+{
+    string result;
+    const size_t I=str.length();
+    for (size_t i=0; i<I; i++) {
+        char c = str[i];
+        if (c == '\\') {
+            result += "\\\\";
+        } else {
+            result += c;
+        }
+    }
+    return result;
+}
+
+void
+Document::Write(FILE* to)
+{
+    size_t N, i;
+
+    if (this->comment.length() != 0) {
+        fprintf(to, "%s\n", this->comment.c_str());
+    }
+    fprintf(to, "/*\n"
+                " * This file is auto-generated.  DO NOT MODIFY.\n"
+                " * Original file: %s\n"
+                " */\n", escape_backslashes(this->originalSrc).c_str());
+    if (this->package.length() != 0) {
+        fprintf(to, "package %s;\n", this->package.c_str());
+    }
+
+    N = this->classes.size();
+    for (i=0; i<N; i++) {
+        Class* c = this->classes[i];
+        c->Write(to);
+    }
+}
+
diff --git a/AST.h b/AST.h
new file mode 100644
index 0000000..ead5e7a
--- /dev/null
+++ b/AST.h
@@ -0,0 +1,371 @@
+#ifndef AIDL_AST_H
+#define AIDL_AST_H
+
+#include <string>
+#include <vector>
+#include <set>
+#include <stdarg.h>
+#include <stdio.h>
+
+using namespace std;
+
+class Type;
+
+enum {
+    PACKAGE_PRIVATE = 0x00000000,
+    PUBLIC          = 0x00000001,
+    PRIVATE         = 0x00000002,
+    PROTECTED       = 0x00000003,
+    SCOPE_MASK      = 0x00000003,
+
+    STATIC          = 0x00000010,
+    FINAL           = 0x00000020,
+    ABSTRACT        = 0x00000040,
+
+    OVERRIDE        = 0x00000100,
+
+    ALL_MODIFIERS   = 0xffffffff
+};
+
+// Write the modifiers that are set in both mod and mask
+void WriteModifiers(FILE* to, int mod, int mask);
+
+struct ClassElement
+{
+    ClassElement();
+    virtual ~ClassElement();
+
+    virtual void GatherTypes(set<Type*>* types) const = 0;
+    virtual void Write(FILE* to) = 0;
+};
+
+struct Expression
+{
+    virtual ~Expression();
+    virtual void Write(FILE* to) = 0;
+};
+
+struct LiteralExpression : public Expression
+{
+    string value;
+
+    LiteralExpression(const string& value);
+    virtual ~LiteralExpression();
+    virtual void Write(FILE* to);
+};
+
+// TODO: also escape the contents.  not needed for now
+struct StringLiteralExpression : public Expression
+{
+    string value;
+
+    StringLiteralExpression(const string& value);
+    virtual ~StringLiteralExpression();
+    virtual void Write(FILE* to);
+};
+
+struct Variable : public Expression
+{
+    Type* type;
+    string name;
+    int dimension;
+
+    Variable();
+    Variable(Type* type, const string& name);
+    Variable(Type* type, const string& name, int dimension);
+    virtual ~Variable();
+
+    virtual void GatherTypes(set<Type*>* types) const;
+    void WriteDeclaration(FILE* to);
+    void Write(FILE* to);
+};
+
+struct FieldVariable : public Expression
+{
+    Expression* object;
+    Type* clazz;
+    string name;
+
+    FieldVariable(Expression* object, const string& name);
+    FieldVariable(Type* clazz, const string& name);
+    virtual ~FieldVariable();
+
+    void Write(FILE* to);
+};
+
+struct Field : public ClassElement
+{
+    string comment;
+    int modifiers;
+    Variable *variable;
+    string value;
+
+    Field();
+    Field(int modifiers, Variable* variable);
+    virtual ~Field();
+
+    virtual void GatherTypes(set<Type*>* types) const;
+    virtual void Write(FILE* to);
+};
+
+struct Statement
+{
+    virtual ~Statement();
+    virtual void Write(FILE* to) = 0;
+};
+
+struct StatementBlock : public Statement
+{
+    vector<Statement*> statements;
+
+    StatementBlock();
+    virtual ~StatementBlock();
+    virtual void Write(FILE* to);
+
+    void Add(Statement* statement);
+    void Add(Expression* expression);
+};
+
+struct ExpressionStatement : public Statement
+{
+    Expression* expression;
+
+    ExpressionStatement(Expression* expression);
+    virtual ~ExpressionStatement();
+    virtual void Write(FILE* to);
+};
+
+struct Assignment : public Expression
+{
+    Variable* lvalue;
+    Expression* rvalue;
+    Type* cast;
+
+    Assignment(Variable* lvalue, Expression* rvalue);
+    Assignment(Variable* lvalue, Expression* rvalue, Type* cast);
+    virtual ~Assignment();
+    virtual void Write(FILE* to);
+};
+
+struct MethodCall : public Expression
+{
+    Expression* obj;
+    Type* clazz;
+    string name;
+    vector<Expression*> arguments;
+    vector<string> exceptions;
+
+    MethodCall(const string& name);
+    MethodCall(const string& name, int argc, ...);
+    MethodCall(Expression* obj, const string& name);
+    MethodCall(Type* clazz, const string& name);
+    MethodCall(Expression* obj, const string& name, int argc, ...);
+    MethodCall(Type* clazz, const string& name, int argc, ...);
+    virtual ~MethodCall();
+    virtual void Write(FILE* to);
+
+private:
+    void init(int n, va_list args);
+};
+
+struct Comparison : public Expression
+{
+    Expression* lvalue;
+    string op;
+    Expression* rvalue;
+
+    Comparison(Expression* lvalue, const string& op, Expression* rvalue);
+    virtual ~Comparison();
+    virtual void Write(FILE* to);
+};
+
+struct NewExpression : public Expression
+{
+    Type* type;
+    vector<Expression*> arguments;
+
+    NewExpression(Type* type);
+    NewExpression(Type* type, int argc, ...);
+    virtual ~NewExpression();
+    virtual void Write(FILE* to);
+
+private:
+    void init(int n, va_list args);
+};
+
+struct NewArrayExpression : public Expression
+{
+    Type* type;
+    Expression* size;
+
+    NewArrayExpression(Type* type, Expression* size);
+    virtual ~NewArrayExpression();
+    virtual void Write(FILE* to);
+};
+
+struct Ternary : public Expression
+{
+    Expression* condition;
+    Expression* ifpart;
+    Expression* elsepart;
+
+    Ternary();
+    Ternary(Expression* condition, Expression* ifpart, Expression* elsepart);
+    virtual ~Ternary();
+    virtual void Write(FILE* to);
+};
+
+struct Cast : public Expression
+{
+    Type* type;
+    Expression* expression;
+
+    Cast();
+    Cast(Type* type, Expression* expression);
+    virtual ~Cast();
+    virtual void Write(FILE* to);
+};
+
+struct VariableDeclaration : public Statement
+{
+    Variable* lvalue;
+    Type* cast;
+    Expression* rvalue;
+
+    VariableDeclaration(Variable* lvalue);
+    VariableDeclaration(Variable* lvalue, Expression* rvalue, Type* cast = NULL);
+    virtual ~VariableDeclaration();
+    virtual void Write(FILE* to);
+};
+
+struct IfStatement : public Statement
+{
+    Expression* expression;
+    StatementBlock* statements;
+    IfStatement* elseif;
+
+    IfStatement();
+    virtual ~IfStatement();
+    virtual void Write(FILE* to);
+};
+
+struct ReturnStatement : public Statement
+{
+    Expression* expression;
+
+    ReturnStatement(Expression* expression);
+    virtual ~ReturnStatement();
+    virtual void Write(FILE* to);
+};
+
+struct TryStatement : public Statement
+{
+    StatementBlock* statements;
+
+    TryStatement();
+    virtual ~TryStatement();
+    virtual void Write(FILE* to);
+};
+
+struct CatchStatement : public Statement
+{
+    StatementBlock* statements;
+    Variable* exception;
+
+    CatchStatement(Variable* exception);
+    virtual ~CatchStatement();
+    virtual void Write(FILE* to);
+};
+
+struct FinallyStatement : public Statement
+{
+    StatementBlock* statements;
+
+    FinallyStatement();
+    virtual ~FinallyStatement();
+    virtual void Write(FILE* to);
+};
+
+struct Case
+{
+    vector<string> cases;
+    StatementBlock* statements;
+
+    Case();
+    Case(const string& c);
+    virtual ~Case();
+    virtual void Write(FILE* to);
+};
+
+struct SwitchStatement : public Statement
+{
+    Expression* expression;
+    vector<Case*> cases;
+
+    SwitchStatement(Expression* expression);
+    virtual ~SwitchStatement();
+    virtual void Write(FILE* to);
+};
+
+struct Break : public Statement
+{
+    Break();
+    virtual ~Break();
+    virtual void Write(FILE* to);
+};
+
+struct Method : public ClassElement
+{
+    string comment;
+    int modifiers;
+    Type* returnType;
+    size_t returnTypeDimension;
+    string name;
+    vector<Variable*> parameters;
+    vector<Type*> exceptions;
+    StatementBlock* statements;
+
+    Method();
+    virtual ~Method();
+
+    virtual void GatherTypes(set<Type*>* types) const;
+    virtual void Write(FILE* to);
+};
+
+struct Class : public ClassElement
+{
+    enum {
+        CLASS,
+        INTERFACE
+    };
+
+    string comment;
+    int modifiers;
+    int what;               // CLASS or INTERFACE
+    Type* type;
+    Type* extends;
+    vector<Type*> interfaces;
+    vector<ClassElement*> elements;
+
+    Class();
+    virtual ~Class();
+
+    virtual void GatherTypes(set<Type*>* types) const;
+    virtual void Write(FILE* to);
+};
+
+struct Document
+{
+    string comment;
+    string package;
+    string originalSrc;
+    set<Type*> imports;
+    vector<Class*> classes;
+
+    Document();
+    virtual ~Document();
+
+    virtual void Write(FILE* to);
+};
+
+#endif // AIDL_AST_H
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..77d46ab
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,29 @@
+# Copyright 2007 The Android Open Source Project
+#
+# Copies files into the directory structure described by a manifest
+
+# This tool is prebuilt if we're doing an app-only build.
+ifeq ($(TARGET_BUILD_APPS),)
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+	aidl_language_l.l \
+	aidl_language_y.y \
+	aidl.cpp \
+	aidl_language.cpp \
+	options.cpp \
+	search_path.cpp \
+	AST.cpp \
+	Type.cpp \
+	generate_java.cpp \
+	generate_java_binder.cpp \
+	generate_java_rpc.cpp
+
+LOCAL_CFLAGS := -g
+LOCAL_MODULE := aidl
+
+include $(BUILD_HOST_EXECUTABLE)
+
+endif # TARGET_BUILD_APPS
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-2008, The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/Type.cpp b/Type.cpp
new file mode 100644
index 0000000..d572af6
--- /dev/null
+++ b/Type.cpp
@@ -0,0 +1,1440 @@
+#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* OBJECT_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* CONTEXT_TYPE;
+Type* MAP_TYPE;
+Type* LIST_TYPE;
+Type* CLASSLOADER_TYPE;
+Type* RPC_DATA_TYPE;
+Type* RPC_ERROR_TYPE;
+Type* EVENT_FAKE_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",
+            "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",
+            "putByte", "getByte", "putByteArray", "createByteArray", "getByteArray");
+    NAMES.Add(BYTE_TYPE);
+
+    CHAR_TYPE = new CharType();
+    NAMES.Add(CHAR_TYPE);
+
+    INT_TYPE = new BasicType("int",
+            "writeInt", "readInt", "writeIntArray", "createIntArray", "readIntArray",
+            "putInteger", "getInteger", "putIntegerArray", "createIntegerArray", "getIntegerArray");
+    NAMES.Add(INT_TYPE);
+
+    LONG_TYPE = new BasicType("long",
+            "writeLong", "readLong", "writeLongArray", "createLongArray", "readLongArray",
+            "putLong", "getLong", "putLongArray", "createLongArray", "getLongArray");
+    NAMES.Add(LONG_TYPE);
+
+    FLOAT_TYPE = new BasicType("float",
+            "writeFloat", "readFloat", "writeFloatArray", "createFloatArray", "readFloatArray",
+            "putFloat", "getFloat", "putFloatArray", "createFloatArray", "getFloatArray");
+    NAMES.Add(FLOAT_TYPE);
+
+    DOUBLE_TYPE = new BasicType("double",
+            "writeDouble", "readDouble", "writeDoubleArray", "createDoubleArray", "readDoubleArray",
+            "putDouble", "getDouble", "putDoubleArray", "createDoubleArray", "getDoubleArray");
+    NAMES.Add(DOUBLE_TYPE);
+
+    STRING_TYPE = new StringType();
+    NAMES.Add(STRING_TYPE);
+
+    OBJECT_TYPE = new Type("java.lang", "Object", Type::BUILT_IN, false, false, false);
+    NAMES.Add(OBJECT_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, 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);
+
+    CONTEXT_TYPE = new Type("android.content", "Context", Type::BUILT_IN, false, false, false);
+    NAMES.Add(CONTEXT_TYPE);
+
+    RPC_DATA_TYPE = new RpcDataType();
+    NAMES.Add(RPC_DATA_TYPE);
+
+    RPC_ERROR_TYPE = new UserDataType("android.support.place.rpc", "RpcError",
+                                    true, __FILE__, __LINE__);
+    NAMES.Add(RPC_ERROR_TYPE);
+
+    EVENT_FAKE_TYPE = new Type("event", Type::BUILT_IN, false, false, false);
+    NAMES.Add(EVENT_FAKE_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 canWriteToRpcData,
+        bool canBeOut)
+    :m_package(),
+     m_name(name),
+     m_declFile(""),
+     m_declLine(-1),
+     m_kind(kind),
+     m_canWriteToParcel(canWriteToParcel),
+     m_canWriteToRpcData(canWriteToRpcData),
+     m_canBeOut(canBeOut)
+{
+    m_qualifiedName = name;
+}
+
+Type::Type(const string& package, const string& name,
+            int kind, bool canWriteToParcel, bool canWriteToRpcData,
+            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_canWriteToRpcData(canWriteToRpcData),
+     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::RpcCreatorName() 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, Variable**)
+{
+    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, Variable**)
+{
+    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, Variable**)
+{
+    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, Variable**)
+{
+    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::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+        Variable* data, int flags)
+{
+    fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n",
+            __FILE__, __LINE__, m_qualifiedName.c_str());
+    addTo->Add(new LiteralExpression("/* WriteToRpcData error "
+                + m_qualifiedName + " */"));
+}
+
+void
+Type::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data,
+        Variable** cl)
+{
+    fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n",
+            __FILE__, __LINE__, m_qualifiedName.c_str());
+    addTo->Add(new LiteralExpression("/* ReadFromRpcData 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& marshallParcel,
+          const string& unmarshallParcel, const string& writeArrayParcel,
+          const string& createArrayParcel, const string& readArrayParcel,
+          const string& marshallRpc, const string& unmarshallRpc,
+          const string& writeArrayRpc, const string& createArrayRpc, const string& readArrayRpc)
+    :Type(name, BUILT_IN, true, true, false),
+     m_marshallParcel(marshallParcel),
+     m_unmarshallParcel(unmarshallParcel),
+     m_writeArrayParcel(writeArrayParcel),
+     m_createArrayParcel(createArrayParcel),
+     m_readArrayParcel(readArrayParcel),
+     m_marshallRpc(marshallRpc),
+     m_unmarshallRpc(unmarshallRpc),
+     m_writeArrayRpc(writeArrayRpc),
+     m_createArrayRpc(createArrayRpc),
+     m_readArrayRpc(readArrayRpc)
+{
+}
+
+void
+BasicType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    addTo->Add(new MethodCall(parcel, m_marshallParcel, 1, v));
+}
+
+void
+BasicType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
+{
+    addTo->Add(new Assignment(v, new MethodCall(parcel, m_unmarshallParcel)));
+}
+
+bool
+BasicType::CanBeArray() const
+{
+    return true;
+}
+
+void
+BasicType::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    addTo->Add(new MethodCall(parcel, m_writeArrayParcel, 1, v));
+}
+
+void
+BasicType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
+                            Variable* parcel, Variable**)
+{
+    addTo->Add(new Assignment(v, new MethodCall(parcel, m_createArrayParcel)));
+}
+
+void
+BasicType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
+{
+    addTo->Add(new MethodCall(parcel, m_readArrayParcel, 1, v));
+}
+
+void
+BasicType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+        Variable* data, int flags)
+{
+    addTo->Add(new MethodCall(data, m_marshallRpc, 2, k, v));
+}
+
+void
+BasicType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data,
+        Variable** cl)
+{
+    addTo->Add(new Assignment(v, new MethodCall(data, m_unmarshallRpc, 1, k)));
+}
+
+// ================================================================
+
+BooleanType::BooleanType()
+    :Type("boolean", BUILT_IN, true, 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, Variable**)
+{
+    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, Variable**)
+{
+    addTo->Add(new Assignment(v, new MethodCall(parcel, "createBooleanArray")));
+}
+
+void
+BooleanType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
+{
+    addTo->Add(new MethodCall(parcel, "readBooleanArray", 1, v));
+}
+
+void
+BooleanType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+        Variable* data, int flags)
+{
+    addTo->Add(new MethodCall(data, "putBoolean", 2, k, v));
+}
+
+void
+BooleanType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data,
+        Variable** cl)
+{
+    addTo->Add(new Assignment(v, new MethodCall(data, "getBoolean", 1, k)));
+}
+
+// ================================================================
+
+CharType::CharType()
+    :Type("char", BUILT_IN, true, 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, Variable**)
+{
+    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, Variable**)
+{
+    addTo->Add(new Assignment(v, new MethodCall(parcel, "createCharArray")));
+}
+
+void
+CharType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
+{
+    addTo->Add(new MethodCall(parcel, "readCharArray", 1, v));
+}
+
+void
+CharType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+        Variable* data, int flags)
+{
+    addTo->Add(new MethodCall(data, "putChar", 2, k, v));
+}
+
+void
+CharType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data,
+        Variable** cl)
+{
+    addTo->Add(new Assignment(v, new MethodCall(data, "getChar", 1, k)));
+}
+
+// ================================================================
+
+StringType::StringType()
+    :Type("java.lang", "String", BUILT_IN, true, 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, Variable**)
+{
+    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, Variable**)
+{
+    addTo->Add(new Assignment(v, new MethodCall(parcel, "createStringArray")));
+}
+
+void
+StringType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
+{
+    addTo->Add(new MethodCall(parcel, "readStringArray", 1, v));
+}
+
+void
+StringType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+        Variable* data, int flags)
+{
+    addTo->Add(new MethodCall(data, "putString", 2, k, v));
+}
+
+void
+StringType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+        Variable* data, Variable**)
+{
+    addTo->Add(new Assignment(v, new MethodCall(data, "getString", 1, k)));
+}
+
+// ================================================================
+
+CharSequenceType::CharSequenceType()
+    :Type("java.lang", "CharSequence", BUILT_IN, true, 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, Variable**)
+{
+    // 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, 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, Variable**)
+{
+    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+// ================================================================
+
+RuntimeExceptionType::RuntimeExceptionType()
+    :Type("java.lang", "RuntimeException", BUILT_IN, false, 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, Variable**)
+{
+    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+
+// ================================================================
+
+IBinderType::IBinderType()
+    :Type("android.os", "IBinder", BUILT_IN, true, false, 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, Variable**)
+{
+    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, Variable**)
+{
+    addTo->Add(new Assignment(v, new MethodCall(parcel, "createBinderArray")));
+}
+
+void
+IBinderType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
+{
+    addTo->Add(new MethodCall(parcel, "readBinderArray", 1, v));
+}
+
+
+// ================================================================
+
+IInterfaceType::IInterfaceType()
+    :Type("android.os", "IInterface", BUILT_IN, false, 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, Variable**)
+{
+    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+
+// ================================================================
+
+BinderType::BinderType()
+    :Type("android.os", "Binder", BUILT_IN, false, 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, Variable**)
+{
+    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+
+// ================================================================
+
+BinderProxyType::BinderProxyType()
+    :Type("android.os", "BinderProxy", BUILT_IN, false, 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, Variable**)
+{
+    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+
+// ================================================================
+
+ParcelType::ParcelType()
+    :Type("android.os", "Parcel", BUILT_IN, false, 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, Variable**)
+{
+    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+// ================================================================
+
+ParcelableInterfaceType::ParcelableInterfaceType()
+    :Type("android.os", "Parcelable", BUILT_IN, false, 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, Variable**)
+{
+    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+// ================================================================
+
+MapType::MapType()
+    :Type("java.util", "Map", BUILT_IN, true, false, true)
+{
+}
+
+void
+MapType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    addTo->Add(new MethodCall(parcel, "writeMap", 1, v));
+}
+
+static void EnsureClassLoader(StatementBlock* addTo, Variable** cl)
+{
+    // We don't want to look up the class loader once for every
+    // collection argument, so ensure we do it at most once per method.
+    if (*cl == NULL) {
+        *cl = new Variable(CLASSLOADER_TYPE, "cl");
+        addTo->Add(new VariableDeclaration(*cl,
+                new LiteralExpression("this.getClass().getClassLoader()"),
+                CLASSLOADER_TYPE));
+    }
+}
+
+void
+MapType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl)
+{
+    EnsureClassLoader(addTo, cl);
+    addTo->Add(new Assignment(v, new MethodCall(parcel, "readHashMap", 1, *cl)));
+}
+
+void
+MapType::ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl)
+{
+    EnsureClassLoader(addTo, cl);
+    addTo->Add(new MethodCall(parcel, "readMap", 2, v, *cl));
+}
+
+
+// ================================================================
+
+ListType::ListType()
+    :Type("java.util", "List", BUILT_IN, true, 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)
+{
+    EnsureClassLoader(addTo, cl);
+    addTo->Add(new Assignment(v, new MethodCall(parcel, "readArrayList", 1, *cl)));
+}
+
+void
+ListType::ReadFromParcel(StatementBlock* addTo, Variable* v,
+                    Variable* parcel, Variable** cl)
+{
+    EnsureClassLoader(addTo, cl);
+    addTo->Add(new MethodCall(parcel, "readList", 2, v, *cl));
+}
+
+void
+ListType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+        Variable* data, int flags)
+{
+    addTo->Add(new MethodCall(data, "putList", 2, k, v));
+}
+
+void
+ListType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data,
+        Variable** cl)
+{
+    addTo->Add(new Assignment(v, new MethodCall(data, "getList", 1, k)));
+}
+
+// ================================================================
+
+UserDataType::UserDataType(const string& package, const string& name,
+                        bool builtIn, bool canWriteToParcel, bool canWriteToRpcData,
+                        const string& declFile, int declLine)
+    :Type(package, name, builtIn ? BUILT_IN : USERDATA, canWriteToParcel, canWriteToRpcData,
+            true, declFile, declLine)
+{
+}
+
+string
+UserDataType::CreatorName() const
+{
+    return QualifiedName() + ".CREATOR";
+}
+
+string
+UserDataType::RpcCreatorName() const
+{
+    return QualifiedName() + ".RPC_CREATOR";
+}
+
+void
+UserDataType::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
+UserDataType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
+{
+    // 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
+UserDataType::ReadFromParcel(StatementBlock* addTo, Variable* v,
+                    Variable* parcel, Variable**)
+{
+    // 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
+UserDataType::CanBeArray() const
+{
+    return true;
+}
+
+void
+UserDataType::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    addTo->Add(new MethodCall(parcel, "writeTypedArray", 2, v,
+                BuildWriteToParcelFlags(flags)));
+}
+
+void
+UserDataType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
+                            Variable* parcel, Variable**)
+{
+    string creator = v->type->QualifiedName() + ".CREATOR";
+    addTo->Add(new Assignment(v, new MethodCall(parcel,
+                "createTypedArray", 1, new LiteralExpression(creator))));
+}
+
+void
+UserDataType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
+{
+    string creator = v->type->QualifiedName() + ".CREATOR";
+    addTo->Add(new MethodCall(parcel, "readTypedArray", 2,
+                    v, new LiteralExpression(creator)));
+}
+
+void
+UserDataType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+                                    Variable* data, int flags)
+{
+    // data.putFlattenable(k, v);
+    addTo->Add(new MethodCall(data, "putFlattenable", 2, k, v));
+}
+
+void
+UserDataType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+                                    Variable* data, Variable** cl)
+{
+    // data.getFlattenable(k, CLASS.RPC_CREATOR);
+    addTo->Add(new Assignment(v, new MethodCall(data, "getFlattenable", 2, k,
+                new FieldVariable(v->type, "RPC_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, 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, Variable**)
+{
+    // 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, 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);
+}
+
+const vector<Type*>&
+GenericType::GenericArgumentTypes() const
+{
+    return m_args;
+}
+
+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, Variable**)
+{
+    fprintf(stderr, "implement GenericType::CreateFromParcel\n");
+}
+
+void
+GenericType::ReadFromParcel(StatementBlock* addTo, Variable* v,
+                            Variable* parcel, Variable**)
+{
+    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, Variable**)
+{
+    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, Variable**)
+{
+    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)));
+    }
+}
+
+void
+GenericListType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+        Variable* data, int flags)
+{
+    Type* generic = GenericArgumentTypes()[0];
+    if (generic == RPC_DATA_TYPE) {
+        addTo->Add(new MethodCall(data, "putRpcDataList", 2, k, v));
+    } else if (generic->RpcCreatorName() != "") {
+        addTo->Add(new MethodCall(data, "putFlattenableList", 2, k, v));
+    } else {
+        addTo->Add(new MethodCall(data, "putList", 2, k, v));
+    }
+}
+
+void
+GenericListType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+        Variable* data, Variable** cl)
+{
+    Type* generic = GenericArgumentTypes()[0];
+    if (generic == RPC_DATA_TYPE) {
+        addTo->Add(new Assignment(v, new MethodCall(data, "getRpcDataList", 2, k)));
+    } else if (generic->RpcCreatorName() != "") {
+        addTo->Add(new Assignment(v, new MethodCall(data, "getFlattenableList", 2, k, 
+                        new LiteralExpression(generic->RpcCreatorName()))));
+    } else {
+        string classArg = GenericArgumentTypes()[0]->QualifiedName();
+        classArg += ".class";
+        addTo->Add(new Assignment(v, new MethodCall(data, "getList", 2, k,
+                        new LiteralExpression(classArg))));
+    }
+}
+
+
+// ================================================================
+
+RpcDataType::RpcDataType()
+    :UserDataType("android.support.place.rpc", "RpcData", true, true, true)
+{
+}
+
+void
+RpcDataType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+        Variable* data, int flags)
+{
+    addTo->Add(new MethodCall(data, "putRpcData", 2, k, v));
+}
+
+void
+RpcDataType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data,
+        Variable** cl)
+{
+    addTo->Add(new Assignment(v, new MethodCall(data, "getRpcData", 1, k)));
+}
+
+
+// ================================================================
+
+ClassLoaderType::ClassLoaderType()
+    :Type("java.lang", "ClassLoader", BUILT_IN, false, 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());
+    }
+}
diff --git a/Type.h b/Type.h
new file mode 100644
index 0000000..ae12720
--- /dev/null
+++ b/Type.h
@@ -0,0 +1,542 @@
+#ifndef AIDL_TYPE_H
+#define AIDL_TYPE_H
+
+#include "AST.h"
+#include <string>
+#include <vector>
+
+using namespace std;
+
+class Type
+{
+public:
+    // kinds
+    enum {
+        BUILT_IN,
+        USERDATA,
+        INTERFACE,
+        GENERATED
+    };
+    
+    // WriteToParcel flags
+    enum {
+        PARCELABLE_WRITE_RETURN_VALUE = 0x0001
+    };
+
+                    Type(const string& name, int kind, bool canWriteToParcel,
+                            bool canWriteToRpcData, bool canBeOut);
+                    Type(const string& package, const string& name,
+                            int kind, bool canWriteToParcel, bool canWriteToRpcData, bool canBeOut,
+                            const string& declFile = "", int declLine = -1);
+    virtual         ~Type();
+
+    inline string   Package() const             { return m_package; }
+    inline string   Name() const                { return m_name; }
+    inline string   QualifiedName() const       { return m_qualifiedName; }
+    inline int      Kind() const                { return m_kind; }
+    inline string   DeclFile() const            { return m_declFile; }
+    inline int      DeclLine() const            { return m_declLine; }
+    inline bool     CanWriteToParcel() const    { return m_canWriteToParcel; }
+    inline bool     CanWriteToRpcData() const   { return m_canWriteToRpcData; }
+    inline bool     CanBeOutParameter() const   { return m_canBeOut; }
+    
+    virtual string  ImportType() const;
+    virtual string  CreatorName() const;
+    virtual string  RpcCreatorName() const;
+    virtual string  InstantiableName() const;
+
+    virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, int flags);
+    virtual void    CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, Variable** cl);
+    virtual void    ReadFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, Variable** cl);
+
+    virtual bool    CanBeArray() const;
+
+    virtual void    WriteArrayToParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, int flags);
+    virtual void    CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, Variable** cl);
+    virtual void    ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, Variable** cl);
+
+    virtual void    WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+                                    Variable* data, int flags);
+    virtual void    CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+                                    Variable* data, Variable** cl);
+
+protected:
+    void SetQualifiedName(const string& qualified);
+    Expression* BuildWriteToParcelFlags(int flags);
+
+private:
+    Type();
+    Type(const Type&);
+
+    string m_package;
+    string m_name;
+    string m_qualifiedName;
+    string m_declFile;
+    int m_declLine;
+    int m_kind;
+    bool m_canWriteToParcel;
+    bool m_canWriteToRpcData;
+    bool m_canBeOut;
+};
+
+class BasicType : public Type
+{
+public:
+                    BasicType(const string& name,
+                              const string& marshallParcel,
+                              const string& unmarshallParcel,
+                              const string& writeArrayParcel,
+                              const string& createArrayParcel,
+                              const string& readArrayParcel,
+                              const string& marshallRpc,
+                              const string& unmarshallRpc,
+                              const string& writeArrayRpc,
+                              const string& createArrayRpc,
+                              const string& readArrayRpc);
+
+    virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, int flags);
+    virtual void    CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, Variable** cl);
+
+    virtual bool    CanBeArray() const;
+
+    virtual void    WriteArrayToParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, int flags);
+    virtual void    CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, Variable** cl);
+    virtual void    ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, Variable** cl);
+
+    virtual void    WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+                                    Variable* data, int flags);
+    virtual void    CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+                                    Variable* data, Variable** cl);
+
+private:
+    string m_marshallParcel;
+    string m_unmarshallParcel;
+    string m_writeArrayParcel;
+    string m_createArrayParcel;
+    string m_readArrayParcel;
+    string m_marshallRpc;
+    string m_unmarshallRpc;
+    string m_writeArrayRpc;
+    string m_createArrayRpc;
+    string m_readArrayRpc;
+};
+
+class BooleanType : public Type
+{
+public:
+                    BooleanType();
+
+    virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, int flags);
+    virtual void    CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, Variable** cl);
+
+    virtual bool    CanBeArray() const;
+
+    virtual void    WriteArrayToParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, int flags);
+    virtual void    CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, Variable** cl);
+    virtual void    ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, Variable** cl);
+
+    virtual void    WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+                                    Variable* data, int flags);
+    virtual void    CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+                                    Variable* data, Variable** cl);
+};
+
+class CharType : public Type
+{
+public:
+                    CharType();
+
+    virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, int flags);
+    virtual void    CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, Variable** cl);
+
+    virtual bool    CanBeArray() const;
+
+    virtual void    WriteArrayToParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, int flags);
+    virtual void    CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, Variable** cl);
+    virtual void    ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, Variable** cl);
+
+    virtual void    WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+                                    Variable* data, int flags);
+    virtual void    CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+                                    Variable* data, Variable** cl);
+};
+
+
+class StringType : public Type
+{
+public:
+                    StringType();
+
+    virtual string  CreatorName() const;
+
+    virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, int flags);
+    virtual void    CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, Variable** cl);
+
+    virtual bool    CanBeArray() const;
+
+    virtual void    WriteArrayToParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, int flags);
+    virtual void    CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, Variable** cl);
+    virtual void    ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, Variable** cl);
+
+    virtual void    WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+                                    Variable* data, int flags);
+    virtual void    CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+                                    Variable* data, Variable** cl);
+};
+
+class CharSequenceType : public Type
+{
+public:
+                    CharSequenceType();
+
+    virtual string  CreatorName() const;
+
+    virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, int flags);
+    virtual void    CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, Variable** cl);
+};
+
+class RemoteExceptionType : public Type
+{
+public:
+                    RemoteExceptionType();
+
+    virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, int flags);
+    virtual void    CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, Variable** cl);
+};
+
+class RuntimeExceptionType : public Type
+{
+public:
+                    RuntimeExceptionType();
+
+    virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, int flags);
+    virtual void    CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, Variable** cl);
+};
+
+class IBinderType : public Type
+{
+public:
+                    IBinderType();
+
+    virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, int flags);
+    virtual void    CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, Variable** cl);
+
+    virtual void    WriteArrayToParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, int flags);
+    virtual void    CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, Variable** cl);
+    virtual void    ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, Variable** cl);
+};
+
+class IInterfaceType : public Type
+{
+public:
+                    IInterfaceType();
+
+    virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, int flags);
+    virtual void    CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, Variable** cl);
+};
+
+class BinderType : public Type
+{
+public:
+                    BinderType();
+
+    virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, int flags);
+    virtual void    CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, Variable** cl);
+};
+
+class BinderProxyType : public Type
+{
+public:
+                    BinderProxyType();
+
+    virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, int flags);
+    virtual void    CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, Variable** cl);
+};
+
+class ParcelType : public Type
+{
+public:
+                    ParcelType();
+
+    virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, int flags);
+    virtual void    CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, Variable** cl);
+};
+
+class ParcelableInterfaceType : public Type
+{
+public:
+                    ParcelableInterfaceType();
+
+    virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, int flags);
+    virtual void    CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, Variable** cl);
+};
+
+class MapType : public Type
+{
+public:
+                    MapType();
+
+    virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, int flags);
+    virtual void    CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, Variable** cl);
+    virtual void    ReadFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, Variable** cl);
+};
+
+class ListType : public Type
+{
+public:
+                    ListType();
+
+    virtual string  InstantiableName() const;
+
+    virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, int flags);
+    virtual void    CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, Variable** cl);
+    virtual void    ReadFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, Variable** cl);
+
+    virtual void    WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+                                    Variable* data, int flags);
+    virtual void    CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+                                    Variable* data, Variable** cl);
+};
+
+class UserDataType : public Type
+{
+public:
+                    UserDataType(const string& package, const string& name,
+                            bool builtIn, bool canWriteToParcel, bool canWriteToRpcData,
+                            const string& declFile = "", int declLine = -1);
+
+    virtual string  CreatorName() const;
+    virtual string  RpcCreatorName() const;
+
+    virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, int flags);
+    virtual void    CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, Variable** cl);
+    virtual void    ReadFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, Variable** cl);
+
+    virtual bool    CanBeArray() const;
+
+    virtual void    WriteArrayToParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, int flags);
+    virtual void    CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, Variable** cl);
+    virtual void    ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, Variable** cl);
+
+    virtual void    WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+                                    Variable* data, int flags);
+    virtual void    CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+                                    Variable* data, Variable** cl);
+};
+
+class InterfaceType : public Type
+{
+public:
+                    InterfaceType(const string& package, const string& name,
+                            bool builtIn, bool oneway,
+                            const string& declFile, int declLine);
+
+    bool            OneWay() const;
+    
+    virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, int flags);
+    virtual void    CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, Variable** cl);
+                                    
+private:
+    bool m_oneway;
+};
+
+
+class GenericType : public Type
+{
+public:
+                    GenericType(const string& package, const string& name,
+                                 const vector<Type*>& args);
+
+    const vector<Type*>& GenericArgumentTypes() const;
+    string          GenericArguments() const;
+
+    virtual string  ImportType() const;
+
+    virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, int flags);
+    virtual void    CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, Variable** cl);
+    virtual void    ReadFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, Variable** cl);
+
+private:
+    string m_genericArguments;
+    string m_importName;
+    vector<Type*> m_args;
+};
+
+class RpcDataType : public UserDataType
+{
+public:
+                    RpcDataType();
+
+    virtual void    WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+                                    Variable* data, int flags);
+    virtual void    CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+                                    Variable* data, Variable** cl);
+};
+
+class ClassLoaderType : public Type
+{
+public:
+                    ClassLoaderType();
+};
+
+class GenericListType : public GenericType
+{
+public:
+                    GenericListType(const string& package, const string& name,
+                                 const vector<Type*>& args);
+
+    virtual string  CreatorName() const;
+    virtual string  InstantiableName() const;
+
+    virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, int flags);
+    virtual void    CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, Variable** cl);
+    virtual void    ReadFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, Variable** cl);
+
+    virtual void    WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+                                    Variable* data, int flags);
+    virtual void    CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+                                    Variable* data, Variable** cl);
+    
+private:
+    string m_creator;
+};
+
+class Namespace
+{
+public:
+            Namespace();
+            ~Namespace();
+    void    Add(Type* type);
+
+    // args is the number of template types (what is this called?)
+    void    AddGenericType(const string& package, const string& name, int args);
+
+    // lookup a specific class name
+    Type*   Find(const string& name) const;
+    Type*   Find(const char* package, const char* name) const;
+    
+    // try to search by either a full name or a partial name
+    Type*   Search(const string& name);
+
+    void    Dump() const;
+
+private:
+    struct Generic {
+        string package;
+        string name;
+        string qualified;
+        int args;
+    };
+
+    const Generic* search_generic(const string& name) const;
+
+    vector<Type*> m_types;
+    vector<Generic> m_generics;
+};
+
+extern Namespace NAMES;
+
+extern Type* VOID_TYPE;
+extern Type* BOOLEAN_TYPE;
+extern Type* BYTE_TYPE;
+extern Type* CHAR_TYPE;
+extern Type* INT_TYPE;
+extern Type* LONG_TYPE;
+extern Type* FLOAT_TYPE;
+extern Type* DOUBLE_TYPE;
+extern Type* OBJECT_TYPE;
+extern Type* STRING_TYPE;
+extern Type* CHAR_SEQUENCE_TYPE;
+extern Type* TEXT_UTILS_TYPE;
+extern Type* REMOTE_EXCEPTION_TYPE;
+extern Type* RUNTIME_EXCEPTION_TYPE;
+extern Type* IBINDER_TYPE;
+extern Type* IINTERFACE_TYPE;
+extern Type* BINDER_NATIVE_TYPE;
+extern Type* BINDER_PROXY_TYPE;
+extern Type* PARCEL_TYPE;
+extern Type* PARCELABLE_INTERFACE_TYPE;
+
+extern Type* CONTEXT_TYPE;
+
+extern Type* RPC_DATA_TYPE;
+extern Type* RPC_ERROR_TYPE;
+extern Type* RPC_CONTEXT_TYPE;
+extern Type* EVENT_FAKE_TYPE;
+
+extern Expression* NULL_VALUE;
+extern Expression* THIS_VALUE;
+extern Expression* SUPER_VALUE;
+extern Expression* TRUE_VALUE;
+extern Expression* FALSE_VALUE;
+
+void register_base_types();
+
+#endif // AIDL_TYPE_H
diff --git a/aidl.cpp b/aidl.cpp
new file mode 100644
index 0000000..b8a4803
--- /dev/null
+++ b/aidl.cpp
@@ -0,0 +1,1155 @@
+
+#include "aidl_language.h"
+#include "options.h"
+#include "search_path.h"
+#include "Type.h"
+#include "generate_java.h"
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <map>
+
+#ifdef HAVE_MS_C_RUNTIME
+#include <io.h>
+#include <sys/stat.h>
+#endif
+
+#ifndef O_BINARY
+#  define O_BINARY  0
+#endif
+
+// The following are gotten as the offset from the allowable id's between
+// android.os.IBinder.FIRST_CALL_TRANSACTION=1 and
+// android.os.IBinder.LAST_CALL_TRANSACTION=16777215
+#define MIN_USER_SET_METHOD_ID                0
+#define MAX_USER_SET_METHOD_ID                16777214
+
+using namespace std;
+
+static void
+test_document(document_item_type* d)
+{
+    while (d) {
+        if (d->item_type == INTERFACE_TYPE_BINDER) {
+            interface_type* c = (interface_type*)d;
+            printf("interface %s %s {\n", c->package, c->name.data);
+            interface_item_type *q = (interface_item_type*)c->interface_items;
+            while (q) {
+                if (q->item_type == METHOD_TYPE) {
+                    method_type *m = (method_type*)q;
+                    printf("  %s %s(", m->type.type.data, m->name.data);
+                    arg_type *p = m->args;
+                    while (p) {
+                        printf("%s %s",p->type.type.data,p->name.data);
+                        if (p->next) printf(", ");
+                        p=p->next;
+                    }
+                    printf(")");
+                    printf(";\n");
+                }
+                q=q->next;
+            }
+            printf("}\n");
+        }
+        else if (d->item_type == USER_DATA_TYPE) {
+            user_data_type* b = (user_data_type*)d;
+            if ((b->flattening_methods & PARCELABLE_DATA) != 0) {
+                printf("parcelable %s %s;\n", b->package, b->name.data);
+            }
+            if ((b->flattening_methods & RPC_DATA) != 0) {
+                printf("flattenable %s %s;\n", b->package, b->name.data);
+            }
+        }
+        else {
+            printf("UNKNOWN d=0x%08lx d->item_type=%d\n", (long)d, d->item_type);
+        }
+        d = d->next;
+    }
+}
+
+// ==========================================================
+int
+convert_direction(const char* direction)
+{
+    if (direction == NULL) {
+        return IN_PARAMETER;
+    }
+    if (0 == strcmp(direction, "in")) {
+        return IN_PARAMETER;
+    }
+    if (0 == strcmp(direction, "out")) {
+        return OUT_PARAMETER;
+    }
+    return INOUT_PARAMETER;
+}
+
+// ==========================================================
+struct import_info {
+    const char* from;
+    const char* filename;
+    buffer_type statement;
+    const char* neededClass;
+    document_item_type* doc;
+    struct import_info* next;
+};
+
+document_item_type* g_document = NULL;
+import_info* g_imports = NULL;
+
+static void
+main_document_parsed(document_item_type* d)
+{
+    g_document = d;
+}
+
+static void
+main_import_parsed(buffer_type* statement)
+{
+    import_info* import = (import_info*)malloc(sizeof(import_info));
+    memset(import, 0, sizeof(import_info));
+    import->from = strdup(g_currentFilename);
+    import->statement.lineno = statement->lineno;
+    import->statement.data = strdup(statement->data);
+    import->statement.extra = NULL;
+    import->next = g_imports;
+    import->neededClass = parse_import_statement(statement->data);
+    g_imports = import;
+}
+
+static ParserCallbacks g_mainCallbacks = {
+    &main_document_parsed,
+    &main_import_parsed
+};
+
+char*
+parse_import_statement(const char* text)
+{
+    const char* end;
+    int len;
+
+    while (isspace(*text)) {
+        text++;
+    }
+    while (!isspace(*text)) {
+        text++;
+    }
+    while (isspace(*text)) {
+        text++;
+    }
+    end = text;
+    while (!isspace(*end) && *end != ';') {
+        end++;
+    }
+    len = end-text;
+
+    char* rv = (char*)malloc(len+1);
+    memcpy(rv, text, len);
+    rv[len] = '\0';
+
+    return rv;
+}
+
+// ==========================================================
+static void
+import_import_parsed(buffer_type* statement)
+{
+}
+
+static ParserCallbacks g_importCallbacks = {
+    &main_document_parsed,
+    &import_import_parsed
+};
+
+// ==========================================================
+static int
+check_filename(const char* filename, const char* package, buffer_type* name)
+{
+    const char* p;
+    string expected;
+    string fn;
+    size_t len;
+    char cwd[MAXPATHLEN];
+    bool valid = false;
+
+#ifdef HAVE_WINDOWS_PATHS
+    if (isalpha(filename[0]) && filename[1] == ':'
+        && filename[2] == OS_PATH_SEPARATOR) {
+#else
+    if (filename[0] == OS_PATH_SEPARATOR) {
+#endif
+        fn = filename;
+    } else {
+        fn = getcwd(cwd, sizeof(cwd));
+        len = fn.length();
+        if (fn[len-1] != OS_PATH_SEPARATOR) {
+            fn += OS_PATH_SEPARATOR;
+        }
+        fn += filename;
+    }
+
+    if (package) {
+        expected = package;
+        expected += '.';
+    }
+
+    len = expected.length();
+    for (size_t i=0; i<len; i++) {
+        if (expected[i] == '.') {
+            expected[i] = OS_PATH_SEPARATOR;
+        }
+    }
+
+    p = strchr(name->data, '.');
+    len = p ? p-name->data : strlen(name->data);
+    expected.append(name->data, len);
+    
+    expected += ".aidl";
+
+    len = fn.length();
+    valid = (len >= expected.length());
+
+    if (valid) {
+        p = fn.c_str() + (len - expected.length());
+
+#ifdef HAVE_WINDOWS_PATHS
+        if (OS_PATH_SEPARATOR != '/') {
+            // Input filename under cygwin most likely has / separators
+            // whereas the expected string uses \\ separators. Adjust
+            // them accordingly.
+          for (char *c = const_cast<char *>(p); *c; ++c) {
+                if (*c == '/') *c = OS_PATH_SEPARATOR;
+            }
+        }
+#endif
+
+#ifdef OS_CASE_SENSITIVE
+        valid = (expected == p);
+#else
+        valid = !strcasecmp(expected.c_str(), p);
+#endif
+    }
+
+    if (!valid) {
+        fprintf(stderr, "%s:%d interface %s should be declared in a file"
+                " called %s.\n",
+                filename, name->lineno, name->data, expected.c_str());
+        return 1;
+    }
+
+    return 0;
+}
+
+static int
+check_filenames(const char* filename, document_item_type* items)
+{
+    int err = 0;
+    while (items) {
+        if (items->item_type == USER_DATA_TYPE) {
+            user_data_type* p = (user_data_type*)items;
+            err |= check_filename(filename, p->package, &p->name);
+        }
+        else if (items->item_type == INTERFACE_TYPE_BINDER
+                || items->item_type == INTERFACE_TYPE_RPC) {
+            interface_type* c = (interface_type*)items;
+            err |= check_filename(filename, c->package, &c->name);
+        }
+        else {
+            fprintf(stderr, "aidl: internal error unkown document type %d.\n",
+                        items->item_type);
+            return 1;
+        }
+        items = items->next;
+    }
+    return err;
+}
+
+// ==========================================================
+static const char*
+kind_to_string(int kind)
+{
+    switch (kind)
+    {
+        case Type::INTERFACE:
+            return "an interface";
+        case Type::USERDATA:
+            return "a user data";
+        default:
+            return "ERROR";
+    }
+}
+
+static char*
+rfind(char* str, char c)
+{
+    char* p = str + strlen(str) - 1;
+    while (p >= str) {
+        if (*p == c) {
+            return p;
+        }
+        p--;
+    }
+    return NULL;
+}
+
+static int
+gather_types(const char* filename, document_item_type* items)
+{
+    int err = 0;
+    while (items) {
+        Type* type;
+        if (items->item_type == USER_DATA_TYPE) {
+            user_data_type* p = (user_data_type*)items;
+            type = new UserDataType(p->package ? p->package : "", p->name.data,
+                    false, ((p->flattening_methods & PARCELABLE_DATA) != 0),
+                    ((p->flattening_methods & RPC_DATA) != 0), filename, p->name.lineno);
+        }
+        else if (items->item_type == INTERFACE_TYPE_BINDER
+                || items->item_type == INTERFACE_TYPE_RPC) {
+            interface_type* c = (interface_type*)items;
+            type = new InterfaceType(c->package ? c->package : "",
+                            c->name.data, false, c->oneway,
+                            filename, c->name.lineno);
+        }
+        else {
+            fprintf(stderr, "aidl: internal error %s:%d\n", __FILE__, __LINE__);
+            return 1;
+        }
+
+        Type* old = NAMES.Find(type->QualifiedName());
+        if (old == NULL) {
+            NAMES.Add(type);
+
+            if (items->item_type == INTERFACE_TYPE_BINDER) {
+                // for interfaces, also add the stub and proxy types, we don't
+                // bother checking these for duplicates, because the parser
+                // won't let us do it.
+                interface_type* c = (interface_type*)items;
+
+                string name = c->name.data;
+                name += ".Stub";
+                Type* stub = new Type(c->package ? c->package : "",
+                                        name, Type::GENERATED, false, false, false,
+                                        filename, c->name.lineno);
+                NAMES.Add(stub);
+
+                name = c->name.data;
+                name += ".Stub.Proxy";
+                Type* proxy = new Type(c->package ? c->package : "",
+                                        name, Type::GENERATED, false, false, false,
+                                        filename, c->name.lineno);
+                NAMES.Add(proxy);
+            }
+            else if (items->item_type == INTERFACE_TYPE_RPC) {
+                // for interfaces, also add the service base type, we don't
+                // bother checking these for duplicates, because the parser
+                // won't let us do it.
+                interface_type* c = (interface_type*)items;
+
+                string name = c->name.data;
+                name += ".ServiceBase";
+                Type* base = new Type(c->package ? c->package : "",
+                                        name, Type::GENERATED, false, false, false,
+                                        filename, c->name.lineno);
+                NAMES.Add(base);
+            }
+        } else {
+            if (old->Kind() == Type::BUILT_IN) {
+                fprintf(stderr, "%s:%d attempt to redefine built in class %s\n",
+                            filename, type->DeclLine(),
+                            type->QualifiedName().c_str());
+                err = 1;
+            }
+            else if (type->Kind() != old->Kind()) {
+                const char* oldKind = kind_to_string(old->Kind());
+                const char* newKind = kind_to_string(type->Kind());
+
+                fprintf(stderr, "%s:%d attempt to redefine %s as %s,\n",
+                            filename, type->DeclLine(),
+                            type->QualifiedName().c_str(), newKind);
+                fprintf(stderr, "%s:%d    previously defined here as %s.\n",
+                            old->DeclFile().c_str(), old->DeclLine(), oldKind);
+                err = 1;
+            }
+        }
+
+        items = items->next;
+    }
+    return err;
+}
+
+// ==========================================================
+static bool
+matches_keyword(const char* str)
+{
+    static const char* KEYWORDS[] = { "abstract", "assert", "boolean", "break",
+        "byte", "case", "catch", "char", "class", "const", "continue",
+        "default", "do", "double", "else", "enum", "extends", "final",
+        "finally", "float", "for", "goto", "if", "implements", "import",
+        "instanceof", "int", "interface", "long", "native", "new", "package",
+        "private", "protected", "public", "return", "short", "static",
+        "strictfp", "super", "switch", "synchronized", "this", "throw",
+        "throws", "transient", "try", "void", "volatile", "while",
+        "true", "false", "null",
+        NULL
+    };
+    const char** k = KEYWORDS;
+    while (*k) {
+        if (0 == strcmp(str, *k)) {
+            return true;
+        }
+        k++;
+    }
+    return false;
+}
+
+static int
+check_method(const char* filename, int kind, method_type* m)
+{
+    int err = 0;
+
+    // return type
+    Type* returnType = NAMES.Search(m->type.type.data);
+    if (returnType == NULL) {
+        fprintf(stderr, "%s:%d unknown return type %s\n", filename,
+                    m->type.type.lineno, m->type.type.data);
+        err = 1;
+        return err;
+    }
+
+    if (returnType == EVENT_FAKE_TYPE) {
+        if (kind != INTERFACE_TYPE_RPC) {
+            fprintf(stderr, "%s:%d event methods only supported for rpc interfaces\n",
+                    filename, m->type.type.lineno);
+            err = 1;
+        }
+    } else {
+        if (!(kind == INTERFACE_TYPE_BINDER ? returnType->CanWriteToParcel()
+                    : returnType->CanWriteToRpcData())) {
+            fprintf(stderr, "%s:%d return type %s can't be marshalled.\n", filename,
+                        m->type.type.lineno, m->type.type.data);
+            err = 1;
+        }
+    }
+
+    if (m->type.dimension > 0 && !returnType->CanBeArray()) {
+        fprintf(stderr, "%s:%d return type %s%s can't be an array.\n", filename,
+                m->type.array_token.lineno, m->type.type.data,
+                m->type.array_token.data);
+        err = 1;
+    }
+
+    if (m->type.dimension > 1) {
+        fprintf(stderr, "%s:%d return type %s%s only one"
+                " dimensional arrays are supported\n", filename,
+                m->type.array_token.lineno, m->type.type.data,
+                m->type.array_token.data);
+        err = 1;
+    }
+
+    int index = 1;
+
+    arg_type* arg = m->args;
+    while (arg) {
+        Type* t = NAMES.Search(arg->type.type.data);
+
+        // check the arg type
+        if (t == NULL) {
+            fprintf(stderr, "%s:%d parameter %s (%d) unknown type %s\n",
+                    filename, m->type.type.lineno, arg->name.data, index,
+                    arg->type.type.data);
+            err = 1;
+            goto next;
+        }
+
+        if (t == EVENT_FAKE_TYPE) {
+            fprintf(stderr, "%s:%d parameter %s (%d) event can not be used as a parameter %s\n",
+                    filename, m->type.type.lineno, arg->name.data, index,
+                    arg->type.type.data);
+            err = 1;
+            goto next;
+        }
+        
+        if (!(kind == INTERFACE_TYPE_BINDER ? t->CanWriteToParcel() : t->CanWriteToRpcData())) {
+            fprintf(stderr, "%s:%d parameter %d: '%s %s' can't be marshalled.\n",
+                        filename, m->type.type.lineno, index,
+                        arg->type.type.data, arg->name.data);
+            err = 1;
+        }
+
+        if (returnType == EVENT_FAKE_TYPE
+                && convert_direction(arg->direction.data) != IN_PARAMETER) {
+            fprintf(stderr, "%s:%d parameter %d: '%s %s' All paremeters on events must be 'in'.\n",
+                    filename, m->type.type.lineno, index,
+                    arg->type.type.data, arg->name.data);
+            err = 1;
+            goto next;
+        }
+
+        if (arg->direction.data == NULL
+                && (arg->type.dimension != 0 || t->CanBeOutParameter())) {
+            fprintf(stderr, "%s:%d parameter %d: '%s %s' can be an out"
+                                " parameter, so you must declare it as in,"
+                                " out or inout.\n",
+                        filename, m->type.type.lineno, index,
+                        arg->type.type.data, arg->name.data);
+            err = 1;
+        }
+
+        if (convert_direction(arg->direction.data) != IN_PARAMETER
+                && !t->CanBeOutParameter()
+                && arg->type.dimension == 0) {
+            fprintf(stderr, "%s:%d parameter %d: '%s %s %s' can only be an in"
+                            " parameter.\n",
+                        filename, m->type.type.lineno, index,
+                        arg->direction.data, arg->type.type.data,
+                        arg->name.data);
+            err = 1;
+        }
+
+        if (arg->type.dimension > 0 && !t->CanBeArray()) {
+            fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' can't be an"
+                    " array.\n", filename,
+                    m->type.array_token.lineno, index, arg->direction.data,
+                    arg->type.type.data, arg->type.array_token.data,
+                    arg->name.data);
+            err = 1;
+        }
+
+        if (arg->type.dimension > 1) {
+            fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' only one"
+                    " dimensional arrays are supported\n", filename,
+                    m->type.array_token.lineno, index, arg->direction.data,
+                    arg->type.type.data, arg->type.array_token.data,
+                    arg->name.data);
+            err = 1;
+        }
+
+        // check that the name doesn't match a keyword
+        if (matches_keyword(arg->name.data)) {
+            fprintf(stderr, "%s:%d parameter %d %s is named the same as a"
+                    " Java or aidl keyword\n",
+                    filename, m->name.lineno, index, arg->name.data);
+            err = 1;
+        }
+        
+next:
+        index++;
+        arg = arg->next;
+    }
+
+    return err;
+}
+
+static int
+check_types(const char* filename, document_item_type* items)
+{
+    int err = 0;
+    while (items) {
+        // (nothing to check for USER_DATA_TYPE)
+        if (items->item_type == INTERFACE_TYPE_BINDER
+                || items->item_type == INTERFACE_TYPE_RPC) {
+            map<string,method_type*> methodNames;
+            interface_type* c = (interface_type*)items;
+
+            interface_item_type* member = c->interface_items;
+            while (member) {
+                if (member->item_type == METHOD_TYPE) {
+                    method_type* m = (method_type*)member;
+
+                    err |= check_method(filename, items->item_type, m);
+
+                    // prevent duplicate methods
+                    if (methodNames.find(m->name.data) == methodNames.end()) {
+                        methodNames[m->name.data] = m;
+                    } else {
+                        fprintf(stderr,"%s:%d attempt to redefine method %s,\n",
+                                filename, m->name.lineno, m->name.data);
+                        method_type* old = methodNames[m->name.data];
+                        fprintf(stderr, "%s:%d    previously defined here.\n",
+                                filename, old->name.lineno);
+                        err = 1;
+                    }
+                }
+                member = member->next;
+            }
+        }
+
+        items = items->next;
+    }
+    return err;
+}
+
+// ==========================================================
+static int
+exactly_one_interface(const char* filename, const document_item_type* items, const Options& options,
+                      bool* onlyParcelable)
+{
+    if (items == NULL) {
+        fprintf(stderr, "%s: file does not contain any interfaces\n",
+                            filename);
+        return 1;
+    }
+
+    const document_item_type* next = items->next;
+    // Allow parcelables to skip the "one-only" rule.
+    if (items->next != NULL && next->item_type != USER_DATA_TYPE) {
+        int lineno = -1;
+        if (next->item_type == INTERFACE_TYPE_BINDER) {
+            lineno = ((interface_type*)next)->interface_token.lineno;
+        }
+        else if (next->item_type == INTERFACE_TYPE_RPC) {
+            lineno = ((interface_type*)next)->interface_token.lineno;
+        }
+        fprintf(stderr, "%s:%d aidl can only handle one interface per file\n",
+                            filename, lineno);
+        return 1;
+    }
+
+    if (items->item_type == USER_DATA_TYPE) {
+        *onlyParcelable = true;
+        if (options.failOnParcelable) {
+            fprintf(stderr, "%s:%d aidl can only generate code for interfaces, not"
+                            " parcelables or flattenables,\n", filename,
+                            ((user_data_type*)items)->keyword_token.lineno);
+            fprintf(stderr, "%s:%d .aidl files that only declare parcelables or flattenables"
+                            "may not go in the Makefile.\n", filename,
+                            ((user_data_type*)items)->keyword_token.lineno);
+            return 1;
+        }
+    } else {
+        *onlyParcelable = false;
+    }
+
+    return 0;
+}
+
+// ==========================================================
+void
+generate_dep_file(const Options& options, const document_item_type* items)
+{
+    /* we open the file in binary mode to ensure that the same output is
+     * generated on all platforms !!
+     */
+    FILE* to = NULL;
+    if (options.autoDepFile) {
+        string fileName = options.outputFileName + ".d";
+        to = fopen(fileName.c_str(), "wb");
+    } else {
+        to = fopen(options.depFileName.c_str(), "wb");
+    }
+
+    if (to == NULL) {
+        return;
+    }
+
+    const char* slash = "\\";
+    import_info* import = g_imports;
+    if (import == NULL) {
+        slash = "";
+    }
+
+    if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) {
+        fprintf(to, "%s: \\\n", options.outputFileName.c_str());
+    } else {
+        // parcelable: there's no output file.
+        fprintf(to, " : \\\n");
+    }
+    fprintf(to, "  %s %s\n", options.inputFileName.c_str(), slash);
+
+    while (import) {
+        if (import->next == NULL) {
+            slash = "";
+        }
+        if (import->filename) {
+            fprintf(to, "  %s %s\n", import->filename, slash);
+        }
+        import = import->next;
+    }
+
+    fprintf(to, "\n");
+
+    // Output "<imported_file>: " so make won't fail if the imported file has
+    // been deleted, moved or renamed in incremental build.
+    import = g_imports;
+    while (import) {
+        if (import->filename) {
+            fprintf(to, "%s :\n", import->filename);
+        }
+        import = import->next;
+    }
+
+    fclose(to);
+}
+
+// ==========================================================
+static string
+generate_outputFileName2(const Options& options, const buffer_type& name, const char* package)
+{
+    string result;
+
+    // create the path to the destination folder based on the
+    // interface package name
+    result = options.outputBaseFolder;
+    result += OS_PATH_SEPARATOR;
+
+    string packageStr = package;
+    size_t len = packageStr.length();
+    for (size_t i=0; i<len; i++) {
+        if (packageStr[i] == '.') {
+            packageStr[i] = OS_PATH_SEPARATOR;
+        }
+    }
+
+    result += packageStr;
+
+    // add the filename by replacing the .aidl extension to .java
+    const char* p = strchr(name.data, '.');
+    len = p ? p-name.data : strlen(name.data);
+
+    result += OS_PATH_SEPARATOR;
+    result.append(name.data, len);
+    result += ".java";
+
+    return result;
+}
+
+// ==========================================================
+static string
+generate_outputFileName(const Options& options, const document_item_type* items)
+{
+    // items has already been checked to have only one interface.
+    if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) {
+        interface_type* type = (interface_type*)items;
+
+        return generate_outputFileName2(options, type->name, type->package);
+    } else if (items->item_type == USER_DATA_TYPE) {
+        user_data_type* type = (user_data_type*)items;
+        return generate_outputFileName2(options, type->name, type->package);
+    }
+
+    // I don't think we can come here, but safer than returning NULL.
+    string result;
+    return result;
+}
+
+
+
+// ==========================================================
+static void
+check_outputFilePath(const string& path) {
+    size_t len = path.length();
+    for (size_t i=0; i<len ; i++) {
+        if (path[i] == OS_PATH_SEPARATOR) {
+            string p = path.substr(0, i);
+            if (access(path.data(), F_OK) != 0) {
+#ifdef HAVE_MS_C_RUNTIME
+                _mkdir(p.data());
+#else
+                mkdir(p.data(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
+#endif
+            }
+        }
+    }
+}
+
+
+// ==========================================================
+static int
+parse_preprocessed_file(const string& filename)
+{
+    int err;
+
+    FILE* f = fopen(filename.c_str(), "rb");
+    if (f == NULL) {
+        fprintf(stderr, "aidl: can't open preprocessed file: %s\n",
+                filename.c_str());
+        return 1;
+    }
+
+    int lineno = 1;
+    char line[1024];
+    char type[1024];
+    char fullname[1024];
+    while (fgets(line, sizeof(line), f)) {
+        // skip comments and empty lines
+        if (!line[0] || strncmp(line, "//", 2) == 0) {
+          continue;
+        }
+
+        sscanf(line, "%s %[^; \r\n\t];", type, fullname);
+
+        char* packagename;
+        char* classname = rfind(fullname, '.');
+        if (classname != NULL) {
+            *classname = '\0';
+            classname++;
+            packagename = fullname;
+        } else {
+            classname = fullname;
+            packagename = NULL;
+        }
+
+        //printf("%s:%d:...%s...%s...%s...\n", filename.c_str(), lineno,
+        //        type, packagename, classname);
+        document_item_type* doc;
+        
+        if (0 == strcmp("parcelable", type)) {
+            user_data_type* parcl = (user_data_type*)malloc(
+                    sizeof(user_data_type));
+            memset(parcl, 0, sizeof(user_data_type));
+            parcl->document_item.item_type = USER_DATA_TYPE;
+            parcl->keyword_token.lineno = lineno;
+            parcl->keyword_token.data = strdup(type);
+            parcl->package = packagename ? strdup(packagename) : NULL;
+            parcl->name.lineno = lineno;
+            parcl->name.data = strdup(classname);
+            parcl->semicolon_token.lineno = lineno;
+            parcl->semicolon_token.data = strdup(";");
+            parcl->flattening_methods = PARCELABLE_DATA;
+            doc = (document_item_type*)parcl;
+        }
+        else if (0 == strcmp("flattenable", type)) {
+            user_data_type* parcl = (user_data_type*)malloc(
+                    sizeof(user_data_type));
+            memset(parcl, 0, sizeof(user_data_type));
+            parcl->document_item.item_type = USER_DATA_TYPE;
+            parcl->keyword_token.lineno = lineno;
+            parcl->keyword_token.data = strdup(type);
+            parcl->package = packagename ? strdup(packagename) : NULL;
+            parcl->name.lineno = lineno;
+            parcl->name.data = strdup(classname);
+            parcl->semicolon_token.lineno = lineno;
+            parcl->semicolon_token.data = strdup(";");
+            parcl->flattening_methods = RPC_DATA;
+            doc = (document_item_type*)parcl;
+        }
+        else if (0 == strcmp("interface", type)) {
+            interface_type* iface = (interface_type*)malloc(
+                    sizeof(interface_type));
+            memset(iface, 0, sizeof(interface_type));
+            iface->document_item.item_type = INTERFACE_TYPE_BINDER;
+            iface->interface_token.lineno = lineno;
+            iface->interface_token.data = strdup(type);
+            iface->package = packagename ? strdup(packagename) : NULL;
+            iface->name.lineno = lineno;
+            iface->name.data = strdup(classname);
+            iface->open_brace_token.lineno = lineno;
+            iface->open_brace_token.data = strdup("{");
+            iface->close_brace_token.lineno = lineno;
+            iface->close_brace_token.data = strdup("}");
+            doc = (document_item_type*)iface;
+        }
+        else {
+            fprintf(stderr, "%s:%d: bad type in line: %s\n",
+                    filename.c_str(), lineno, line);
+            return 1;
+        }
+        err = gather_types(filename.c_str(), doc);
+        lineno++;
+    }
+
+    if (!feof(f)) {
+        fprintf(stderr, "%s:%d: error reading file, line to long.\n",
+                filename.c_str(), lineno);
+        return 1;
+    }
+
+    fclose(f);
+    return 0;
+}
+
+static int
+check_and_assign_method_ids(const char * filename, interface_item_type* first_item)
+{
+    // Check whether there are any methods with manually assigned id's and any that are not.
+    // Either all method id's must be manually assigned or all of them must not.
+    // Also, check for duplicates of user set id's and that the id's are within the proper bounds.
+    set<int> usedIds;
+    interface_item_type* item = first_item;
+    bool hasUnassignedIds = false;
+    bool hasAssignedIds = false;
+    while (item != NULL) {
+        if (item->item_type == METHOD_TYPE) {
+            method_type* method_item = (method_type*)item;
+            if (method_item->hasId) {
+                hasAssignedIds = true;
+                method_item->assigned_id = atoi(method_item->id.data);
+                // Ensure that the user set id is not duplicated.
+                if (usedIds.find(method_item->assigned_id) != usedIds.end()) {
+                    // We found a duplicate id, so throw an error.
+                    fprintf(stderr,
+                            "%s:%d Found duplicate method id (%d) for method: %s\n",
+                            filename, method_item->id.lineno,
+                            method_item->assigned_id, method_item->name.data);
+                    return 1;
+                }
+                // Ensure that the user set id is within the appropriate limits
+                if (method_item->assigned_id < MIN_USER_SET_METHOD_ID ||
+                        method_item->assigned_id > MAX_USER_SET_METHOD_ID) {
+                    fprintf(stderr, "%s:%d Found out of bounds id (%d) for method: %s\n",
+                            filename, method_item->id.lineno,
+                            method_item->assigned_id, method_item->name.data);
+                    fprintf(stderr, "    Value for id must be between %d and %d inclusive.\n",
+                            MIN_USER_SET_METHOD_ID, MAX_USER_SET_METHOD_ID);
+                    return 1;
+                }
+                usedIds.insert(method_item->assigned_id);
+            } else {
+                hasUnassignedIds = true;
+            }
+            if (hasAssignedIds && hasUnassignedIds) {
+                fprintf(stderr,
+                        "%s: You must either assign id's to all methods or to none of them.\n",
+                        filename);
+                return 1;
+            }
+        }
+        item = item->next;
+    }
+
+    // In the case that all methods have unassigned id's, set a unique id for them.
+    if (hasUnassignedIds) {
+        int newId = 0;
+        item = first_item;
+        while (item != NULL) {
+            if (item->item_type == METHOD_TYPE) {
+                method_type* method_item = (method_type*)item;
+                method_item->assigned_id = newId++;
+            }
+            item = item->next;
+        }
+    }
+
+    // success
+    return 0;
+}
+
+// ==========================================================
+static int
+compile_aidl(Options& options)
+{
+    int err = 0, N;
+
+    set_import_paths(options.importPaths);
+
+    register_base_types();
+
+    // import the preprocessed file
+    N = options.preprocessedFiles.size();
+    for (int i=0; i<N; i++) {
+        const string& s = options.preprocessedFiles[i];
+        err |= parse_preprocessed_file(s);
+    }
+    if (err != 0) {
+        return err;
+    }
+
+    // parse the main file
+    g_callbacks = &g_mainCallbacks;
+    err = parse_aidl(options.inputFileName.c_str());
+    document_item_type* mainDoc = g_document;
+    g_document = NULL;
+
+    // parse the imports
+    g_callbacks = &g_mainCallbacks;
+    import_info* import = g_imports;
+    while (import) {
+        if (NAMES.Find(import->neededClass) == NULL) {
+            import->filename = find_import_file(import->neededClass);
+            if (!import->filename) {
+                fprintf(stderr, "%s:%d: couldn't find import for class %s\n",
+                        import->from, import->statement.lineno,
+                        import->neededClass);
+                err |= 1;
+            } else {
+                err |= parse_aidl(import->filename);
+                import->doc = g_document;
+                if (import->doc == NULL) {
+                    err |= 1;
+                }
+            }
+        }
+        import = import->next;
+    }
+    // bail out now if parsing wasn't successful
+    if (err != 0 || mainDoc == NULL) {
+        //fprintf(stderr, "aidl: parsing failed, stopping.\n");
+        return 1;
+    }
+
+    // complain about ones that aren't in the right files
+    err |= check_filenames(options.inputFileName.c_str(), mainDoc);
+    import = g_imports;
+    while (import) {
+        err |= check_filenames(import->filename, import->doc);
+        import = import->next;
+    }
+
+    // gather the types that have been declared
+    err |= gather_types(options.inputFileName.c_str(), mainDoc);
+    import = g_imports;
+    while (import) {
+        err |= gather_types(import->filename, import->doc);
+        import = import->next;
+    }
+
+#if 0
+    printf("---- main doc ----\n");
+    test_document(mainDoc);
+
+    import = g_imports;
+    while (import) {
+        printf("---- import doc ----\n");
+        test_document(import->doc);
+        import = import->next;
+    }
+    NAMES.Dump();
+#endif
+
+    // check the referenced types in mainDoc to make sure we've imported them
+    err |= check_types(options.inputFileName.c_str(), mainDoc);
+
+    // finally, there really only needs to be one thing in mainDoc, and it
+    // needs to be an interface.
+    bool onlyParcelable = false;
+    err |= exactly_one_interface(options.inputFileName.c_str(), mainDoc, options, &onlyParcelable);
+
+    // If this includes an interface definition, then assign method ids and validate.
+    if (!onlyParcelable) {
+        err |= check_and_assign_method_ids(options.inputFileName.c_str(),
+                ((interface_type*)mainDoc)->interface_items);
+    }
+
+    // after this, there shouldn't be any more errors because of the
+    // input.
+    if (err != 0 || mainDoc == NULL) {
+        return 1;
+    }
+
+    // if needed, generate the outputFileName from the outputBaseFolder
+    if (options.outputFileName.length() == 0 &&
+            options.outputBaseFolder.length() > 0) {
+        options.outputFileName = generate_outputFileName(options, mainDoc);
+    }
+
+    // if we were asked to, generate a make dependency file
+    // unless it's a parcelable *and* it's supposed to fail on parcelable
+    if ((options.autoDepFile || options.depFileName != "") &&
+            !(onlyParcelable && options.failOnParcelable)) {
+        // make sure the folders of the output file all exists
+        check_outputFilePath(options.outputFileName);
+        generate_dep_file(options, mainDoc);
+    }
+
+    // they didn't ask to fail on parcelables, so just exit quietly.
+    if (onlyParcelable && !options.failOnParcelable) {
+        return 0;
+    }
+
+    // make sure the folders of the output file all exists
+    check_outputFilePath(options.outputFileName);
+
+    err = generate_java(options.outputFileName, options.inputFileName.c_str(),
+                        (interface_type*)mainDoc);
+
+    return err;
+}
+
+static int
+preprocess_aidl(const Options& options)
+{
+    vector<string> lines;
+    int err;
+
+    // read files
+    int N = options.filesToPreprocess.size();
+    for (int i=0; i<N; i++) {
+        g_callbacks = &g_mainCallbacks;
+        err = parse_aidl(options.filesToPreprocess[i].c_str());
+        if (err != 0) {
+            return err;
+        }
+        document_item_type* doc = g_document;
+        string line;
+        if (doc->item_type == USER_DATA_TYPE) {
+            user_data_type* parcelable = (user_data_type*)doc;
+            if ((parcelable->flattening_methods & PARCELABLE_DATA) != 0) {
+                line = "parcelable ";
+            }
+            if ((parcelable->flattening_methods & RPC_DATA) != 0) {
+                line = "flattenable ";
+            }
+            if (parcelable->package) {
+                line += parcelable->package;
+                line += '.';
+            }
+            line += parcelable->name.data;
+        } else {
+            line = "interface ";
+            interface_type* iface = (interface_type*)doc;
+            if (iface->package) {
+                line += iface->package;
+                line += '.';
+            }
+            line += iface->name.data;
+        }
+        line += ";\n";
+        lines.push_back(line);
+    }
+
+    // write preprocessed file
+    int fd = open( options.outputFileName.c_str(), 
+                   O_RDWR|O_CREAT|O_TRUNC|O_BINARY,
+#ifdef HAVE_MS_C_RUNTIME
+                   _S_IREAD|_S_IWRITE);
+#else    
+                   S_IRUSR|S_IWUSR|S_IRGRP);
+#endif            
+    if (fd == -1) {
+        fprintf(stderr, "aidl: could not open file for write: %s\n",
+                options.outputFileName.c_str());
+        return 1;
+    }
+
+    N = lines.size();
+    for (int i=0; i<N; i++) {
+        const string& s = lines[i];
+        int len = s.length();
+        if (len != write(fd, s.c_str(), len)) {
+            fprintf(stderr, "aidl: error writing to file %s\n",
+                options.outputFileName.c_str());
+            close(fd);
+            unlink(options.outputFileName.c_str());
+            return 1;
+        }
+    }
+
+    close(fd);
+    return 0;
+}
+
+// ==========================================================
+int
+main(int argc, const char **argv)
+{
+    Options options;
+    int result = parse_options(argc, argv, &options);
+    if (result) {
+        return result;
+    }
+
+    switch (options.task)
+    {
+        case COMPILE_AIDL:
+            return compile_aidl(options);
+        case PREPROCESS_AIDL:
+            return preprocess_aidl(options);
+    }
+    fprintf(stderr, "aidl: internal error\n");
+    return 1;
+}
diff --git a/aidl_language.cpp b/aidl_language.cpp
new file mode 100644
index 0000000..cd6a3bd
--- /dev/null
+++ b/aidl_language.cpp
@@ -0,0 +1,20 @@
+#include "aidl_language.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef HAVE_MS_C_RUNTIME
+int isatty(int  fd)
+{
+    return (fd == 0);
+}
+#endif
+
+#if 0
+ParserCallbacks k_parserCallbacks = {
+    NULL
+};
+#endif
+
+ParserCallbacks* g_callbacks = NULL; // &k_parserCallbacks;
+
diff --git a/aidl_language.h b/aidl_language.h
new file mode 100644
index 0000000..de1370c
--- /dev/null
+++ b/aidl_language.h
@@ -0,0 +1,172 @@
+#ifndef DEVICE_TOOLS_AIDL_AIDL_LANGUAGE_H
+#define DEVICE_TOOLS_AIDL_AIDL_LANGUAGE_H
+
+
+typedef enum {
+    NO_EXTRA_TEXT = 0,
+    SHORT_COMMENT,
+    LONG_COMMENT,
+    COPY_TEXT,
+    WHITESPACE
+} which_extra_text;
+
+typedef struct extra_text_type {
+    unsigned lineno;
+    which_extra_text which;
+    char* data; 
+    unsigned len;
+    struct extra_text_type* next;
+} extra_text_type;
+
+typedef struct buffer_type {
+    unsigned lineno;
+    unsigned token;
+    char *data;
+    extra_text_type* extra;
+} buffer_type;
+
+typedef struct type_type {
+    buffer_type type;
+    buffer_type array_token;
+    int dimension;
+} type_type;
+
+typedef struct arg_type {
+    buffer_type comma_token; // empty in the first one in the list
+    buffer_type direction;
+    type_type type;
+    buffer_type name;
+    struct arg_type *next;
+} arg_type;
+
+enum {
+    METHOD_TYPE
+};
+
+typedef struct interface_item_type {
+    unsigned item_type;
+    struct interface_item_type* next;
+} interface_item_type;
+
+typedef struct method_type {
+    interface_item_type interface_item;
+    type_type type;
+    bool oneway;
+    buffer_type oneway_token;
+    buffer_type name;
+    buffer_type open_paren_token;
+    arg_type* args;
+    buffer_type close_paren_token;
+    bool hasId;
+    buffer_type equals_token;
+    buffer_type id;
+    // XXX missing comments/copy text here
+    buffer_type semicolon_token;
+    buffer_type* comments_token; // points into this structure, DO NOT DELETE
+    int assigned_id;
+} method_type;
+
+enum {
+    USER_DATA_TYPE = 12,
+    INTERFACE_TYPE_BINDER,
+    INTERFACE_TYPE_RPC
+};
+
+typedef struct document_item_type {
+    unsigned item_type;
+    struct document_item_type* next;
+} document_item_type;
+
+
+// for user_data_type.flattening_methods
+enum {
+    PARCELABLE_DATA = 0x1,
+    RPC_DATA = 0x2
+};
+
+typedef struct user_data_type {
+    document_item_type document_item;
+    buffer_type keyword_token; // only the first one
+    char* package;
+    buffer_type name;
+    buffer_type semicolon_token;
+    int flattening_methods;
+} user_data_type;
+
+typedef struct interface_type {
+    document_item_type document_item;
+    buffer_type interface_token;
+    bool oneway;
+    buffer_type oneway_token;
+    char* package;
+    buffer_type name;
+    buffer_type open_brace_token;
+    interface_item_type* interface_items;
+    buffer_type close_brace_token;
+    buffer_type* comments_token; // points into this structure, DO NOT DELETE
+} interface_type;
+
+typedef union lexer_type {
+    buffer_type buffer;
+    type_type type;
+    arg_type *arg;
+    method_type* method;
+    interface_item_type* interface_item;
+    interface_type* interface_obj;
+    user_data_type* user_data;
+    document_item_type* document_item;
+} lexer_type;
+
+
+#define YYSTYPE lexer_type
+
+#if __cplusplus
+extern "C" {
+#endif
+
+int parse_aidl(char const *);
+
+// strips off the leading whitespace, the "import" text
+// also returns whether it's a local or system import
+// we rely on the input matching the import regex from below
+char* parse_import_statement(const char* text);
+
+// in, out or inout
+enum {
+    IN_PARAMETER = 1,
+    OUT_PARAMETER = 2,
+    INOUT_PARAMETER = 3
+};
+int convert_direction(const char* direction);
+
+// callbacks from within the parser
+// these functions all take ownership of the strings
+typedef struct ParserCallbacks {
+    void (*document)(document_item_type* items);
+    void (*import)(buffer_type* statement);
+} ParserCallbacks;
+
+extern ParserCallbacks* g_callbacks;
+
+// true if there was an error parsing, false otherwise
+extern int g_error;
+
+// the name of the file we're currently parsing
+extern char const* g_currentFilename;
+
+// the package name for our current file
+extern char const* g_currentPackage;
+
+typedef enum {
+    STATEMENT_INSIDE_INTERFACE
+} error_type;
+
+void init_buffer_type(buffer_type* buf, int lineno);
+
+
+#if __cplusplus
+}
+#endif
+
+
+#endif // DEVICE_TOOLS_AIDL_AIDL_LANGUAGE_H
diff --git a/aidl_language_l.l b/aidl_language_l.l
new file mode 100644
index 0000000..3d33e7a
--- /dev/null
+++ b/aidl_language_l.l
@@ -0,0 +1,214 @@
+%{
+#include "aidl_language.h"
+#include "aidl_language_y.h"
+#include "search_path.h"
+#include <string.h>
+#include <stdlib.h>
+
+extern YYSTYPE yylval;
+
+// comment and whitespace handling
+// these functions save a copy of the buffer
+static void begin_extra_text(unsigned lineno, which_extra_text which);
+static void append_extra_text(char* text);
+static extra_text_type* get_extra_text(void);   // you now own the object
+                                                // this returns
+static void drop_extra_text(void);
+
+// package handling
+static void do_package_statement(const char* importText);
+
+#define SET_BUFFER(t) \
+    do { \
+        yylval.buffer.lineno = yylineno; \
+        yylval.buffer.token = (t); \
+        yylval.buffer.data = strdup(yytext); \
+        yylval.buffer.extra = get_extra_text(); \
+    } while(0)
+
+%}
+
+%option yylineno
+%option noyywrap
+
+%x COPYING LONG_COMMENT
+
+identifier  [_a-zA-Z][_a-zA-Z0-9\.]*
+whitespace  ([ \t\n\r]+)
+brackets    \[{whitespace}?\]
+idvalue     (0|[1-9][0-9]*)
+
+%%
+
+
+\%\%\{              { begin_extra_text(yylineno, COPY_TEXT); BEGIN(COPYING); }
+<COPYING>\}\%\%     { BEGIN(INITIAL); }
+<COPYING>.*\n       { append_extra_text(yytext); }
+<COPYING>.*         { append_extra_text(yytext); }
+<COPYING>\n+        { append_extra_text(yytext); }
+
+
+\/\*                            { begin_extra_text(yylineno, (which_extra_text)LONG_COMMENT);
+                                  BEGIN(LONG_COMMENT); }
+<LONG_COMMENT>[^*]*             { append_extra_text(yytext); }
+<LONG_COMMENT>\*+[^/]           { append_extra_text(yytext); }
+<LONG_COMMENT>\n                { append_extra_text(yytext); }
+<LONG_COMMENT>\**\/             { BEGIN(INITIAL); }
+
+^{whitespace}?import{whitespace}[^ \t\r\n]+{whitespace}?;  {
+                                                SET_BUFFER(IMPORT);
+                                                return IMPORT;
+                                            }
+^{whitespace}?package{whitespace}[^ \t\r\n]+{whitespace}?;  {
+                                                do_package_statement(yytext);
+                                                SET_BUFFER(PACKAGE);
+                                                return PACKAGE;
+                                            }
+<<EOF>>             { yyterminate(); }
+
+\/\/.*\n            { begin_extra_text(yylineno, SHORT_COMMENT);
+                        append_extra_text(yytext); }
+
+{whitespace}    { /* begin_extra_text(yylineno, WHITESPACE);
+                    append_extra_text(yytext); */ }
+
+;               { SET_BUFFER(';'); return ';'; }
+\{              { SET_BUFFER('{'); return '{'; }
+\}              { SET_BUFFER('}'); return '}'; }
+\(              { SET_BUFFER('('); return '('; }
+\)              { SET_BUFFER(')'); return ')'; }
+,               { SET_BUFFER(','); return ','; }
+=               { SET_BUFFER('='); return '='; }
+
+    /* keywords */
+parcelable      { SET_BUFFER(PARCELABLE); return PARCELABLE; }
+interface       { SET_BUFFER(INTERFACE); return INTERFACE; }
+flattenable     { SET_BUFFER(FLATTENABLE); return FLATTENABLE; }
+rpc             { SET_BUFFER(INTERFACE); return RPC; }
+in              { SET_BUFFER(IN); return IN; }
+out             { SET_BUFFER(OUT); return OUT; }
+inout           { SET_BUFFER(INOUT); return INOUT; }
+oneway          { SET_BUFFER(ONEWAY); return ONEWAY; }
+
+{brackets}+     { SET_BUFFER(ARRAY); return ARRAY; }
+{idvalue}       { SET_BUFFER(IDVALUE); return IDVALUE; }
+{identifier}                                        { SET_BUFFER(IDENTIFIER); return IDENTIFIER; }
+{identifier}\<{whitespace}*{identifier}({whitespace}*,{whitespace}*{identifier})*{whitespace}*\>    {
+                                                      SET_BUFFER(GENERIC); return GENERIC; }
+
+    /* syntax error! */
+.               { printf("UNKNOWN(%s)", yytext);
+                  yylval.buffer.lineno = yylineno;
+                  yylval.buffer.token = IDENTIFIER;
+                  yylval.buffer.data = strdup(yytext);
+                  return IDENTIFIER;
+                }
+
+%%
+
+// comment and whitespace handling
+// ================================================
+extra_text_type* g_extraText = NULL;
+extra_text_type* g_nextExtraText = NULL;
+
+void begin_extra_text(unsigned lineno, which_extra_text which)
+{
+    extra_text_type* text = (extra_text_type*)malloc(sizeof(extra_text_type));
+    text->lineno = lineno;
+    text->which = which;
+    text->data = NULL;
+    text->len = 0;
+    text->next = NULL;
+    if (g_nextExtraText == NULL) {
+        g_extraText = text;
+    } else {
+        g_nextExtraText->next = text;
+    }
+    g_nextExtraText = text;
+}
+
+void append_extra_text(char* text)
+{
+    if (g_nextExtraText->data == NULL) {
+        g_nextExtraText->data = strdup(text);
+        g_nextExtraText->len = strlen(text);
+    } else {
+        char* orig = g_nextExtraText->data;
+        unsigned oldLen = g_nextExtraText->len;
+        unsigned len = strlen(text);
+        g_nextExtraText->len += len;
+        g_nextExtraText->data = (char*)malloc(g_nextExtraText->len+1);
+        memcpy(g_nextExtraText->data, orig, oldLen);
+        memcpy(g_nextExtraText->data+oldLen, text, len);
+        g_nextExtraText->data[g_nextExtraText->len] = '\0';
+        free(orig);
+    }
+}
+
+extra_text_type*
+get_extra_text(void)
+{
+    extra_text_type* result = g_extraText;
+    g_extraText = NULL;
+    g_nextExtraText = NULL;
+    return result;
+}
+
+void drop_extra_text(void)
+{
+    extra_text_type* p = g_extraText;
+    while (p) {
+        extra_text_type* next = p->next;
+        free(p->data);
+        free(p);
+        free(next);
+    }
+    g_extraText = NULL;
+    g_nextExtraText = NULL;
+}
+
+
+// package handling
+// ================================================
+void do_package_statement(const char* importText)
+{
+    if (g_currentPackage) free((void*)g_currentPackage);
+    g_currentPackage = parse_import_statement(importText);
+}
+
+
+// main parse function
+// ================================================
+char const* g_currentFilename = NULL;
+char const* g_currentPackage = NULL;
+
+int yyparse(void);
+
+int parse_aidl(char const *filename)
+{
+    yyin = fopen(filename, "r");
+    if (yyin) {
+        char const* oldFilename = g_currentFilename;
+        char const* oldPackage = g_currentPackage;
+        g_currentFilename = strdup(filename);
+
+        g_error = 0;
+        yylineno = 1;
+        int rv = yyparse();
+        if (g_error != 0) {
+            rv = g_error;
+        }
+
+        free((void*)g_currentFilename);
+        g_currentFilename = oldFilename;
+        
+        if (g_currentPackage) free((void*)g_currentPackage);
+        g_currentPackage = oldPackage;
+
+        return rv;
+    } else {
+        fprintf(stderr, "aidl: unable to open file for read: %s\n", filename);
+        return 1;
+    }
+}
+
diff --git a/aidl_language_y.y b/aidl_language_y.y
new file mode 100644
index 0000000..9b40d28
--- /dev/null
+++ b/aidl_language_y.y
@@ -0,0 +1,373 @@
+%{
+#include "aidl_language.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int yyerror(char* errstr);
+int yylex(void);
+extern int yylineno;
+
+static int count_brackets(const char*);
+
+%}
+
+%token IMPORT
+%token PACKAGE
+%token IDENTIFIER
+%token IDVALUE
+%token GENERIC
+%token ARRAY
+%token PARCELABLE
+%token INTERFACE
+%token FLATTENABLE
+%token RPC
+%token IN
+%token OUT
+%token INOUT
+%token ONEWAY
+
+%%
+document:
+        document_items                          { g_callbacks->document($1.document_item); }
+    |   headers document_items                  { g_callbacks->document($2.document_item); }
+    ;
+
+headers:
+        package                                 { }
+    |   imports                                 { }
+    |   package imports                         { }
+    ;
+
+package:
+        PACKAGE                                 { }
+    ;
+
+imports:
+        IMPORT                                  { g_callbacks->import(&($1.buffer)); }
+    |   IMPORT imports                          { g_callbacks->import(&($1.buffer)); }
+    ;
+
+document_items:
+                                                { $$.document_item = NULL; }
+    |   document_items declaration              {
+                                                    if ($2.document_item == NULL) {
+                                                        // error cases only
+                                                        $$ = $1;
+                                                    } else {
+                                                        document_item_type* p = $1.document_item;
+                                                        while (p && p->next) {
+                                                            p=p->next;
+                                                        }
+                                                        if (p) {
+                                                            p->next = (document_item_type*)$2.document_item;
+                                                            $$ = $1;
+                                                        } else {
+                                                            $$.document_item = (document_item_type*)$2.document_item;
+                                                        }
+                                                    }
+                                                }
+    | document_items error                      {
+                                                    fprintf(stderr, "%s:%d: syntax error don't know what to do with \"%s\"\n", g_currentFilename,
+                                                            $2.buffer.lineno, $2.buffer.data);
+                                                    $$ = $1;
+                                                }
+    ;
+
+declaration:
+        parcelable_decl                            { $$.document_item = (document_item_type*)$1.user_data; }
+    |   interface_decl                             { $$.document_item = (document_item_type*)$1.interface_item; }
+    ;
+
+parcelable_decl:
+        PARCELABLE IDENTIFIER ';'                   {
+                                                        user_data_type* b = (user_data_type*)malloc(sizeof(user_data_type));
+                                                        b->document_item.item_type = USER_DATA_TYPE;
+                                                        b->document_item.next = NULL;
+                                                        b->keyword_token = $1.buffer;
+                                                        b->name = $2.buffer;
+                                                        b->package = g_currentPackage ? strdup(g_currentPackage) : NULL;
+                                                        b->semicolon_token = $3.buffer;
+                                                        b->flattening_methods = PARCELABLE_DATA;
+                                                        $$.user_data = b;
+                                                    }
+    |   PARCELABLE ';'                              {
+                                                        fprintf(stderr, "%s:%d syntax error in parcelable declaration. Expected type name.\n",
+                                                                     g_currentFilename, $1.buffer.lineno);
+                                                        $$.user_data = NULL;
+                                                    }
+    |   PARCELABLE error ';'                        {
+                                                        fprintf(stderr, "%s:%d syntax error in parcelable declaration. Expected type name, saw \"%s\".\n",
+                                                                     g_currentFilename, $2.buffer.lineno, $2.buffer.data);
+                                                        $$.user_data = NULL;
+                                                    }
+    |   FLATTENABLE IDENTIFIER ';'                  {
+                                                        user_data_type* b = (user_data_type*)malloc(sizeof(user_data_type));
+                                                        b->document_item.item_type = USER_DATA_TYPE;
+                                                        b->document_item.next = NULL;
+                                                        b->keyword_token = $1.buffer;
+                                                        b->name = $2.buffer;
+                                                        b->package = g_currentPackage ? strdup(g_currentPackage) : NULL;
+                                                        b->semicolon_token = $3.buffer;
+                                                        b->flattening_methods = PARCELABLE_DATA | RPC_DATA;
+                                                        $$.user_data = b;
+                                                    }
+    |   FLATTENABLE ';'                             {
+                                                        fprintf(stderr, "%s:%d syntax error in flattenable declaration. Expected type name.\n",
+                                                                     g_currentFilename, $1.buffer.lineno);
+                                                        $$.user_data = NULL;
+                                                    }
+    |   FLATTENABLE error ';'                       {
+                                                        fprintf(stderr, "%s:%d syntax error in flattenable declaration. Expected type name, saw \"%s\".\n",
+                                                                     g_currentFilename, $2.buffer.lineno, $2.buffer.data);
+                                                        $$.user_data = NULL;
+                                                    }
+
+    ;
+
+interface_header:
+        INTERFACE                                  {
+                                                        interface_type* c = (interface_type*)malloc(sizeof(interface_type));
+                                                        c->document_item.item_type = INTERFACE_TYPE_BINDER;
+                                                        c->document_item.next = NULL;
+                                                        c->interface_token = $1.buffer;
+                                                        c->oneway = false;
+                                                        memset(&c->oneway_token, 0, sizeof(buffer_type));
+                                                        c->comments_token = &c->interface_token;
+                                                        $$.interface_obj = c;
+                                                   }
+    |   ONEWAY INTERFACE                           {
+                                                        interface_type* c = (interface_type*)malloc(sizeof(interface_type));
+                                                        c->document_item.item_type = INTERFACE_TYPE_BINDER;
+                                                        c->document_item.next = NULL;
+                                                        c->interface_token = $2.buffer;
+                                                        c->oneway = true;
+                                                        c->oneway_token = $1.buffer;
+                                                        c->comments_token = &c->oneway_token;
+                                                        $$.interface_obj = c;
+                                                   }
+    |   RPC                                        {
+                                                        interface_type* c = (interface_type*)malloc(sizeof(interface_type));
+                                                        c->document_item.item_type = INTERFACE_TYPE_RPC;
+                                                        c->document_item.next = NULL;
+                                                        c->interface_token = $1.buffer;
+                                                        c->oneway = false;
+                                                        memset(&c->oneway_token, 0, sizeof(buffer_type));
+                                                        c->comments_token = &c->interface_token;
+                                                        $$.interface_obj = c;
+                                                   }
+    ;
+
+interface_keywords:
+        INTERFACE
+    |   RPC
+    ;
+
+interface_decl:
+        interface_header IDENTIFIER '{' interface_items '}' { 
+                                                        interface_type* c = $1.interface_obj;
+                                                        c->name = $2.buffer;
+                                                        c->package = g_currentPackage ? strdup(g_currentPackage) : NULL;
+                                                        c->open_brace_token = $3.buffer;
+                                                        c->interface_items = $4.interface_item;
+                                                        c->close_brace_token = $5.buffer;
+                                                        $$.interface_obj = c;
+                                                    }
+    |   interface_keywords error '{' interface_items '}'     {
+                                                        fprintf(stderr, "%s:%d: syntax error in interface declaration.  Expected type name, saw \"%s\"\n",
+                                                                    g_currentFilename, $2.buffer.lineno, $2.buffer.data);
+                                                        $$.document_item = NULL;
+                                                    }
+    |   interface_keywords error '}'                {
+                                                        fprintf(stderr, "%s:%d: syntax error in interface declaration.  Expected type name, saw \"%s\"\n",
+                                                                    g_currentFilename, $2.buffer.lineno, $2.buffer.data);
+                                                        $$.document_item = NULL;
+                                                    }
+
+    ;
+
+interface_items:
+                                                    { $$.interface_item = NULL; }
+    |   interface_items method_decl                 {
+                                                        interface_item_type* p=$1.interface_item;
+                                                        while (p && p->next) {
+                                                            p=p->next;
+                                                        }
+                                                        if (p) {
+                                                            p->next = (interface_item_type*)$2.method;
+                                                            $$ = $1;
+                                                        } else {
+                                                            $$.interface_item = (interface_item_type*)$2.method;
+                                                        }
+                                                    }
+    |   interface_items error ';'                   {
+                                                        fprintf(stderr, "%s:%d: syntax error before ';' (expected method declaration)\n",
+                                                                    g_currentFilename, $3.buffer.lineno);
+                                                        $$ = $1;
+                                                    }
+    ;
+
+method_decl:
+        type IDENTIFIER '(' arg_list ')' ';'  {
+                                                        method_type *method = (method_type*)malloc(sizeof(method_type));
+                                                        method->interface_item.item_type = METHOD_TYPE;
+                                                        method->interface_item.next = NULL;
+                                                        method->oneway = false;
+                                                        method->type = $1.type;
+                                                        memset(&method->oneway_token, 0, sizeof(buffer_type));
+                                                        method->name = $2.buffer;
+                                                        method->open_paren_token = $3.buffer;
+                                                        method->args = $4.arg;
+                                                        method->close_paren_token = $5.buffer;
+                                                        method->hasId = false;
+                                                        memset(&method->equals_token, 0, sizeof(buffer_type));
+                                                        memset(&method->id, 0, sizeof(buffer_type));
+                                                        method->semicolon_token = $6.buffer;
+                                                        method->comments_token = &method->type.type;
+                                                        $$.method = method;
+                                                    }
+    |   ONEWAY type IDENTIFIER '(' arg_list ')' ';'  {
+                                                        method_type *method = (method_type*)malloc(sizeof(method_type));
+                                                        method->interface_item.item_type = METHOD_TYPE;
+                                                        method->interface_item.next = NULL;
+                                                        method->oneway = true;
+                                                        method->oneway_token = $1.buffer;
+                                                        method->type = $2.type;
+                                                        method->name = $3.buffer;
+                                                        method->open_paren_token = $4.buffer;
+                                                        method->args = $5.arg;
+                                                        method->close_paren_token = $6.buffer;
+                                                        method->hasId = false;
+                                                        memset(&method->equals_token, 0, sizeof(buffer_type));
+                                                        memset(&method->id, 0, sizeof(buffer_type));
+                                                        method->semicolon_token = $7.buffer;
+                                                        method->comments_token = &method->oneway_token;
+                                                        $$.method = method;
+                                                    }
+    |    type IDENTIFIER '(' arg_list ')' '=' IDVALUE ';'  {
+                                                        method_type *method = (method_type*)malloc(sizeof(method_type));
+                                                        method->interface_item.item_type = METHOD_TYPE;
+                                                        method->interface_item.next = NULL;
+                                                        method->oneway = false;
+                                                        memset(&method->oneway_token, 0, sizeof(buffer_type));
+                                                        method->type = $1.type;
+                                                        method->name = $2.buffer;
+                                                        method->open_paren_token = $3.buffer;
+                                                        method->args = $4.arg;
+                                                        method->close_paren_token = $5.buffer;
+                                                        method->hasId = true;
+                                                        method->equals_token = $6.buffer;
+                                                        method->id = $7.buffer;
+                                                        method->semicolon_token = $8.buffer;
+                                                        method->comments_token = &method->type.type;
+                                                        $$.method = method;
+                                                    }
+    |   ONEWAY type IDENTIFIER '(' arg_list ')' '=' IDVALUE ';'  {
+                                                        method_type *method = (method_type*)malloc(sizeof(method_type));
+                                                        method->interface_item.item_type = METHOD_TYPE;
+                                                        method->interface_item.next = NULL;
+                                                        method->oneway = true;
+                                                        method->oneway_token = $1.buffer;
+                                                        method->type = $2.type;
+                                                        method->name = $3.buffer;
+                                                        method->open_paren_token = $4.buffer;
+                                                        method->args = $5.arg;
+                                                        method->close_paren_token = $6.buffer;
+                                                        method->hasId = true;
+                                                        method->equals_token = $7.buffer;
+                                                        method->id = $8.buffer;
+                                                        method->semicolon_token = $9.buffer;
+                                                        method->comments_token = &method->oneway_token;
+                                                        $$.method = method;
+                                                    }
+    ;
+
+arg_list:
+                                { $$.arg = NULL; }
+    |   arg                     { $$ = $1; }
+    |   arg_list ',' arg        {
+                                    if ($$.arg != NULL) {
+                                        // only NULL on error
+                                        $$ = $1;
+                                        arg_type *p = $1.arg;
+                                        while (p && p->next) {
+                                            p=p->next;
+                                        }
+                                        $3.arg->comma_token = $2.buffer;
+                                        p->next = $3.arg;
+                                    }
+                                }
+    |   error                   {
+                                    fprintf(stderr, "%s:%d: syntax error in parameter list\n", g_currentFilename, $1.buffer.lineno);
+                                    $$.arg = NULL;
+                                }
+    ;
+
+arg:
+        direction type IDENTIFIER     {
+                                                arg_type* arg = (arg_type*)malloc(sizeof(arg_type));
+                                                memset(&arg->comma_token, 0, sizeof(buffer_type));
+                                                arg->direction = $1.buffer;
+                                                arg->type = $2.type;
+                                                arg->name = $3.buffer;
+                                                arg->next = NULL;
+                                                $$.arg = arg;
+                                      }
+    ;
+
+type:
+        IDENTIFIER              {
+                                    $$.type.type = $1.buffer;
+                                    init_buffer_type(&$$.type.array_token, yylineno);
+                                    $$.type.dimension = 0;
+                                }
+    |   IDENTIFIER ARRAY        {
+                                    $$.type.type = $1.buffer;
+                                    $$.type.array_token = $2.buffer;
+                                    $$.type.dimension = count_brackets($2.buffer.data);
+                                }
+    |   GENERIC                 {
+                                    $$.type.type = $1.buffer;
+                                    init_buffer_type(&$$.type.array_token, yylineno);
+                                    $$.type.dimension = 0;
+                                }
+    ;
+
+direction:
+                    { init_buffer_type(&$$.buffer, yylineno); }
+    |   IN          { $$.buffer = $1.buffer; }
+    |   OUT         { $$.buffer = $1.buffer; }
+    |   INOUT       { $$.buffer = $1.buffer; }
+    ;
+
+%%
+
+#include <ctype.h>
+#include <stdio.h>
+
+int g_error = 0;
+
+int yyerror(char* errstr)
+{
+    fprintf(stderr, "%s:%d: %s\n", g_currentFilename, yylineno, errstr);
+    g_error = 1;
+    return 1;
+}
+
+void init_buffer_type(buffer_type* buf, int lineno)
+{
+    buf->lineno = lineno;
+    buf->token = 0;
+    buf->data = NULL;
+    buf->extra = NULL;
+}
+
+static int count_brackets(const char* s)
+{
+    int n=0;
+    while (*s) {
+        if (*s == '[') n++;
+        s++;
+    }
+    return n;
+}
diff --git a/generate_java.cpp b/generate_java.cpp
new file mode 100644
index 0000000..9e57407
--- /dev/null
+++ b/generate_java.cpp
@@ -0,0 +1,99 @@
+#include "generate_java.h"
+#include "Type.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+// =================================================
+VariableFactory::VariableFactory(const string& base)
+    :m_base(base),
+     m_index(0)
+{
+}
+
+Variable*
+VariableFactory::Get(Type* type)
+{
+    char name[100];
+    sprintf(name, "%s%d", m_base.c_str(), m_index);
+    m_index++;
+    Variable* v = new Variable(type, name);
+    m_vars.push_back(v);
+    return v;
+}
+
+Variable*
+VariableFactory::Get(int index)
+{
+    return m_vars[index];
+}
+
+// =================================================
+string
+gather_comments(extra_text_type* extra)
+{
+    string s;
+    while (extra) {
+        if (extra->which == SHORT_COMMENT) {
+            s += extra->data;
+        }
+        else if (extra->which == LONG_COMMENT) {
+            s += "/*";
+            s += extra->data;
+            s += "*/";
+        }
+        extra = extra->next;
+    }
+    return s;
+}
+
+string
+append(const char* a, const char* b)
+{
+    string s = a;
+    s += b;
+    return s;
+}
+
+// =================================================
+int
+generate_java(const string& filename, const string& originalSrc,
+                interface_type* iface)
+{
+    Class* cl;
+
+    if (iface->document_item.item_type == INTERFACE_TYPE_BINDER) {
+        cl = generate_binder_interface_class(iface);
+    }
+    else if (iface->document_item.item_type == INTERFACE_TYPE_RPC) {
+        cl = generate_rpc_interface_class(iface);
+    }
+
+    Document* document = new Document;
+        document->comment = "";
+        if (iface->package) document->package = iface->package;
+        document->originalSrc = originalSrc;
+        document->classes.push_back(cl);
+
+//    printf("outputting... filename=%s\n", filename.c_str());
+    FILE* to;
+    if (filename == "-") {
+        to = stdout;
+    } else {
+       /* open file in binary mode to ensure that the tool produces the
+        * same output on all platforms !!
+        */
+        to = fopen(filename.c_str(), "wb");
+        if (to == NULL) {
+            fprintf(stderr, "unable to open %s for write\n", filename.c_str());
+            return 1;
+        }
+    }
+
+    document->Write(to);
+
+    fclose(to);
+    return 0;
+}
+
diff --git a/generate_java.h b/generate_java.h
new file mode 100644
index 0000000..4bfcfeb
--- /dev/null
+++ b/generate_java.h
@@ -0,0 +1,33 @@
+#ifndef GENERATE_JAVA_H
+#define GENERATE_JAVA_H
+
+#include "aidl_language.h"
+#include "AST.h"
+
+#include <string>
+
+using namespace std;
+
+int generate_java(const string& filename, const string& originalSrc,
+                interface_type* iface);
+
+Class* generate_binder_interface_class(const interface_type* iface);
+Class* generate_rpc_interface_class(const interface_type* iface);
+
+string gather_comments(extra_text_type* extra);
+string append(const char* a, const char* b);
+
+class VariableFactory
+{
+public:
+    VariableFactory(const string& base); // base must be short
+    Variable* Get(Type* type);
+    Variable* Get(int index);
+private:
+    vector<Variable*> m_vars;
+    string m_base;
+    int m_index;
+};
+
+#endif // GENERATE_JAVA_H
+
diff --git a/generate_java_binder.cpp b/generate_java_binder.cpp
new file mode 100644
index 0000000..f291ceb
--- /dev/null
+++ b/generate_java_binder.cpp
@@ -0,0 +1,560 @@
+#include "generate_java.h"
+#include "Type.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+// =================================================
+class StubClass : public Class
+{
+public:
+    StubClass(Type* type, Type* interfaceType);
+    virtual ~StubClass();
+
+    Variable* transact_code;
+    Variable* transact_data;
+    Variable* transact_reply;
+    Variable* transact_flags;
+    SwitchStatement* transact_switch;
+private:
+    void make_as_interface(Type* interfaceType);
+};
+
+StubClass::StubClass(Type* type, Type* interfaceType)
+    :Class()
+{
+    this->comment = "/** Local-side IPC implementation stub class. */";
+    this->modifiers = PUBLIC | ABSTRACT | STATIC;
+    this->what = Class::CLASS;
+    this->type = type;
+    this->extends = BINDER_NATIVE_TYPE;
+    this->interfaces.push_back(interfaceType);
+
+    // descriptor
+    Field* descriptor = new Field(STATIC | FINAL | PRIVATE,
+                            new Variable(STRING_TYPE, "DESCRIPTOR"));
+    descriptor->value = "\"" + interfaceType->QualifiedName() + "\"";
+    this->elements.push_back(descriptor);
+
+    // ctor
+    Method* ctor = new Method;
+        ctor->modifiers = PUBLIC;
+        ctor->comment = "/** Construct the stub at attach it to the "
+                        "interface. */";
+        ctor->name = "Stub";
+        ctor->statements = new StatementBlock;
+    MethodCall* attach = new MethodCall(THIS_VALUE, "attachInterface",
+                            2, THIS_VALUE, new LiteralExpression("DESCRIPTOR"));
+    ctor->statements->Add(attach);
+    this->elements.push_back(ctor);
+
+    // asInterface
+    make_as_interface(interfaceType);
+
+    // asBinder
+    Method* asBinder = new Method;
+        asBinder->modifiers = PUBLIC | OVERRIDE;
+        asBinder->returnType = IBINDER_TYPE;
+        asBinder->name = "asBinder";
+        asBinder->statements = new StatementBlock;
+    asBinder->statements->Add(new ReturnStatement(THIS_VALUE));
+    this->elements.push_back(asBinder);
+
+    // onTransact
+    this->transact_code = new Variable(INT_TYPE, "code");
+    this->transact_data = new Variable(PARCEL_TYPE, "data");
+    this->transact_reply = new Variable(PARCEL_TYPE, "reply");
+    this->transact_flags = new Variable(INT_TYPE, "flags");
+    Method* onTransact = new Method;
+        onTransact->modifiers = PUBLIC | OVERRIDE;
+        onTransact->returnType = BOOLEAN_TYPE;
+        onTransact->name = "onTransact";
+        onTransact->parameters.push_back(this->transact_code);
+        onTransact->parameters.push_back(this->transact_data);
+        onTransact->parameters.push_back(this->transact_reply);
+        onTransact->parameters.push_back(this->transact_flags);
+        onTransact->statements = new StatementBlock;
+        onTransact->exceptions.push_back(REMOTE_EXCEPTION_TYPE);
+    this->elements.push_back(onTransact);
+    this->transact_switch = new SwitchStatement(this->transact_code);
+
+    onTransact->statements->Add(this->transact_switch);
+    MethodCall* superCall = new MethodCall(SUPER_VALUE, "onTransact", 4,
+                                    this->transact_code, this->transact_data,
+                                    this->transact_reply, this->transact_flags);
+    onTransact->statements->Add(new ReturnStatement(superCall));
+}
+
+StubClass::~StubClass()
+{
+}
+
+void
+StubClass::make_as_interface(Type *interfaceType)
+{
+    Variable* obj = new Variable(IBINDER_TYPE, "obj");
+
+    Method* m = new Method;
+        m->comment = "/**\n * Cast an IBinder object into an ";
+        m->comment += interfaceType->QualifiedName();
+        m->comment += " interface,\n";
+        m->comment += " * generating a proxy if needed.\n */";
+        m->modifiers = PUBLIC | STATIC;
+        m->returnType = interfaceType;
+        m->name = "asInterface";
+        m->parameters.push_back(obj);
+        m->statements = new StatementBlock;
+
+    IfStatement* ifstatement = new IfStatement();
+        ifstatement->expression = new Comparison(obj, "==", NULL_VALUE);
+        ifstatement->statements = new StatementBlock;
+        ifstatement->statements->Add(new ReturnStatement(NULL_VALUE));
+    m->statements->Add(ifstatement);
+
+    // IInterface iin = obj.queryLocalInterface(DESCRIPTOR)
+    MethodCall* queryLocalInterface = new MethodCall(obj, "queryLocalInterface");
+    queryLocalInterface->arguments.push_back(new LiteralExpression("DESCRIPTOR"));
+    IInterfaceType* iinType = new IInterfaceType();
+    Variable *iin = new Variable(iinType, "iin");
+    VariableDeclaration* iinVd = new VariableDeclaration(iin, queryLocalInterface, NULL);
+    m->statements->Add(iinVd);
+
+    // Ensure the instance type of the local object is as expected.
+    // One scenario where this is needed is if another package (with a
+    // different class loader) runs in the same process as the service.
+
+    // if (iin != null && iin instanceof <interfaceType>) return (<interfaceType>) iin;
+    Comparison* iinNotNull = new Comparison(iin, "!=", NULL_VALUE);
+    Comparison* instOfCheck = new Comparison(iin, " instanceof ",
+            new LiteralExpression(interfaceType->QualifiedName()));
+    IfStatement* instOfStatement = new IfStatement();
+        instOfStatement->expression = new Comparison(iinNotNull, "&&", instOfCheck);
+        instOfStatement->statements = new StatementBlock;
+        instOfStatement->statements->Add(new ReturnStatement(new Cast(interfaceType, iin)));
+    m->statements->Add(instOfStatement);
+
+    string proxyType = interfaceType->QualifiedName();
+    proxyType += ".Stub.Proxy";
+    NewExpression* ne = new NewExpression(NAMES.Find(proxyType));
+    ne->arguments.push_back(obj);
+    m->statements->Add(new ReturnStatement(ne));
+
+    this->elements.push_back(m);
+}
+
+
+
+// =================================================
+class ProxyClass : public Class
+{
+public:
+    ProxyClass(Type* type, InterfaceType* interfaceType);
+    virtual ~ProxyClass();
+
+    Variable* mRemote;
+    bool mOneWay;
+};
+
+ProxyClass::ProxyClass(Type* type, InterfaceType* interfaceType)
+    :Class()
+{
+    this->modifiers = PRIVATE | STATIC;
+    this->what = Class::CLASS;
+    this->type = type;
+    this->interfaces.push_back(interfaceType);
+
+    mOneWay = interfaceType->OneWay();
+
+    // IBinder mRemote
+    mRemote = new Variable(IBINDER_TYPE, "mRemote");
+    this->elements.push_back(new Field(PRIVATE, mRemote));
+
+    // Proxy()
+    Variable* remote = new Variable(IBINDER_TYPE, "remote");
+    Method* ctor = new Method;
+        ctor->name = "Proxy";
+        ctor->statements = new StatementBlock;
+        ctor->parameters.push_back(remote);
+    ctor->statements->Add(new Assignment(mRemote, remote));
+    this->elements.push_back(ctor);
+
+    // IBinder asBinder()
+    Method* asBinder = new Method;
+        asBinder->modifiers = PUBLIC | OVERRIDE;
+        asBinder->returnType = IBINDER_TYPE;
+        asBinder->name = "asBinder";
+        asBinder->statements = new StatementBlock;
+    asBinder->statements->Add(new ReturnStatement(mRemote));
+    this->elements.push_back(asBinder);
+}
+
+ProxyClass::~ProxyClass()
+{
+}
+
+// =================================================
+static void
+generate_new_array(Type* t, StatementBlock* addTo, Variable* v,
+                            Variable* parcel)
+{
+    Variable* len = new Variable(INT_TYPE, v->name + "_length");
+    addTo->Add(new VariableDeclaration(len, new MethodCall(parcel, "readInt")));
+    IfStatement* lencheck = new IfStatement();
+    lencheck->expression = new Comparison(len, "<", new LiteralExpression("0"));
+    lencheck->statements->Add(new Assignment(v, NULL_VALUE));
+    lencheck->elseif = new IfStatement();
+    lencheck->elseif->statements->Add(new Assignment(v,
+                new NewArrayExpression(t, len)));
+    addTo->Add(lencheck);
+}
+
+static void
+generate_write_to_parcel(Type* t, StatementBlock* addTo, Variable* v,
+                            Variable* parcel, int flags)
+{
+    if (v->dimension == 0) {
+        t->WriteToParcel(addTo, v, parcel, flags);
+    }
+    if (v->dimension == 1) {
+        t->WriteArrayToParcel(addTo, v, parcel, flags);
+    }
+}
+
+static void
+generate_create_from_parcel(Type* t, StatementBlock* addTo, Variable* v,
+                            Variable* parcel, Variable** cl)
+{
+    if (v->dimension == 0) {
+        t->CreateFromParcel(addTo, v, parcel, cl);
+    }
+    if (v->dimension == 1) {
+        t->CreateArrayFromParcel(addTo, v, parcel, cl);
+    }
+}
+
+static void
+generate_read_from_parcel(Type* t, StatementBlock* addTo, Variable* v,
+                            Variable* parcel, Variable** cl)
+{
+    if (v->dimension == 0) {
+        t->ReadFromParcel(addTo, v, parcel, cl);
+    }
+    if (v->dimension == 1) {
+        t->ReadArrayFromParcel(addTo, v, parcel, cl);
+    }
+}
+
+
+static void
+generate_method(const method_type* method, Class* interface,
+                    StubClass* stubClass, ProxyClass* proxyClass, int index)
+{
+    arg_type* arg;
+    int i;
+    bool hasOutParams = false;
+
+    const bool oneway = proxyClass->mOneWay || method->oneway;
+
+    // == the TRANSACT_ constant =============================================
+    string transactCodeName = "TRANSACTION_";
+    transactCodeName += method->name.data;
+
+    char transactCodeValue[60];
+    sprintf(transactCodeValue, "(android.os.IBinder.FIRST_CALL_TRANSACTION + %d)", index);
+
+    Field* transactCode = new Field(STATIC | FINAL,
+                            new Variable(INT_TYPE, transactCodeName));
+    transactCode->value = transactCodeValue;
+    stubClass->elements.push_back(transactCode);
+
+    // == the declaration in the interface ===================================
+    Method* decl = new Method;
+        decl->comment = gather_comments(method->comments_token->extra);
+        decl->modifiers = PUBLIC;
+        decl->returnType = NAMES.Search(method->type.type.data);
+        decl->returnTypeDimension = method->type.dimension;
+        decl->name = method->name.data;
+
+    arg = method->args;
+    while (arg != NULL) {
+        decl->parameters.push_back(new Variable(
+                            NAMES.Search(arg->type.type.data), arg->name.data,
+                            arg->type.dimension));
+        arg = arg->next;
+    }
+
+    decl->exceptions.push_back(REMOTE_EXCEPTION_TYPE);
+
+    interface->elements.push_back(decl);
+
+    // == the stub method ====================================================
+
+    Case* c = new Case(transactCodeName);
+
+    MethodCall* realCall = new MethodCall(THIS_VALUE, method->name.data);
+
+    // interface token validation is the very first thing we do
+    c->statements->Add(new MethodCall(stubClass->transact_data,
+            "enforceInterface", 1, new LiteralExpression("DESCRIPTOR")));
+
+    // args
+    Variable* cl = NULL;
+    VariableFactory stubArgs("_arg");
+    arg = method->args;
+    while (arg != NULL) {
+        Type* t = NAMES.Search(arg->type.type.data);
+        Variable* v = stubArgs.Get(t);
+        v->dimension = arg->type.dimension;
+
+        c->statements->Add(new VariableDeclaration(v));
+
+        if (convert_direction(arg->direction.data) & IN_PARAMETER) {
+            generate_create_from_parcel(t, c->statements, v,
+                    stubClass->transact_data, &cl);
+        } else {
+            if (arg->type.dimension == 0) {
+                c->statements->Add(new Assignment(v, new NewExpression(v->type)));
+            }
+            else if (arg->type.dimension == 1) {
+                generate_new_array(v->type, c->statements, v,
+                        stubClass->transact_data);
+            }
+            else {
+                fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__,
+                        __LINE__);
+            }
+        }
+
+        realCall->arguments.push_back(v);
+
+        arg = arg->next;
+    }
+
+    // the real call
+    Variable* _result = NULL;
+    if (0 == strcmp(method->type.type.data, "void")) {
+        c->statements->Add(realCall);
+
+        if (!oneway) {
+            // report that there were no exceptions
+            MethodCall* ex = new MethodCall(stubClass->transact_reply,
+                    "writeNoException", 0);
+            c->statements->Add(ex);
+        }
+    } else {
+        _result = new Variable(decl->returnType, "_result",
+                                decl->returnTypeDimension);
+        c->statements->Add(new VariableDeclaration(_result, realCall));
+
+        if (!oneway) {
+            // report that there were no exceptions
+            MethodCall* ex = new MethodCall(stubClass->transact_reply,
+                    "writeNoException", 0);
+            c->statements->Add(ex);
+        }
+
+        // marshall the return value
+        generate_write_to_parcel(decl->returnType, c->statements, _result,
+                                    stubClass->transact_reply,
+                                    Type::PARCELABLE_WRITE_RETURN_VALUE);
+    }
+
+    // out parameters
+    i = 0;
+    arg = method->args;
+    while (arg != NULL) {
+        Type* t = NAMES.Search(arg->type.type.data);
+        Variable* v = stubArgs.Get(i++);
+
+        if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
+            generate_write_to_parcel(t, c->statements, v,
+                                stubClass->transact_reply,
+                                Type::PARCELABLE_WRITE_RETURN_VALUE);
+            hasOutParams = true;
+        }
+
+        arg = arg->next;
+    }
+
+    // return true
+    c->statements->Add(new ReturnStatement(TRUE_VALUE));
+    stubClass->transact_switch->cases.push_back(c);
+
+    // == the proxy method ===================================================
+    Method* proxy = new Method;
+        proxy->comment = gather_comments(method->comments_token->extra);
+        proxy->modifiers = PUBLIC | OVERRIDE;
+        proxy->returnType = NAMES.Search(method->type.type.data);
+        proxy->returnTypeDimension = method->type.dimension;
+        proxy->name = method->name.data;
+        proxy->statements = new StatementBlock;
+        arg = method->args;
+        while (arg != NULL) {
+            proxy->parameters.push_back(new Variable(
+                            NAMES.Search(arg->type.type.data), arg->name.data,
+                            arg->type.dimension));
+            arg = arg->next;
+        }
+        proxy->exceptions.push_back(REMOTE_EXCEPTION_TYPE);
+    proxyClass->elements.push_back(proxy);
+
+    // the parcels
+    Variable* _data = new Variable(PARCEL_TYPE, "_data");
+    proxy->statements->Add(new VariableDeclaration(_data,
+                                new MethodCall(PARCEL_TYPE, "obtain")));
+    Variable* _reply = NULL;
+    if (!oneway) {
+        _reply = new Variable(PARCEL_TYPE, "_reply");
+        proxy->statements->Add(new VariableDeclaration(_reply,
+                                    new MethodCall(PARCEL_TYPE, "obtain")));
+    }
+
+    // the return value
+    _result = NULL;
+    if (0 != strcmp(method->type.type.data, "void")) {
+        _result = new Variable(proxy->returnType, "_result",
+                method->type.dimension);
+        proxy->statements->Add(new VariableDeclaration(_result));
+    }
+
+    // try and finally
+    TryStatement* tryStatement = new TryStatement();
+    proxy->statements->Add(tryStatement);
+    FinallyStatement* finallyStatement = new FinallyStatement();
+    proxy->statements->Add(finallyStatement);
+
+    // the interface identifier token: the DESCRIPTOR constant, marshalled as a string
+    tryStatement->statements->Add(new MethodCall(_data, "writeInterfaceToken",
+            1, new LiteralExpression("DESCRIPTOR")));
+
+    // the parameters
+    arg = method->args;
+    while (arg != NULL) {
+        Type* t = NAMES.Search(arg->type.type.data);
+        Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
+        int dir = convert_direction(arg->direction.data);
+        if (dir == OUT_PARAMETER && arg->type.dimension != 0) {
+            IfStatement* checklen = new IfStatement();
+            checklen->expression = new Comparison(v, "==", NULL_VALUE);
+            checklen->statements->Add(new MethodCall(_data, "writeInt", 1,
+                        new LiteralExpression("-1")));
+            checklen->elseif = new IfStatement();
+            checklen->elseif->statements->Add(new MethodCall(_data, "writeInt",
+                        1, new FieldVariable(v, "length")));
+            tryStatement->statements->Add(checklen);
+        }
+        else if (dir & IN_PARAMETER) {
+            generate_write_to_parcel(t, tryStatement->statements, v, _data, 0);
+        }
+        arg = arg->next;
+    }
+
+    // the transact call
+    MethodCall* call = new MethodCall(proxyClass->mRemote, "transact", 4,
+                            new LiteralExpression("Stub." + transactCodeName),
+                            _data, _reply ? _reply : NULL_VALUE,
+                            new LiteralExpression(
+                                oneway ? "android.os.IBinder.FLAG_ONEWAY" : "0"));
+    tryStatement->statements->Add(call);
+
+    // throw back exceptions.
+    if (_reply) {
+        MethodCall* ex = new MethodCall(_reply, "readException", 0);
+        tryStatement->statements->Add(ex);
+    }
+
+    // returning and cleanup
+    if (_reply != NULL) {
+        if (_result != NULL) {
+            generate_create_from_parcel(proxy->returnType,
+                    tryStatement->statements, _result, _reply, &cl);
+        }
+
+        // the out/inout parameters
+        arg = method->args;
+        while (arg != NULL) {
+            Type* t = NAMES.Search(arg->type.type.data);
+            Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
+            if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
+                generate_read_from_parcel(t, tryStatement->statements,
+                                            v, _reply, &cl);
+            }
+            arg = arg->next;
+        }
+
+        finallyStatement->statements->Add(new MethodCall(_reply, "recycle"));
+    }
+    finallyStatement->statements->Add(new MethodCall(_data, "recycle"));
+
+    if (_result != NULL) {
+        proxy->statements->Add(new ReturnStatement(_result));
+    }
+}
+
+static void
+generate_interface_descriptors(StubClass* stub, ProxyClass* proxy)
+{
+    // the interface descriptor transaction handler
+    Case* c = new Case("INTERFACE_TRANSACTION");
+    c->statements->Add(new MethodCall(stub->transact_reply, "writeString",
+            1, new LiteralExpression("DESCRIPTOR")));
+    c->statements->Add(new ReturnStatement(TRUE_VALUE));
+    stub->transact_switch->cases.push_back(c);
+
+    // and the proxy-side method returning the descriptor directly
+    Method* getDesc = new Method;
+    getDesc->modifiers = PUBLIC;
+    getDesc->returnType = STRING_TYPE;
+    getDesc->returnTypeDimension = 0;
+    getDesc->name = "getInterfaceDescriptor";
+    getDesc->statements = new StatementBlock;
+    getDesc->statements->Add(new ReturnStatement(new LiteralExpression("DESCRIPTOR")));
+    proxy->elements.push_back(getDesc);
+}
+
+Class*
+generate_binder_interface_class(const interface_type* iface)
+{
+    InterfaceType* interfaceType = static_cast<InterfaceType*>(
+        NAMES.Find(iface->package, iface->name.data));
+
+    // the interface class
+    Class* interface = new Class;
+        interface->comment = gather_comments(iface->comments_token->extra);
+        interface->modifiers = PUBLIC;
+        interface->what = Class::INTERFACE;
+        interface->type = interfaceType;
+        interface->interfaces.push_back(IINTERFACE_TYPE);
+
+    // the stub inner class
+    StubClass* stub = new StubClass(
+        NAMES.Find(iface->package, append(iface->name.data, ".Stub").c_str()),
+        interfaceType);
+    interface->elements.push_back(stub);
+
+    // the proxy inner class
+    ProxyClass* proxy = new ProxyClass(
+        NAMES.Find(iface->package,
+                         append(iface->name.data, ".Stub.Proxy").c_str()),
+        interfaceType);
+    stub->elements.push_back(proxy);
+
+    // stub and proxy support for getInterfaceDescriptor()
+    generate_interface_descriptors(stub, proxy);
+
+    // all the declared methods of the interface
+    int index = 0;
+    interface_item_type* item = iface->interface_items;
+    while (item != NULL) {
+        if (item->item_type == METHOD_TYPE) {
+            method_type * method_item = (method_type*) item;
+            generate_method(method_item, interface, stub, proxy, method_item->assigned_id);
+        }
+        item = item->next;
+        index++;
+    }
+
+    return interface;
+}
+
diff --git a/generate_java_rpc.cpp b/generate_java_rpc.cpp
new file mode 100644
index 0000000..5e4dacc
--- /dev/null
+++ b/generate_java_rpc.cpp
@@ -0,0 +1,1001 @@
+#include "generate_java.h"
+#include "Type.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+Type* SERVICE_CONTEXT_TYPE = new Type("android.content",
+        "Context", Type::BUILT_IN, false, false, false);
+Type* PRESENTER_BASE_TYPE = new Type("android.support.place.connector",
+        "EventListener", Type::BUILT_IN, false, false, false);
+Type* PRESENTER_LISTENER_BASE_TYPE = new Type("android.support.place.connector",
+        "EventListener.Listener", Type::BUILT_IN, false, false, false);
+Type* RPC_BROKER_TYPE = new Type("android.support.place.connector", "Broker",
+        Type::BUILT_IN, false, false, false);
+Type* RPC_CONTAINER_TYPE = new Type("com.android.athome.connector", "ConnectorContainer",
+        Type::BUILT_IN, false, false, false);
+Type* PLACE_INFO_TYPE = new Type("android.support.place.connector", "PlaceInfo",
+        Type::BUILT_IN, false, false, false);
+// TODO: Just use Endpoint, so this works for all endpoints.
+Type* RPC_CONNECTOR_TYPE = new Type("android.support.place.connector", "Connector",
+        Type::BUILT_IN, false, false, false);
+Type* RPC_ENDPOINT_INFO_TYPE = new UserDataType("android.support.place.rpc",
+        "EndpointInfo", true, __FILE__, __LINE__);
+Type* RPC_RESULT_HANDLER_TYPE = new UserDataType("android.support.place.rpc", "RpcResultHandler",
+        true, __FILE__, __LINE__);
+Type* RPC_ERROR_LISTENER_TYPE = new Type("android.support.place.rpc", "RpcErrorHandler",
+        Type::BUILT_IN, false, false, false);
+Type* RPC_CONTEXT_TYPE = new UserDataType("android.support.place.rpc", "RpcContext", true,
+        __FILE__, __LINE__);
+
+static void generate_create_from_data(Type* t, StatementBlock* addTo, const string& key,
+        Variable* v, Variable* data, Variable** cl);
+static void generate_new_array(Type* t, StatementBlock* addTo, Variable* v, Variable* from);
+static void generate_write_to_data(Type* t, StatementBlock* addTo, Expression* k, Variable* v,
+        Variable* data);
+
+static string
+format_int(int n)
+{
+    char str[20];
+    sprintf(str, "%d", n);
+    return string(str);
+}
+
+static string
+class_name_leaf(const string& str)
+{
+    string::size_type pos = str.rfind('.');
+    if (pos == string::npos) {
+        return str;
+    } else {
+        return string(str, pos+1);
+    }
+}
+
+static string
+results_class_name(const string& n)
+{
+    string str = n;
+    str[0] = toupper(str[0]);
+    str.insert(0, "On");
+    return str;
+}
+
+static string
+results_method_name(const string& n)
+{
+    string str = n;
+    str[0] = toupper(str[0]);
+    str.insert(0, "on");
+    return str;
+}
+
+static string
+push_method_name(const string& n)
+{
+    string str = n;
+    str[0] = toupper(str[0]);
+    str.insert(0, "push");
+    return str;
+}
+
+// =================================================
+class DispatcherClass : public Class
+{
+public:
+    DispatcherClass(const interface_type* iface, Expression* target);
+    virtual ~DispatcherClass();
+
+    void AddMethod(const method_type* method);
+    void DoneWithMethods();
+
+    Method* processMethod;
+    Variable* actionParam;
+    Variable* requestParam;
+    Variable* rpcContextParam;
+    Variable* errorParam;
+    Variable* requestData;
+    Variable* resultData;
+    IfStatement* dispatchIfStatement;
+    Expression* targetExpression;
+
+private:
+    void generate_process();
+};
+
+DispatcherClass::DispatcherClass(const interface_type* iface, Expression* target)
+    :Class(),
+     dispatchIfStatement(NULL),
+     targetExpression(target)
+{
+    generate_process();
+}
+
+DispatcherClass::~DispatcherClass()
+{
+}
+
+void
+DispatcherClass::generate_process()
+{
+    // byte[] process(String action, byte[] params, RpcContext context, RpcError status)
+    this->processMethod = new Method;
+        this->processMethod->modifiers = PUBLIC;
+        this->processMethod->returnType = BYTE_TYPE;
+        this->processMethod->returnTypeDimension = 1;
+        this->processMethod->name = "process";
+        this->processMethod->statements = new StatementBlock;
+
+    this->actionParam = new Variable(STRING_TYPE, "action");
+    this->processMethod->parameters.push_back(this->actionParam);
+
+    this->requestParam = new Variable(BYTE_TYPE, "requestParam", 1);
+    this->processMethod->parameters.push_back(this->requestParam);
+
+    this->rpcContextParam = new Variable(RPC_CONTEXT_TYPE, "context", 0);
+    this->processMethod->parameters.push_back(this->rpcContextParam);    
+
+    this->errorParam = new Variable(RPC_ERROR_TYPE, "errorParam", 0);
+    this->processMethod->parameters.push_back(this->errorParam);
+
+    this->requestData = new Variable(RPC_DATA_TYPE, "request");
+    this->processMethod->statements->Add(new VariableDeclaration(requestData,
+                new NewExpression(RPC_DATA_TYPE, 1, this->requestParam)));
+
+    this->resultData = new Variable(RPC_DATA_TYPE, "resultData");
+    this->processMethod->statements->Add(new VariableDeclaration(this->resultData,
+                NULL_VALUE));
+}
+
+void
+DispatcherClass::AddMethod(const method_type* method)
+{
+    arg_type* arg;
+
+    // The if/switch statement
+    IfStatement* ifs = new IfStatement();
+        ifs->expression = new MethodCall(new StringLiteralExpression(method->name.data), "equals",
+                1, this->actionParam);
+    StatementBlock* block = ifs->statements = new StatementBlock;
+    if (this->dispatchIfStatement == NULL) {
+        this->dispatchIfStatement = ifs;
+        this->processMethod->statements->Add(dispatchIfStatement);
+    } else {
+        this->dispatchIfStatement->elseif = ifs;
+        this->dispatchIfStatement = ifs;
+    }
+    
+    // The call to decl (from above)
+    MethodCall* realCall = new MethodCall(this->targetExpression, method->name.data);
+
+    // args
+    Variable* classLoader = NULL;
+    VariableFactory stubArgs("_arg");
+    arg = method->args;
+    while (arg != NULL) {
+        Type* t = NAMES.Search(arg->type.type.data);
+        Variable* v = stubArgs.Get(t);
+        v->dimension = arg->type.dimension;
+
+        // Unmarshall the parameter
+        block->Add(new VariableDeclaration(v));
+        if (convert_direction(arg->direction.data) & IN_PARAMETER) {
+            generate_create_from_data(t, block, arg->name.data, v,
+                    this->requestData, &classLoader);
+        } else {
+            if (arg->type.dimension == 0) {
+                block->Add(new Assignment(v, new NewExpression(v->type)));
+            }
+            else if (arg->type.dimension == 1) {
+                generate_new_array(v->type, block, v, this->requestData);
+            }
+            else {
+                fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__,
+                        __LINE__);
+            }
+        }
+
+        // Add that parameter to the method call
+        realCall->arguments.push_back(v);
+
+        arg = arg->next;
+    }
+
+    // Add a final parameter: RpcContext. Contains data about
+    // incoming request (e.g., certificate)
+    realCall->arguments.push_back(new Variable(RPC_CONTEXT_TYPE, "context", 0));
+
+    Type* returnType = NAMES.Search(method->type.type.data);
+    if (returnType == EVENT_FAKE_TYPE) {
+        returnType = VOID_TYPE;
+    }
+    
+    // the real call
+    bool first = true;
+    Variable* _result = NULL;
+    if (returnType == VOID_TYPE) {
+        block->Add(realCall);
+    } else {
+        _result = new Variable(returnType, "_result",
+                                method->type.dimension);
+        block->Add(new VariableDeclaration(_result, realCall));
+
+        // need the result RpcData
+        if (first) {
+            block->Add(new Assignment(this->resultData,
+                        new NewExpression(RPC_DATA_TYPE)));
+            first = false;
+        }
+
+        // marshall the return value
+        generate_write_to_data(returnType, block,
+                new StringLiteralExpression("_result"), _result, this->resultData);
+    }
+
+    // out parameters
+    int i = 0;
+    arg = method->args;
+    while (arg != NULL) {
+        Type* t = NAMES.Search(arg->type.type.data);
+        Variable* v = stubArgs.Get(i++);
+
+        if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
+            // need the result RpcData
+            if (first) {
+                block->Add(new Assignment(this->resultData, new NewExpression(RPC_DATA_TYPE)));
+                first = false;
+            }
+
+            generate_write_to_data(t, block, new StringLiteralExpression(arg->name.data),
+                    v, this->resultData);
+        }
+
+        arg = arg->next;
+    }
+}
+
+void
+DispatcherClass::DoneWithMethods()
+{
+    if (this->dispatchIfStatement == NULL) {
+        return;
+    }
+
+    this->elements.push_back(this->processMethod);
+
+    IfStatement* fallthrough = new IfStatement();
+        fallthrough->statements = new StatementBlock;
+        fallthrough->statements->Add(new ReturnStatement(
+                    new MethodCall(SUPER_VALUE, "process", 4, 
+                    this->actionParam, this->requestParam, 
+                    this->rpcContextParam,
+                    this->errorParam)));
+    this->dispatchIfStatement->elseif = fallthrough;
+    IfStatement* s = new IfStatement;
+        s->statements = new StatementBlock;
+    this->processMethod->statements->Add(s);
+    s->expression = new Comparison(this->resultData, "!=", NULL_VALUE);
+    s->statements->Add(new ReturnStatement(new MethodCall(this->resultData, "serialize")));
+    s->elseif = new IfStatement;
+    s = s->elseif;
+    s->statements->Add(new ReturnStatement(NULL_VALUE));
+}
+
+// =================================================
+class RpcProxyClass : public Class
+{
+public:
+    RpcProxyClass(const interface_type* iface, InterfaceType* interfaceType);
+    virtual ~RpcProxyClass();
+
+    Variable* endpoint;
+    Variable* broker;
+
+private:
+    void generate_ctor();
+    void generate_get_endpoint_info();
+};
+
+RpcProxyClass::RpcProxyClass(const interface_type* iface, InterfaceType* interfaceType)
+    :Class()
+{
+    this->comment = gather_comments(iface->comments_token->extra);
+    this->modifiers = PUBLIC;
+    this->what = Class::CLASS;
+    this->type = interfaceType;
+
+    // broker
+    this->broker = new Variable(RPC_BROKER_TYPE, "_broker");
+    this->elements.push_back(new Field(PRIVATE, this->broker));
+    // endpoint
+    this->endpoint = new Variable(RPC_ENDPOINT_INFO_TYPE, "_endpoint");
+    this->elements.push_back(new Field(PRIVATE, this->endpoint));
+
+    // methods
+    generate_ctor();
+    generate_get_endpoint_info();
+}
+
+RpcProxyClass::~RpcProxyClass()
+{
+}
+
+void
+RpcProxyClass::generate_ctor()
+{
+    Variable* broker = new Variable(RPC_BROKER_TYPE, "broker");
+    Variable* endpoint = new Variable(RPC_ENDPOINT_INFO_TYPE, "endpoint");
+    Method* ctor = new Method;
+        ctor->modifiers = PUBLIC;
+        ctor->name = class_name_leaf(this->type->Name());
+        ctor->statements = new StatementBlock;
+        ctor->parameters.push_back(broker);
+        ctor->parameters.push_back(endpoint);
+    this->elements.push_back(ctor);
+
+    ctor->statements->Add(new Assignment(this->broker, broker));
+    ctor->statements->Add(new Assignment(this->endpoint, endpoint));
+}
+
+void
+RpcProxyClass::generate_get_endpoint_info()
+{
+    Method* get = new Method;
+    get->modifiers = PUBLIC;
+    get->returnType = RPC_ENDPOINT_INFO_TYPE;
+    get->name = "getEndpointInfo";
+    get->statements = new StatementBlock;
+    this->elements.push_back(get);
+
+    get->statements->Add(new ReturnStatement(this->endpoint));
+}
+
+// =================================================
+class EventListenerClass : public DispatcherClass
+{
+public:
+    EventListenerClass(const interface_type* iface, Type* listenerType);
+    virtual ~EventListenerClass();
+
+    Variable* _listener;
+
+private:
+    void generate_ctor();
+};
+
+Expression*
+generate_get_listener_expression(Type* cast)
+{
+    return new Cast(cast, new MethodCall(THIS_VALUE, "getView"));
+}
+
+EventListenerClass::EventListenerClass(const interface_type* iface, Type* listenerType)
+    :DispatcherClass(iface, new FieldVariable(THIS_VALUE, "_listener"))
+{
+    this->modifiers = PRIVATE;
+    this->what = Class::CLASS;
+    this->type = new Type(iface->package ? iface->package : "",
+                        append(iface->name.data, ".Presenter"),
+                        Type::GENERATED, false, false, false);
+    this->extends = PRESENTER_BASE_TYPE;
+
+    this->_listener = new Variable(listenerType, "_listener");
+    this->elements.push_back(new Field(PRIVATE, this->_listener));
+
+    // methods
+    generate_ctor();
+}
+
+EventListenerClass::~EventListenerClass()
+{
+}
+
+void
+EventListenerClass::generate_ctor()
+{
+    Variable* broker = new Variable(RPC_BROKER_TYPE, "broker");
+    Variable* listener = new Variable(this->_listener->type, "listener");
+    Method* ctor = new Method;
+        ctor->modifiers = PUBLIC;
+        ctor->name = class_name_leaf(this->type->Name());
+        ctor->statements = new StatementBlock;
+        ctor->parameters.push_back(broker);
+        ctor->parameters.push_back(listener);
+    this->elements.push_back(ctor);
+
+    ctor->statements->Add(new MethodCall("super", 2, broker, listener));
+    ctor->statements->Add(new Assignment(this->_listener, listener));
+}
+
+// =================================================
+class ListenerClass : public Class
+{
+public:
+    ListenerClass(const interface_type* iface);
+    virtual ~ListenerClass();
+
+    bool needed;
+
+private:
+    void generate_ctor();
+};
+
+ListenerClass::ListenerClass(const interface_type* iface)
+    :Class(),
+     needed(false)
+{
+    this->comment = "/** Extend this to listen to the events from this class. */";
+    this->modifiers = STATIC | PUBLIC ;
+    this->what = Class::CLASS;
+    this->type = new Type(iface->package ? iface->package : "",
+                        append(iface->name.data, ".Listener"),
+                        Type::GENERATED, false, false, false);
+    this->extends = PRESENTER_LISTENER_BASE_TYPE;
+}
+
+ListenerClass::~ListenerClass()
+{
+}
+
+// =================================================
+class EndpointBaseClass : public DispatcherClass
+{
+public:
+    EndpointBaseClass(const interface_type* iface);
+    virtual ~EndpointBaseClass();
+
+    bool needed;
+
+private:
+    void generate_ctor();
+};
+
+EndpointBaseClass::EndpointBaseClass(const interface_type* iface)
+    :DispatcherClass(iface, THIS_VALUE),
+     needed(false)
+{
+    this->comment = "/** Extend this to implement a link service. */";
+    this->modifiers = STATIC | PUBLIC | ABSTRACT;
+    this->what = Class::CLASS;
+    this->type = new Type(iface->package ? iface->package : "",
+                        append(iface->name.data, ".EndpointBase"),
+                        Type::GENERATED, false, false, false);
+    this->extends = RPC_CONNECTOR_TYPE;
+
+    // methods
+    generate_ctor();
+}
+
+EndpointBaseClass::~EndpointBaseClass()
+{
+}
+
+void
+EndpointBaseClass::generate_ctor()
+{
+    Variable* container = new Variable(RPC_CONTAINER_TYPE, "container");
+    Variable* broker = new Variable(RPC_BROKER_TYPE, "broker");
+	Variable* place = new Variable(PLACE_INFO_TYPE, "placeInfo");
+    Method* ctor = new Method;
+        ctor->modifiers = PUBLIC;
+        ctor->name = class_name_leaf(this->type->Name());
+        ctor->statements = new StatementBlock;
+        ctor->parameters.push_back(container);
+        ctor->parameters.push_back(broker);
+        ctor->parameters.push_back(place);
+    this->elements.push_back(ctor);
+
+    ctor->statements->Add(new MethodCall("super", 3, container, broker, place));
+}
+
+// =================================================
+class ResultDispatcherClass : public Class
+{
+public:
+    ResultDispatcherClass();
+    virtual ~ResultDispatcherClass();
+
+    void AddMethod(int index, const string& name, Method** method, Variable** param);
+
+    bool needed;
+    Variable* methodId;
+    Variable* callback;
+    Method* onResultMethod;
+    Variable* resultParam;
+    SwitchStatement* methodSwitch;
+
+private:
+    void generate_ctor();
+    void generate_onResult();
+};
+
+ResultDispatcherClass::ResultDispatcherClass()
+    :Class(),
+     needed(false)
+{
+    this->modifiers = PRIVATE | FINAL;
+    this->what = Class::CLASS;
+    this->type = new Type("_ResultDispatcher", Type::GENERATED, false, false, false);
+    this->interfaces.push_back(RPC_RESULT_HANDLER_TYPE);
+
+    // methodId
+    this->methodId = new Variable(INT_TYPE, "methodId");
+    this->elements.push_back(new Field(PRIVATE, this->methodId));
+    this->callback = new Variable(OBJECT_TYPE, "callback");
+    this->elements.push_back(new Field(PRIVATE, this->callback));
+
+    // methods
+    generate_ctor();
+    generate_onResult();
+}
+
+ResultDispatcherClass::~ResultDispatcherClass()
+{
+}
+
+void
+ResultDispatcherClass::generate_ctor()
+{
+    Variable* methodIdParam = new Variable(INT_TYPE, "methId");
+    Variable* callbackParam = new Variable(OBJECT_TYPE, "cbObj");
+    Method* ctor = new Method;
+        ctor->modifiers = PUBLIC;
+        ctor->name = class_name_leaf(this->type->Name());
+        ctor->statements = new StatementBlock;
+        ctor->parameters.push_back(methodIdParam);
+        ctor->parameters.push_back(callbackParam);
+    this->elements.push_back(ctor);
+
+    ctor->statements->Add(new Assignment(this->methodId, methodIdParam));
+    ctor->statements->Add(new Assignment(this->callback, callbackParam));
+}
+
+void
+ResultDispatcherClass::generate_onResult()
+{
+    this->onResultMethod = new Method;
+        this->onResultMethod->modifiers = PUBLIC;
+        this->onResultMethod->returnType = VOID_TYPE;
+        this->onResultMethod->returnTypeDimension = 0;
+        this->onResultMethod->name = "onResult";
+        this->onResultMethod->statements = new StatementBlock;
+    this->elements.push_back(this->onResultMethod);
+
+    this->resultParam = new Variable(BYTE_TYPE, "result", 1);
+    this->onResultMethod->parameters.push_back(this->resultParam);
+
+    this->methodSwitch = new SwitchStatement(this->methodId);
+    this->onResultMethod->statements->Add(this->methodSwitch);
+}
+
+void
+ResultDispatcherClass::AddMethod(int index, const string& name, Method** method, Variable** param)
+{
+    Method* m = new Method;
+        m->modifiers = PUBLIC;
+        m->returnType = VOID_TYPE;
+        m->returnTypeDimension = 0;
+        m->name = name;
+        m->statements = new StatementBlock;
+    *param = new Variable(BYTE_TYPE, "result", 1);
+    m->parameters.push_back(*param);
+    this->elements.push_back(m);
+    *method = m;
+
+    Case* c = new Case(format_int(index));
+    c->statements->Add(new MethodCall(new LiteralExpression("this"), name, 1, this->resultParam));
+    c->statements->Add(new Break());
+
+    this->methodSwitch->cases.push_back(c);
+}
+
+// =================================================
+static void
+generate_new_array(Type* t, StatementBlock* addTo, Variable* v, Variable* from)
+{
+    fprintf(stderr, "aidl: implement generate_new_array %s:%d\n", __FILE__, __LINE__);
+    exit(1);
+}
+
+static void
+generate_create_from_data(Type* t, StatementBlock* addTo, const string& key, Variable* v,
+                            Variable* data, Variable** cl)
+{
+    Expression* k = new StringLiteralExpression(key);
+    if (v->dimension == 0) {
+        t->CreateFromRpcData(addTo, k, v, data, cl);
+    }
+    if (v->dimension == 1) {
+        //t->ReadArrayFromRpcData(addTo, v, data, cl);
+        fprintf(stderr, "aidl: implement generate_create_from_data for arrays%s:%d\n",
+                __FILE__, __LINE__);
+    }
+}
+
+static void
+generate_write_to_data(Type* t, StatementBlock* addTo, Expression* k, Variable* v, Variable* data)
+{
+    if (v->dimension == 0) {
+        t->WriteToRpcData(addTo, k, v, data, 0);
+    }
+    if (v->dimension == 1) {
+        //t->WriteArrayToParcel(addTo, v, data);
+        fprintf(stderr, "aidl: implement generate_write_to_data for arrays%s:%d\n",
+                __FILE__, __LINE__);
+    }
+}
+
+// =================================================
+static Type*
+generate_results_method(const method_type* method, RpcProxyClass* proxyClass)
+{
+    arg_type* arg;
+
+    string resultsMethodName = results_method_name(method->name.data);
+    Type* resultsInterfaceType = new Type(results_class_name(method->name.data),
+            Type::GENERATED, false, false, false);
+
+    if (!method->oneway) {
+        Class* resultsClass = new Class;
+            resultsClass->modifiers = STATIC | PUBLIC;
+            resultsClass->what = Class::INTERFACE;
+            resultsClass->type = resultsInterfaceType;
+
+        Method* resultMethod = new Method;
+            resultMethod->comment = gather_comments(method->comments_token->extra);
+            resultMethod->modifiers = PUBLIC;
+            resultMethod->returnType = VOID_TYPE;
+            resultMethod->returnTypeDimension = 0;
+            resultMethod->name = resultsMethodName;
+        if (0 != strcmp("void", method->type.type.data)) {
+            resultMethod->parameters.push_back(new Variable(NAMES.Search(method->type.type.data),
+                        "_result", method->type.dimension));
+        }
+        arg = method->args;
+        while (arg != NULL) {
+            if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
+                resultMethod->parameters.push_back(new Variable(
+                                    NAMES.Search(arg->type.type.data), arg->name.data,
+                                    arg->type.dimension));
+            }
+            arg = arg->next;
+        }
+        resultsClass->elements.push_back(resultMethod);
+
+        if (resultMethod->parameters.size() > 0) {
+            proxyClass->elements.push_back(resultsClass);
+            return resultsInterfaceType;
+        } 
+    }
+    //delete resultsInterfaceType;
+    return NULL;
+}
+
+static void
+generate_proxy_method(const method_type* method, RpcProxyClass* proxyClass,
+        ResultDispatcherClass* resultsDispatcherClass, Type* resultsInterfaceType, int index)
+{
+    arg_type* arg;
+    Method* proxyMethod = new Method;
+        proxyMethod->comment = gather_comments(method->comments_token->extra);
+        proxyMethod->modifiers = PUBLIC;
+        proxyMethod->returnType = VOID_TYPE;
+        proxyMethod->returnTypeDimension = 0;
+        proxyMethod->name = method->name.data;
+        proxyMethod->statements = new StatementBlock;
+    proxyClass->elements.push_back(proxyMethod);
+
+    // The local variables
+    Variable* _data = new Variable(RPC_DATA_TYPE, "_data");
+    proxyMethod->statements->Add(new VariableDeclaration(_data, new NewExpression(RPC_DATA_TYPE)));
+
+    // Add the arguments
+    arg = method->args;
+    while (arg != NULL) {
+        if (convert_direction(arg->direction.data) & IN_PARAMETER) {
+            // Function signature
+            Type* t = NAMES.Search(arg->type.type.data);
+            Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
+            proxyMethod->parameters.push_back(v);
+
+            // Input parameter marshalling
+            generate_write_to_data(t, proxyMethod->statements,
+                    new StringLiteralExpression(arg->name.data), v, _data);
+        }
+        arg = arg->next;
+    }
+
+    // If there is a results interface for this class
+    Expression* resultParameter;
+    if (resultsInterfaceType != NULL) {
+        // Result interface parameter
+        Variable* resultListener = new Variable(resultsInterfaceType, "_result");
+        proxyMethod->parameters.push_back(resultListener);
+
+        // Add the results dispatcher callback
+        resultsDispatcherClass->needed = true;
+        resultParameter = new NewExpression(resultsDispatcherClass->type, 2,
+                new LiteralExpression(format_int(index)), resultListener);
+    } else {
+        resultParameter = NULL_VALUE;
+    }
+
+    // All proxy methods take an error parameter
+    Variable* errorListener = new Variable(RPC_ERROR_LISTENER_TYPE, "_errors");
+    proxyMethod->parameters.push_back(errorListener);
+
+    // Call the broker
+    proxyMethod->statements->Add(new MethodCall(new FieldVariable(THIS_VALUE, "_broker"),
+                "sendRpc", 5,
+                proxyClass->endpoint,
+                new StringLiteralExpression(method->name.data),
+                new MethodCall(_data, "serialize"),
+                resultParameter,
+                errorListener));
+}
+
+static void
+generate_result_dispatcher_method(const method_type* method,
+        ResultDispatcherClass* resultsDispatcherClass, Type* resultsInterfaceType, int index)
+{
+    arg_type* arg;
+    Method* dispatchMethod;
+    Variable* dispatchParam;
+    resultsDispatcherClass->AddMethod(index, method->name.data, &dispatchMethod, &dispatchParam);
+
+    Variable* classLoader = NULL;
+    Variable* resultData = new Variable(RPC_DATA_TYPE, "resultData");
+    dispatchMethod->statements->Add(new VariableDeclaration(resultData,
+                new NewExpression(RPC_DATA_TYPE, 1, dispatchParam)));
+
+    // The callback method itself
+    MethodCall* realCall = new MethodCall(
+            new Cast(resultsInterfaceType, new FieldVariable(THIS_VALUE, "callback")),
+            results_method_name(method->name.data));
+
+    // The return value
+    {
+        Type* t = NAMES.Search(method->type.type.data);
+        if (t != VOID_TYPE) {
+            Variable* rv = new Variable(t, "rv");
+            dispatchMethod->statements->Add(new VariableDeclaration(rv));
+            generate_create_from_data(t, dispatchMethod->statements, "_result", rv,
+                    resultData, &classLoader);
+            realCall->arguments.push_back(rv);
+        }
+    }
+
+    VariableFactory stubArgs("arg");
+    arg = method->args;
+    while (arg != NULL) {
+        if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
+            // Unmarshall the results
+            Type* t = NAMES.Search(arg->type.type.data);
+            Variable* v = stubArgs.Get(t);
+            dispatchMethod->statements->Add(new VariableDeclaration(v));
+
+            generate_create_from_data(t, dispatchMethod->statements, arg->name.data, v,
+                    resultData, &classLoader);
+
+            // Add the argument to the callback
+            realCall->arguments.push_back(v);
+        }
+        arg = arg->next;
+    }
+
+    // Call the callback method
+    IfStatement* ifst = new IfStatement;
+        ifst->expression = new Comparison(new FieldVariable(THIS_VALUE, "callback"), "!=", NULL_VALUE);
+    dispatchMethod->statements->Add(ifst);
+    ifst->statements->Add(realCall);
+}
+
+static void
+generate_regular_method(const method_type* method, RpcProxyClass* proxyClass,
+        EndpointBaseClass* serviceBaseClass, ResultDispatcherClass* resultsDispatcherClass,
+        int index)
+{
+    arg_type* arg;
+
+    // == the callback interface for results ================================
+    // the service base class
+    Type* resultsInterfaceType = generate_results_method(method, proxyClass);
+    
+    // == the method in the proxy class =====================================
+    generate_proxy_method(method, proxyClass, resultsDispatcherClass, resultsInterfaceType, index);
+
+    // == the method in the result dispatcher class =========================
+    if (resultsInterfaceType != NULL) {
+        generate_result_dispatcher_method(method, resultsDispatcherClass, resultsInterfaceType,
+                index);
+    }
+
+    // == The abstract method that the service developers implement ==========
+    Method* decl = new Method;
+        decl->comment = gather_comments(method->comments_token->extra);
+        decl->modifiers = PUBLIC | ABSTRACT;
+        decl->returnType = NAMES.Search(method->type.type.data);
+        decl->returnTypeDimension = method->type.dimension;
+        decl->name = method->name.data;
+    arg = method->args;
+    while (arg != NULL) {
+        decl->parameters.push_back(new Variable(
+                            NAMES.Search(arg->type.type.data), arg->name.data,
+                            arg->type.dimension));
+        arg = arg->next;
+    }
+
+    // Add the default RpcContext param to all methods
+    decl->parameters.push_back(new Variable(RPC_CONTEXT_TYPE, "context", 0));
+	
+    serviceBaseClass->elements.push_back(decl);
+    
+
+    // == the dispatch method in the service base class ======================
+    serviceBaseClass->AddMethod(method);
+}
+
+static void
+generate_event_method(const method_type* method, RpcProxyClass* proxyClass,
+        EndpointBaseClass* serviceBaseClass, ListenerClass* listenerClass,
+        EventListenerClass* presenterClass, int index)
+{
+    arg_type* arg;
+    listenerClass->needed = true;
+
+    // == the push method in the service base class =========================
+    Method* push = new Method;
+        push->modifiers = PUBLIC;
+        push->name = push_method_name(method->name.data);
+        push->statements = new StatementBlock;
+        push->returnType = VOID_TYPE;
+    serviceBaseClass->elements.push_back(push);
+
+    // The local variables
+    Variable* _data = new Variable(RPC_DATA_TYPE, "_data");
+    push->statements->Add(new VariableDeclaration(_data, new NewExpression(RPC_DATA_TYPE)));
+
+    // Add the arguments
+    arg = method->args;
+    while (arg != NULL) {
+        // Function signature
+        Type* t = NAMES.Search(arg->type.type.data);
+        Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
+        push->parameters.push_back(v);
+
+        // Input parameter marshalling
+        generate_write_to_data(t, push->statements,
+                new StringLiteralExpression(arg->name.data), v, _data);
+
+        arg = arg->next;
+    }
+
+    // Send the notifications
+    push->statements->Add(new MethodCall("pushEvent", 2,
+                new StringLiteralExpression(method->name.data),
+                new MethodCall(_data, "serialize")));
+
+    // == the event callback dispatcher method  ====================================
+    presenterClass->AddMethod(method);
+
+    // == the event method in the listener base class =====================
+    Method* event = new Method;
+        event->modifiers = PUBLIC;
+        event->name = method->name.data;
+        event->statements = new StatementBlock;
+        event->returnType = VOID_TYPE;
+    listenerClass->elements.push_back(event);
+    arg = method->args;
+    while (arg != NULL) {
+        event->parameters.push_back(new Variable(
+                            NAMES.Search(arg->type.type.data), arg->name.data,
+                            arg->type.dimension));
+        arg = arg->next;
+    }
+
+    // Add a final parameter: RpcContext. Contains data about
+    // incoming request (e.g., certificate)
+    event->parameters.push_back(new Variable(RPC_CONTEXT_TYPE, "context", 0));
+}
+
+static void
+generate_listener_methods(RpcProxyClass* proxyClass, Type* presenterType, Type* listenerType)
+{
+    // AndroidAtHomePresenter _presenter;
+    // void startListening(Listener listener) {
+    //     stopListening();
+    //     _presenter = new Presenter(_broker, listener);
+    //     _presenter.startListening(_endpoint);
+    // }
+    // void stopListening() {
+    //     if (_presenter != null) {
+    //         _presenter.stopListening();
+    //     }
+    // }
+
+    Variable* _presenter = new Variable(presenterType, "_presenter");
+    proxyClass->elements.push_back(new Field(PRIVATE, _presenter));
+
+    Variable* listener = new Variable(listenerType, "listener");
+
+    Method* startListeningMethod = new Method;
+        startListeningMethod->modifiers = PUBLIC;
+        startListeningMethod->returnType = VOID_TYPE;
+        startListeningMethod->name = "startListening";
+        startListeningMethod->statements = new StatementBlock;
+        startListeningMethod->parameters.push_back(listener);
+    proxyClass->elements.push_back(startListeningMethod);
+
+    startListeningMethod->statements->Add(new MethodCall(THIS_VALUE, "stopListening"));
+    startListeningMethod->statements->Add(new Assignment(_presenter,
+                new NewExpression(presenterType, 2, proxyClass->broker, listener)));
+    startListeningMethod->statements->Add(new MethodCall(_presenter,
+                "startListening", 1, proxyClass->endpoint));
+
+    Method* stopListeningMethod = new Method;
+        stopListeningMethod->modifiers = PUBLIC;
+        stopListeningMethod->returnType = VOID_TYPE;
+        stopListeningMethod->name = "stopListening";
+        stopListeningMethod->statements = new StatementBlock;
+    proxyClass->elements.push_back(stopListeningMethod);
+
+    IfStatement* ifst = new IfStatement;
+        ifst->expression = new Comparison(_presenter, "!=", NULL_VALUE);
+    stopListeningMethod->statements->Add(ifst);
+
+    ifst->statements->Add(new MethodCall(_presenter, "stopListening"));
+    ifst->statements->Add(new Assignment(_presenter, NULL_VALUE));
+}
+
+Class*
+generate_rpc_interface_class(const interface_type* iface)
+{
+    // the proxy class
+    InterfaceType* interfaceType = static_cast<InterfaceType*>(
+        NAMES.Find(iface->package, iface->name.data));
+    RpcProxyClass* proxy = new RpcProxyClass(iface, interfaceType);
+
+    // the listener class
+    ListenerClass* listener = new ListenerClass(iface);
+
+    // the presenter class
+    EventListenerClass* presenter = new EventListenerClass(iface, listener->type);
+
+    // the service base class
+    EndpointBaseClass* base = new EndpointBaseClass(iface);
+    proxy->elements.push_back(base);
+
+    // the result dispatcher
+    ResultDispatcherClass* results = new ResultDispatcherClass();
+
+    // all the declared methods of the proxy
+    int index = 0;
+    interface_item_type* item = iface->interface_items;
+    while (item != NULL) {
+        if (item->item_type == METHOD_TYPE) {
+            if (NAMES.Search(((method_type*)item)->type.type.data) == EVENT_FAKE_TYPE) {
+                generate_event_method((method_type*)item, proxy, base, listener, presenter, index);
+            } else {
+                generate_regular_method((method_type*)item, proxy, base, results, index);
+            }
+        }
+        item = item->next;
+        index++;
+    }
+    presenter->DoneWithMethods();
+    base->DoneWithMethods();
+
+    // only add this if there are methods with results / out parameters
+    if (results->needed) {
+        proxy->elements.push_back(results);
+    }
+    if (listener->needed) {
+        proxy->elements.push_back(listener);
+        proxy->elements.push_back(presenter);
+        generate_listener_methods(proxy, presenter->type, listener->type);
+    }
+
+    return proxy;
+}
diff --git a/options.cpp b/options.cpp
new file mode 100644
index 0000000..7b2daeb
--- /dev/null
+++ b/options.cpp
@@ -0,0 +1,154 @@
+
+#include "options.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static int
+usage()
+{
+    fprintf(stderr,
+            "usage: aidl OPTIONS INPUT [OUTPUT]\n"
+            "       aidl --preprocess OUTPUT INPUT...\n"
+            "\n"
+            "OPTIONS:\n"
+            "   -I<DIR>    search path for import statements.\n"
+            "   -d<FILE>   generate dependency file.\n"
+            "   -a         generate dependency file next to the output file with the name based on the input file.\n"
+            "   -p<FILE>   file created by --preprocess to import.\n"
+            "   -o<FOLDER> base output folder for generated files.\n"
+            "   -b         fail when trying to compile a parcelable.\n"
+            "\n"
+            "INPUT:\n"
+            "   An aidl interface file.\n"
+            "\n"
+            "OUTPUT:\n"
+            "   The generated interface files.\n"
+            "   If omitted and the -o option is not used, the input filename is used, with the .aidl extension changed to a .java extension.\n"
+            "   If the -o option is used, the generated files will be placed in the base output folder, under their package folder\n"
+           );
+    return 1;
+}
+
+int
+parse_options(int argc, const char* const* argv, Options *options)
+{
+    int i = 1;
+
+    if (argc >= 2 && 0 == strcmp(argv[1], "--preprocess")) {
+        if (argc < 4) {
+            return usage();
+        }
+        options->outputFileName = argv[2];
+        for (int i=3; i<argc; i++) {
+            options->filesToPreprocess.push_back(argv[i]);
+        }
+        options->task = PREPROCESS_AIDL;
+        return 0;
+    }
+
+    options->task = COMPILE_AIDL;
+    options->failOnParcelable = false;
+    options->autoDepFile = false;
+
+    // OPTIONS
+    while (i < argc) {
+        const char* s = argv[i];
+        int len = strlen(s);
+        if (s[0] == '-') {
+            if (len > 1) {
+                // -I<system-import-path>
+                if (s[1] == 'I') {
+                    if (len > 2) {
+                        options->importPaths.push_back(s+2);
+                    } else {
+                        fprintf(stderr, "-I option (%d) requires a path.\n", i);
+                        return usage();
+                    }
+                }
+                else if (s[1] == 'd') {
+                    if (len > 2) {
+                        options->depFileName = s+2;
+                    } else {
+                        fprintf(stderr, "-d option (%d) requires a file.\n", i);
+                        return usage();
+                    }
+                }
+                else if (s[1] == 'a') {
+                    options->autoDepFile = true;
+                }
+                else if (s[1] == 'p') {
+                    if (len > 2) {
+                        options->preprocessedFiles.push_back(s+2);
+                    } else {
+                        fprintf(stderr, "-p option (%d) requires a file.\n", i);
+                        return usage();
+                    }
+                }
+                else if (s[1] == 'o') {
+                    if (len > 2) {
+                        options->outputBaseFolder = s+2;
+                    } else {
+                        fprintf(stderr, "-o option (%d) requires a path.\n", i);
+                        return usage();
+                    }
+                }
+                else if (len == 2 && s[1] == 'b') {
+                    options->failOnParcelable = true;
+                }
+                else {
+                    // s[1] is not known
+                    fprintf(stderr, "unknown option (%d): %s\n", i, s);
+                    return usage();
+                }
+            } else {
+                // len <= 1
+                fprintf(stderr, "unknown option (%d): %s\n", i, s);
+                return usage();
+            }
+        } else {
+            // s[0] != '-'
+            break;
+        }
+        i++;
+    }
+
+    // INPUT
+    if (i < argc) {
+        options->inputFileName = argv[i];
+        i++;
+    } else {
+        fprintf(stderr, "INPUT required\n");
+        return usage();
+    }
+
+    // OUTPUT
+    if (i < argc) {
+        options->outputFileName = argv[i];
+        i++;
+    } else if (options->outputBaseFolder.length() == 0) {
+        // copy input into output and change the extension from .aidl to .java
+        options->outputFileName = options->inputFileName;
+        string::size_type pos = options->outputFileName.size()-5;
+        if (options->outputFileName.compare(pos, 5, ".aidl") == 0) {  // 5 = strlen(".aidl")
+            options->outputFileName.replace(pos, 5, ".java"); // 5 = strlen(".aidl")
+        } else {
+            fprintf(stderr, "INPUT is not an .aidl file.\n");
+            return usage();
+        }
+     }
+
+    // anything remaining?
+    if (i != argc) {
+        fprintf(stderr, "unknown option%s:", (i==argc-1?(const char*)"":(const char*)"s"));
+        for (; i<argc-1; i++) {
+            fprintf(stderr, " %s", argv[i]);
+        }
+        fprintf(stderr, "\n");
+        return usage();
+    }
+
+    return 0;
+}
+
diff --git a/options.h b/options.h
new file mode 100644
index 0000000..387e37d
--- /dev/null
+++ b/options.h
@@ -0,0 +1,36 @@
+#ifndef DEVICE_TOOLS_AIDL_H
+#define DEVICE_TOOLS_AIDL_H
+
+#include <string.h>
+#include <string>
+#include <vector>
+
+using namespace std;
+
+enum {
+    COMPILE_AIDL,
+    PREPROCESS_AIDL
+};
+
+// This struct is the parsed version of the command line options
+struct Options
+{
+    int task;
+    bool failOnParcelable;
+    vector<string> importPaths;
+    vector<string> preprocessedFiles;
+    string inputFileName;
+    string outputFileName;
+    string outputBaseFolder;
+    string depFileName;
+    bool autoDepFile;
+
+    vector<string> filesToPreprocess;
+};
+
+// takes the inputs from the command line and fills in the Options struct
+// Returns 0 on success, and nonzero on failure.
+// It also prints the usage statement on failure.
+int parse_options(int argc, const char* const* argv, Options *options);
+
+#endif // DEVICE_TOOLS_AIDL_H
diff --git a/options_test.cpp b/options_test.cpp
new file mode 100644
index 0000000..bd106ce
--- /dev/null
+++ b/options_test.cpp
@@ -0,0 +1,291 @@
+#include <iostream>
+#include "options.h"
+
+const bool VERBOSE = false;
+
+using namespace std;
+
+struct Answer {
+    const char* argv[8];
+    int result;
+    const char* systemSearchPath[8];
+    const char* localSearchPath[8];
+    const char* inputFileName;
+    language_t nativeLanguage;
+    const char* outputH;
+    const char* outputCPP;
+    const char* outputJava;
+};
+
+bool
+match_arrays(const char* const*expected, const vector<string> &got)
+{
+    int count = 0;
+    while (expected[count] != NULL) {
+        count++;
+    }
+    if (got.size() != count) {
+        return false;
+    }
+    for (int i=0; i<count; i++) {
+        if (got[i] != expected[i]) {
+            return false;
+        }
+    }
+    return true;
+}
+
+void
+print_array(const char* prefix, const char* const*expected)
+{
+    while (*expected) {
+        cout << prefix << *expected << endl;
+        expected++;
+    }
+}
+
+void
+print_array(const char* prefix, const vector<string> &got)
+{
+    size_t count = got.size();
+    for (size_t i=0; i<count; i++) {
+        cout << prefix << got[i] << endl;
+    }
+}
+
+static int
+test(const Answer& answer)
+{
+    int argc = 0;
+    while (answer.argv[argc]) {
+        argc++;
+    }
+
+    int err = 0;
+
+    Options options;
+    int result = parse_options(argc, answer.argv, &options);
+
+    // result
+    if (((bool)result) != ((bool)answer.result)) {
+        cout << "mismatch: result: got " << result << " expected " <<
+            answer.result << endl;
+        err = 1;
+    }
+
+    if (result != 0) {
+        // if it failed, everything is invalid
+        return err;
+    }
+
+    // systemSearchPath
+    if (!match_arrays(answer.systemSearchPath, options.systemSearchPath)) {
+        cout << "mismatch: systemSearchPath: got" << endl;
+        print_array("        ", options.systemSearchPath);
+        cout << "    expected" << endl;
+        print_array("        ", answer.systemSearchPath);
+        err = 1;
+    }
+
+    // localSearchPath
+    if (!match_arrays(answer.localSearchPath, options.localSearchPath)) {
+        cout << "mismatch: localSearchPath: got" << endl;
+        print_array("        ", options.localSearchPath);
+        cout << "    expected" << endl;
+        print_array("        ", answer.localSearchPath);
+        err = 1;
+    }
+
+    // inputFileName
+    if (answer.inputFileName != options.inputFileName) {
+        cout << "mismatch: inputFileName: got " << options.inputFileName
+            << " expected " << answer.inputFileName << endl;
+        err = 1;
+    }
+
+    // nativeLanguage
+    if (answer.nativeLanguage != options.nativeLanguage) {
+        cout << "mismatch: nativeLanguage: got " << options.nativeLanguage
+            << " expected " << answer.nativeLanguage << endl;
+        err = 1;
+    }
+
+    // outputH
+    if (answer.outputH != options.outputH) {
+        cout << "mismatch: outputH: got " << options.outputH
+            << " expected " << answer.outputH << endl;
+        err = 1;
+    }
+
+    // outputCPP
+    if (answer.outputCPP != options.outputCPP) {
+        cout << "mismatch: outputCPP: got " << options.outputCPP
+            << " expected " << answer.outputCPP << endl;
+        err = 1;
+    }
+
+    // outputJava
+    if (answer.outputJava != options.outputJava) {
+        cout << "mismatch: outputJava: got " << options.outputJava
+            << " expected " << answer.outputJava << endl;
+        err = 1;
+    }
+
+    return err;
+}
+
+const Answer g_tests[] = {
+
+    {
+        /* argv */              { "test", "-i/moof", "-I/blah", "-Ibleh", "-imoo", "inputFileName.aidl_cpp", NULL, NULL },
+        /* result */            0,
+        /* systemSearchPath */  { "/blah", "bleh", NULL, NULL, NULL, NULL, NULL, NULL },
+        /* localSearchPath */   { "/moof", "moo", NULL, NULL, NULL, NULL, NULL, NULL },
+        /* inputFileName */     "inputFileName.aidl_cpp",
+        /* nativeLanguage */    CPP,
+        /* outputH */           "",
+        /* outputCPP */         "",
+        /* outputJava */        ""
+    },
+
+    {
+        /* argv */              { "test", "inputFileName.aidl_cpp", "-oh", "outputH", NULL, NULL, NULL, NULL },
+        /* result */            0,
+        /* systemSearchPath */  { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
+        /* localSearchPath */   { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
+        /* inputFileName */     "inputFileName.aidl_cpp",
+        /* nativeLanguage */    CPP,
+        /* outputH */           "outputH",
+        /* outputCPP */         "",
+        /* outputJava */        ""
+    },
+
+    {
+        /* argv */              { "test", "inputFileName.aidl_cpp", "-ocpp", "outputCPP", NULL, NULL, NULL, NULL },
+        /* result */            0,
+        /* systemSearchPath */  { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
+        /* localSearchPath */   { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
+        /* inputFileName */     "inputFileName.aidl_cpp",
+        /* nativeLanguage */    CPP,
+        /* outputH */           "",
+        /* outputCPP */         "outputCPP",
+        /* outputJava */        ""
+    },
+
+    {
+        /* argv */              { "test", "inputFileName.aidl_cpp", "-ojava", "outputJava", NULL, NULL, NULL, NULL },
+        /* result */            0,
+        /* systemSearchPath */  { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
+        /* localSearchPath */   { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
+        /* inputFileName */     "inputFileName.aidl_cpp",
+        /* nativeLanguage */    CPP,
+        /* outputH */           "",
+        /* outputCPP */         "",
+        /* outputJava */        "outputJava"
+    },
+
+    {
+        /* argv */              { "test", "inputFileName.aidl_cpp", "-oh", "outputH", "-ocpp", "outputCPP", "-ojava", "outputJava" },
+        /* result */            0,
+        /* systemSearchPath */  { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
+        /* localSearchPath */   { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
+        /* inputFileName */     "inputFileName.aidl_cpp",
+        /* nativeLanguage */    CPP,
+        /* outputH */           "outputH",
+        /* outputCPP */         "outputCPP",
+        /* outputJava */        "outputJava"
+    },
+
+    {
+        /* argv */              { "test", "inputFileName.aidl_cpp", "-oh", "outputH", "-oh", "outputH1", NULL, NULL },
+        /* result */            1,
+        /* systemSearchPath */  { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
+        /* localSearchPath */   { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
+        /* inputFileName */     "",
+        /* nativeLanguage */    CPP,
+        /* outputH */           "",
+        /* outputCPP */         "",
+        /* outputJava */        ""
+    },
+
+    {
+        /* argv */              { "test", "inputFileName.aidl_cpp", "-ocpp", "outputCPP", "-ocpp", "outputCPP1", NULL, NULL },
+        /* result */            1,
+        /* systemSearchPath */  { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
+        /* localSearchPath */   { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
+        /* inputFileName */     "",
+        /* nativeLanguage */    CPP,
+        /* outputH */           "",
+        /* outputCPP */         "",
+        /* outputJava */        ""
+    },
+
+    {
+        /* argv */              { "test", "inputFileName.aidl_cpp", "-ojava", "outputJava", "-ojava", "outputJava1", NULL, NULL },
+        /* result */            1,
+        /* systemSearchPath */  { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
+        /* localSearchPath */   { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
+        /* inputFileName */     "",
+        /* nativeLanguage */    CPP,
+        /* outputH */           "",
+        /* outputCPP */         "",
+        /* outputJava */        ""
+    },
+
+};
+
+int
+main(int argc, const char** argv)
+{
+    const int count = sizeof(g_tests)/sizeof(g_tests[0]);
+    int matches[count];
+
+    int result = 0;
+    for (int i=0; i<count; i++) {
+        if (VERBOSE) {
+            cout << endl;
+            cout << "---------------------------------------------" << endl;
+            const char* const* p = g_tests[i].argv;
+            while (*p) {
+                cout << " " << *p;
+                p++;
+            }
+            cout << endl;
+            cout << "---------------------------------------------" << endl;
+        }
+        matches[i] = test(g_tests[i]);
+        if (VERBOSE) {
+            if (0 == matches[i]) {
+                cout << "passed" << endl;
+            } else {
+                cout << "failed" << endl;
+            }
+            result |= matches[i];
+        }
+    }
+
+    cout << endl;
+    cout << "=============================================" << endl;
+    cout << "options_test summary" << endl;
+    cout << "=============================================" << endl;
+
+    if (!result) {
+        cout << "passed" << endl;
+    } else {
+        cout << "failed the following tests:" << endl;
+        for (int i=0; i<count; i++) {
+            if (matches[i]) {
+                cout << "   ";
+                const char* const* p = g_tests[i].argv;
+                while (*p) {
+                    cout << " " << *p;
+                    p++;
+                }
+                cout << endl;
+            }
+        }
+    }
+
+    return result;
+}
+
diff --git a/search_path.cpp b/search_path.cpp
new file mode 100644
index 0000000..ffb6cb2
--- /dev/null
+++ b/search_path.cpp
@@ -0,0 +1,57 @@
+#include <unistd.h>
+#include "search_path.h"
+#include "options.h"
+#include <string.h>
+
+#ifdef HAVE_MS_C_RUNTIME
+#include <io.h>
+#endif
+
+static vector<string> g_importPaths;
+
+void
+set_import_paths(const vector<string>& importPaths)
+{
+    g_importPaths = importPaths;
+}
+
+char*
+find_import_file(const char* given)
+{
+    string expected = given;
+
+    int N = expected.length();
+    for (int i=0; i<N; i++) {
+        char c = expected[i];
+        if (c == '.') {
+            expected[i] = OS_PATH_SEPARATOR;
+        }
+    }
+    expected += ".aidl";
+
+    vector<string>& paths = g_importPaths;
+    for (vector<string>::iterator it=paths.begin(); it!=paths.end(); it++) {
+        string f = *it;
+        if (f.size() == 0) {
+            f = ".";
+            f += OS_PATH_SEPARATOR;
+        }
+        else if (f[f.size()-1] != OS_PATH_SEPARATOR) {
+            f += OS_PATH_SEPARATOR;
+        }
+        f.append(expected);
+
+#ifdef HAVE_MS_C_RUNTIME
+        /* check that the file exists and is not write-only */
+        if (0 == _access(f.c_str(), 0) &&  /* mode 0=exist */
+            0 == _access(f.c_str(), 4) ) { /* mode 4=readable */
+#else
+        if (0 == access(f.c_str(), R_OK)) {
+#endif        
+            return strdup(f.c_str());
+        }
+    }
+
+    return NULL;
+}
+
diff --git a/search_path.h b/search_path.h
new file mode 100644
index 0000000..2bf94b1
--- /dev/null
+++ b/search_path.h
@@ -0,0 +1,23 @@
+#ifndef DEVICE_TOOLS_AIDL_SEARCH_PATH_H
+#define DEVICE_TOOLS_AIDL_SEARCH_PATH_H
+
+#include <stdio.h>
+
+#if __cplusplus
+#include <vector>
+#include <string>
+using namespace std;
+extern "C" {
+#endif
+
+// returns a FILE* and the char* for the file that it found
+// given is the class name we're looking for
+char* find_import_file(const char* given);
+
+#if __cplusplus
+}; // extern "C"
+void set_import_paths(const vector<string>& importPaths);
+#endif
+
+#endif // DEVICE_TOOLS_AIDL_SEARCH_PATH_H
+