auto import from //depot/cupcake/@135843
diff --git a/tools/aidl/AST.cpp b/tools/aidl/AST.cpp
new file mode 100755
index 0000000..91802a9
--- /dev/null
+++ b/tools/aidl/AST.cpp
@@ -0,0 +1,867 @@
+#include "AST.h"
+#include "Type.h"
+
+void
+WriteModifiers(FILE* to, int mod, int mask)
+{
+    int m = mod & mask;
+
+    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);
+    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());
+}
+
+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(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()
+{
+}
+
+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");
+}
+
+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 | FINAL);
+
+    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());
+    }
+
+    // gather the types for the import statements
+    set<Type*> types;
+    N = this->classes.size();
+    for (i=0; i<N; i++) {
+        Class* c = this->classes[i];
+        c->GatherTypes(&types);
+    }
+    
+    set<Type*>::iterator it;
+    for (it=types.begin(); it!=types.end(); it++) {
+        Type* t = *it;
+        string pkg = t->Package();
+        if (pkg.length() != 0 && pkg != this->package) {
+            fprintf(to, "import %s;\n", t->ImportType().c_str());
+        }
+    }
+
+    N = this->classes.size();
+    for (i=0; i<N; i++) {
+        Class* c = this->classes[i];
+        c->Write(to);
+    }
+}
+
diff --git a/tools/aidl/AST.h b/tools/aidl/AST.h
new file mode 100755
index 0000000..1dedd04
--- /dev/null
+++ b/tools/aidl/AST.h
@@ -0,0 +1,346 @@
+#ifndef AIDL_AST_H
+#define AIDL_AST_H
+
+#include <string>
+#include <vector>
+#include <set>
+#include <stdarg.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,
+
+    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);
+};
+
+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
+{
+    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(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);
+    virtual ~NewExpression();
+    virtual void Write(FILE* to);
+};
+
+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 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/tools/aidl/Android.mk b/tools/aidl/Android.mk
new file mode 100644
index 0000000..944aeb6
--- /dev/null
+++ b/tools/aidl/Android.mk
@@ -0,0 +1,24 @@
+# Copyright 2007 The Android Open Source Project
+#
+# Copies files into the directory structure described by a manifest
+
+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
+
+LOCAL_CFLAGS := -g
+LOCAL_MODULE := aidl
+
+include $(BUILD_HOST_EXECUTABLE)
+
+
diff --git a/tools/aidl/Type.cpp b/tools/aidl/Type.cpp
new file mode 100755
index 0000000..a44072d
--- /dev/null
+++ b/tools/aidl/Type.cpp
@@ -0,0 +1,1228 @@
+#include "Type.h"
+
+Namespace NAMES;
+
+Type* VOID_TYPE;
+Type* BOOLEAN_TYPE;
+Type* BYTE_TYPE;
+Type* CHAR_TYPE;
+Type* INT_TYPE;
+Type* LONG_TYPE;
+Type* FLOAT_TYPE;
+Type* DOUBLE_TYPE;
+Type* STRING_TYPE;
+Type* CHAR_SEQUENCE_TYPE;
+Type* TEXT_UTILS_TYPE;
+Type* REMOTE_EXCEPTION_TYPE;
+Type* RUNTIME_EXCEPTION_TYPE;
+Type* IBINDER_TYPE;
+Type* IINTERFACE_TYPE;
+Type* BINDER_NATIVE_TYPE;
+Type* BINDER_PROXY_TYPE;
+Type* PARCEL_TYPE;
+Type* PARCELABLE_INTERFACE_TYPE;
+Type* MAP_TYPE;
+Type* LIST_TYPE;
+Type* CLASSLOADER_TYPE;
+
+Expression* NULL_VALUE;
+Expression* THIS_VALUE;
+Expression* SUPER_VALUE;
+Expression* TRUE_VALUE;
+Expression* FALSE_VALUE;
+
+void
+register_base_types()
+{
+    VOID_TYPE = new BasicType("void", "XXX", "XXX", "XXX", "XXX", "XXX");
+    NAMES.Add(VOID_TYPE);
+
+    BOOLEAN_TYPE = new BooleanType();
+    NAMES.Add(BOOLEAN_TYPE);
+
+    BYTE_TYPE = new BasicType("byte", "writeByte", "readByte",
+                "writeByteArray", "createByteArray", "readByteArray");
+    NAMES.Add(BYTE_TYPE);
+
+    CHAR_TYPE = new CharType();
+    NAMES.Add(CHAR_TYPE);
+
+    INT_TYPE = new BasicType("int", "writeInt", "readInt",
+                "writeIntArray", "createIntArray", "readIntArray");
+    NAMES.Add(INT_TYPE);
+
+    LONG_TYPE = new BasicType("long", "writeLong", "readLong",
+                "writeLongArray", "createLongArray", "readLongArray");
+    NAMES.Add(LONG_TYPE);
+
+    FLOAT_TYPE = new BasicType("float", "writeFloat", "readFloat",
+                "writeFloatArray", "createFloatArray", "readFloatArray");
+    NAMES.Add(FLOAT_TYPE);
+
+    DOUBLE_TYPE = new BasicType("double", "writeDouble", "readDouble",
+                "writeDoubleArray", "createDoubleArray", "readDoubleArray");
+    NAMES.Add(DOUBLE_TYPE);
+
+    STRING_TYPE = new StringType();
+    NAMES.Add(STRING_TYPE);
+
+    CHAR_SEQUENCE_TYPE = new CharSequenceType();
+    NAMES.Add(CHAR_SEQUENCE_TYPE);
+
+    MAP_TYPE = new MapType();
+    NAMES.Add(MAP_TYPE);
+
+    LIST_TYPE = new ListType();
+    NAMES.Add(LIST_TYPE);
+
+    TEXT_UTILS_TYPE = new Type("android.text", "TextUtils",
+                                    Type::BUILT_IN, false, false);
+    NAMES.Add(TEXT_UTILS_TYPE);
+
+    REMOTE_EXCEPTION_TYPE = new RemoteExceptionType();
+    NAMES.Add(REMOTE_EXCEPTION_TYPE);
+
+    RUNTIME_EXCEPTION_TYPE = new RuntimeExceptionType();
+    NAMES.Add(RUNTIME_EXCEPTION_TYPE);
+
+    IBINDER_TYPE = new IBinderType();
+    NAMES.Add(IBINDER_TYPE);
+
+    IINTERFACE_TYPE = new IInterfaceType();
+    NAMES.Add(IINTERFACE_TYPE);
+
+    BINDER_NATIVE_TYPE = new BinderType();
+    NAMES.Add(BINDER_NATIVE_TYPE);
+
+    BINDER_PROXY_TYPE = new BinderProxyType();
+    NAMES.Add(BINDER_PROXY_TYPE);
+
+    PARCEL_TYPE = new ParcelType();
+    NAMES.Add(PARCEL_TYPE);
+
+    PARCELABLE_INTERFACE_TYPE = new ParcelableInterfaceType();
+    NAMES.Add(PARCELABLE_INTERFACE_TYPE);
+
+    CLASSLOADER_TYPE = new ClassLoaderType();
+    NAMES.Add(CLASSLOADER_TYPE);
+
+    NULL_VALUE = new LiteralExpression("null");
+    THIS_VALUE = new LiteralExpression("this");
+    SUPER_VALUE = new LiteralExpression("super");
+    TRUE_VALUE = new LiteralExpression("true");
+    FALSE_VALUE = new LiteralExpression("false");
+
+    NAMES.AddGenericType("java.util", "List", 1);
+    NAMES.AddGenericType("java.util", "Map", 2);
+}
+
+static Type*
+make_generic_type(const string& package, const string& name,
+                    const vector<Type*>& args)
+{
+    if (package == "java.util" && name == "List") {
+        return new GenericListType("java.util", "List", args);
+    }
+    return NULL;
+    //return new GenericType(package, name, args);
+}
+
+// ================================================================
+
+Type::Type(const string& name, int kind, bool canWriteToParcel, bool canBeOut)
+    :m_package(),
+     m_name(name),
+     m_declFile(""),
+     m_declLine(-1),
+     m_kind(kind),
+     m_canWriteToParcel(canWriteToParcel),
+     m_canBeOut(canBeOut)
+{
+    m_qualifiedName = name;
+}
+
+Type::Type(const string& package, const string& name,
+            int kind, bool canWriteToParcel, bool canBeOut,
+            const string& declFile, int declLine)
+    :m_package(package),
+     m_name(name),
+     m_declFile(declFile),
+     m_declLine(declLine),
+     m_kind(kind),
+     m_canWriteToParcel(canWriteToParcel),
+     m_canBeOut(canBeOut)
+{
+    if (package.length() > 0) {
+        m_qualifiedName = package;
+        m_qualifiedName += '.';
+    }
+    m_qualifiedName += name;
+}
+
+Type::~Type()
+{
+}
+
+bool
+Type::CanBeArray() const
+{
+    return false;
+}
+
+string
+Type::ImportType() const
+{
+    return m_qualifiedName;
+}
+
+string
+Type::CreatorName() const
+{
+    return "";
+}
+
+string
+Type::InstantiableName() const
+{
+    return QualifiedName();
+}
+
+
+void
+Type::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%sn",
+            __FILE__, __LINE__, m_qualifiedName.c_str());
+    addTo->Add(new LiteralExpression("/* WriteToParcel error "
+                + m_qualifiedName + " */"));
+}
+
+void
+Type::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n",
+            __FILE__, __LINE__, m_qualifiedName.c_str());
+    addTo->Add(new LiteralExpression("/* CreateFromParcel error "
+                + m_qualifiedName + " */"));
+}
+
+void
+Type::ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n",
+            __FILE__, __LINE__, m_qualifiedName.c_str());
+    addTo->Add(new LiteralExpression("/* ReadFromParcel error "
+                + m_qualifiedName + " */"));
+}
+
+void
+Type::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n",
+            __FILE__, __LINE__, m_qualifiedName.c_str());
+    addTo->Add(new LiteralExpression("/* WriteArrayToParcel error "
+                + m_qualifiedName + " */"));
+}
+
+void
+Type::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
+                            Variable* parcel)
+{
+    fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n",
+            __FILE__, __LINE__, m_qualifiedName.c_str());
+    addTo->Add(new LiteralExpression("/* CreateArrayFromParcel error "
+                + m_qualifiedName + " */"));
+}
+
+void
+Type::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n",
+            __FILE__, __LINE__, m_qualifiedName.c_str());
+    addTo->Add(new LiteralExpression("/* ReadArrayFromParcel error "
+                + m_qualifiedName + " */"));
+}
+
+void
+Type::SetQualifiedName(const string& qualified)
+{
+    m_qualifiedName = qualified;
+}
+
+Expression*
+Type::BuildWriteToParcelFlags(int flags)
+{
+    if (flags == 0) {
+        return new LiteralExpression("0");
+    }
+    if ((flags&PARCELABLE_WRITE_RETURN_VALUE) != 0) {
+        return new FieldVariable(PARCELABLE_INTERFACE_TYPE,
+                "PARCELABLE_WRITE_RETURN_VALUE");
+    }
+    return new LiteralExpression("0");
+}
+
+// ================================================================
+
+BasicType::BasicType(const string& name, const string& marshallMethod,
+                     const string& unmarshallMethod,
+                     const string& writeArray, const string& createArray,
+                     const string& readArray)
+    :Type(name, BUILT_IN, true, false),
+     m_marshallMethod(marshallMethod),
+     m_unmarshallMethod(unmarshallMethod),
+     m_writeArrayMethod(writeArray),
+     m_createArrayMethod(createArray),
+     m_readArrayMethod(readArray)
+{
+}
+
+void
+BasicType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    addTo->Add(new MethodCall(parcel, m_marshallMethod, 1, v));
+}
+
+void
+BasicType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    addTo->Add(new Assignment(v, new MethodCall(parcel, m_unmarshallMethod)));
+}
+
+bool
+BasicType::CanBeArray() const
+{
+    return true;
+}
+
+void
+BasicType::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    addTo->Add(new MethodCall(parcel, m_writeArrayMethod, 1, v));
+}
+
+void
+BasicType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
+                            Variable* parcel)
+{
+    addTo->Add(new Assignment(v, new MethodCall(parcel, m_createArrayMethod)));
+}
+
+void
+BasicType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    addTo->Add(new MethodCall(parcel, m_readArrayMethod, 1, v));
+}
+
+
+// ================================================================
+
+BooleanType::BooleanType()
+    :Type("boolean", BUILT_IN, true, false)
+{
+}
+
+void
+BooleanType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    addTo->Add(new MethodCall(parcel, "writeInt", 1, 
+                new Ternary(v, new LiteralExpression("1"),
+                    new LiteralExpression("0"))));
+}
+
+void
+BooleanType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    addTo->Add(new Assignment(v, new Comparison(new LiteralExpression("0"),
+                    "!=", new MethodCall(parcel, "readInt"))));
+}
+
+bool
+BooleanType::CanBeArray() const
+{
+    return true;
+}
+
+void
+BooleanType::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    addTo->Add(new MethodCall(parcel, "writeBooleanArray", 1, v));
+}
+
+void
+BooleanType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
+                            Variable* parcel)
+{
+    addTo->Add(new Assignment(v, new MethodCall(parcel, "createBooleanArray")));
+}
+
+void
+BooleanType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    addTo->Add(new MethodCall(parcel, "readBooleanArray", 1, v));
+}
+
+
+// ================================================================
+
+CharType::CharType()
+    :Type("char", BUILT_IN, true, false)
+{
+}
+
+void
+CharType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    addTo->Add(new MethodCall(parcel, "writeInt", 1, 
+                    new Cast(INT_TYPE, v)));
+}
+
+void
+CharType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    addTo->Add(new Assignment(v, new MethodCall(parcel, "readInt"), this));
+}
+
+bool
+CharType::CanBeArray() const
+{
+    return true;
+}
+
+void
+CharType::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    addTo->Add(new MethodCall(parcel, "writeCharArray", 1, v));
+}
+
+void
+CharType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
+                            Variable* parcel)
+{
+    addTo->Add(new Assignment(v, new MethodCall(parcel, "createCharArray")));
+}
+
+void
+CharType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    addTo->Add(new MethodCall(parcel, "readCharArray", 1, v));
+}
+
+// ================================================================
+
+StringType::StringType()
+    :Type("java.lang", "String", BUILT_IN, true, false)
+{
+}
+
+string
+StringType::CreatorName() const
+{
+    return "android.os.Parcel.STRING_CREATOR";
+}
+
+void
+StringType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    addTo->Add(new MethodCall(parcel, "writeString", 1, v));
+}
+
+void
+StringType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    addTo->Add(new Assignment(v, new MethodCall(parcel, "readString")));
+}
+
+bool
+StringType::CanBeArray() const
+{
+    return true;
+}
+
+void
+StringType::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    addTo->Add(new MethodCall(parcel, "writeStringArray", 1, v));
+}
+
+void
+StringType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
+                            Variable* parcel)
+{
+    addTo->Add(new Assignment(v, new MethodCall(parcel, "createStringArray")));
+}
+
+void
+StringType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    addTo->Add(new MethodCall(parcel, "readStringArray", 1, v));
+}
+
+// ================================================================
+
+CharSequenceType::CharSequenceType()
+    :Type("java.lang", "CharSequence", BUILT_IN, true, false)
+{
+}
+
+string
+CharSequenceType::CreatorName() const
+{
+    return "android.os.Parcel.STRING_CREATOR";
+}
+
+void
+CharSequenceType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    // if (v != null) {
+    //     parcel.writeInt(1);
+    //     v.writeToParcel(parcel);
+    // } else {
+    //     parcel.writeInt(0);
+    // }
+    IfStatement* elsepart = new IfStatement();
+    elsepart->statements->Add(new MethodCall(parcel, "writeInt", 1,
+                                new LiteralExpression("0")));
+    IfStatement* ifpart = new IfStatement;
+    ifpart->expression = new Comparison(v, "!=", NULL_VALUE);
+    ifpart->elseif = elsepart;
+    ifpart->statements->Add(new MethodCall(parcel, "writeInt", 1,
+                                new LiteralExpression("1")));
+    ifpart->statements->Add(new MethodCall(TEXT_UTILS_TYPE, "writeToParcel",
+                                3, v, parcel, BuildWriteToParcelFlags(flags)));
+
+    addTo->Add(ifpart);
+}
+
+void
+CharSequenceType::CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                Variable* parcel)
+{
+    // if (0 != parcel.readInt()) {
+    //     v = TextUtils.createFromParcel(parcel)
+    // } else {
+    //     v = null;
+    // }
+    IfStatement* elsepart = new IfStatement();
+    elsepart->statements->Add(new Assignment(v, NULL_VALUE));
+
+    IfStatement* ifpart = new IfStatement();
+    ifpart->expression = new Comparison(new LiteralExpression("0"), "!=",
+                new MethodCall(parcel, "readInt"));
+    ifpart->elseif = elsepart;
+    ifpart->statements->Add(new Assignment(v,
+                new MethodCall(TEXT_UTILS_TYPE,
+                                    "CHAR_SEQUENCE_CREATOR.createFromParcel", 1, parcel)));
+
+    addTo->Add(ifpart);
+}
+
+
+// ================================================================
+
+RemoteExceptionType::RemoteExceptionType()
+    :Type("android.os", "RemoteException", BUILT_IN, false, false)
+{
+}
+
+void
+RemoteExceptionType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+void
+RemoteExceptionType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+// ================================================================
+
+RuntimeExceptionType::RuntimeExceptionType()
+    :Type("java.lang", "RuntimeException", BUILT_IN, false, false)
+{
+}
+
+void
+RuntimeExceptionType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+void
+RuntimeExceptionType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+
+// ================================================================
+
+IBinderType::IBinderType()
+    :Type("android.os", "IBinder", BUILT_IN, true, false)
+{
+}
+
+void
+IBinderType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    addTo->Add(new MethodCall(parcel, "writeStrongBinder", 1, v));
+}
+
+void
+IBinderType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    addTo->Add(new Assignment(v, new MethodCall(parcel, "readStrongBinder")));
+}
+
+void
+IBinderType::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    addTo->Add(new MethodCall(parcel, "writeBinderArray", 1, v));
+}
+
+void
+IBinderType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
+                            Variable* parcel)
+{
+    addTo->Add(new Assignment(v, new MethodCall(parcel, "createBinderArray")));
+}
+
+void
+IBinderType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    addTo->Add(new MethodCall(parcel, "readBinderArray", 1, v));
+}
+
+
+// ================================================================
+
+IInterfaceType::IInterfaceType()
+    :Type("android.os", "IInterface", BUILT_IN, false, false)
+{
+}
+
+void
+IInterfaceType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+void
+IInterfaceType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+
+// ================================================================
+
+BinderType::BinderType()
+    :Type("android.os", "Binder", BUILT_IN, false, false)
+{
+}
+
+void
+BinderType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+void
+BinderType::CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel)
+{
+    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+
+// ================================================================
+
+BinderProxyType::BinderProxyType()
+    :Type("android.os", "BinderProxy", BUILT_IN, false, false)
+{
+}
+
+void
+BinderProxyType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+void
+BinderProxyType::CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel)
+{
+    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+
+// ================================================================
+
+ParcelType::ParcelType()
+    :Type("android.os", "Parcel", BUILT_IN, false, false)
+{
+}
+
+void
+ParcelType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+void
+ParcelType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+// ================================================================
+
+ParcelableInterfaceType::ParcelableInterfaceType()
+    :Type("android.os", "Parcelable", BUILT_IN, false, false)
+{
+}
+
+void
+ParcelableInterfaceType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+void
+ParcelableInterfaceType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+// ================================================================
+
+MapType::MapType()
+    :Type("java.util", "Map", BUILT_IN, true, true)
+{
+}
+
+void
+MapType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    addTo->Add(new MethodCall(parcel, "writeMap", 1, v));
+}
+
+void
+MapType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    Variable *cl = new Variable(CLASSLOADER_TYPE, "cl");
+    addTo->Add(new VariableDeclaration(cl,
+        new LiteralExpression("this.getClass().getClassLoader()"),
+        CLASSLOADER_TYPE));
+    addTo->Add(new Assignment(v, new MethodCall(parcel, "readHashMap", 1, cl)));
+}
+
+void
+MapType::ReadFromParcel(StatementBlock* addTo, Variable* v,
+                    Variable* parcel)
+{
+    Variable *cl = new Variable(CLASSLOADER_TYPE, "cl");
+    addTo->Add(new VariableDeclaration(cl, 
+        new LiteralExpression("this.getClass().getClassLoader()"),
+        CLASSLOADER_TYPE));
+    addTo->Add(new MethodCall(parcel, "readMap", 2, v, cl));
+}
+
+
+// ================================================================
+
+ListType::ListType()
+    :Type("java.util", "List", BUILT_IN, true, true)
+{
+}
+
+string
+ListType::InstantiableName() const
+{
+    return "java.util.ArrayList";
+}
+
+void
+ListType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    addTo->Add(new MethodCall(parcel, "writeList", 1, v));
+}
+
+void
+ListType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    Variable *cl = new Variable(CLASSLOADER_TYPE, "cl");
+    addTo->Add(new VariableDeclaration(cl, 
+        new LiteralExpression("this.getClass().getClassLoader()"),
+        CLASSLOADER_TYPE));
+    addTo->Add(new Assignment(v, new MethodCall(parcel, "readArrayList", 1, cl)));
+}
+
+void
+ListType::ReadFromParcel(StatementBlock* addTo, Variable* v,
+                    Variable* parcel)
+{
+    Variable *cl = new Variable(CLASSLOADER_TYPE, "cl");
+    addTo->Add(new VariableDeclaration(cl, 
+        new LiteralExpression("this.getClass().getClassLoader()"),
+        CLASSLOADER_TYPE));
+    addTo->Add(new MethodCall(parcel, "readList", 2, v, cl));
+}
+
+
+// ================================================================
+
+ParcelableType::ParcelableType(const string& package, const string& name,
+                        bool builtIn, const string& declFile, int declLine)
+    :Type(package, name, builtIn ? BUILT_IN : PARCELABLE, true, true,
+            declFile, declLine)
+{
+}
+
+string
+ParcelableType::CreatorName() const
+{
+    return QualifiedName() + ".CREATOR";
+}
+
+void
+ParcelableType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    // if (v != null) {
+    //     parcel.writeInt(1);
+    //     v.writeToParcel(parcel);
+    // } else {
+    //     parcel.writeInt(0);
+    // }
+    IfStatement* elsepart = new IfStatement();
+    elsepart->statements->Add(new MethodCall(parcel, "writeInt", 1,
+                                new LiteralExpression("0")));
+    IfStatement* ifpart = new IfStatement;
+    ifpart->expression = new Comparison(v, "!=", NULL_VALUE);
+    ifpart->elseif = elsepart;
+    ifpart->statements->Add(new MethodCall(parcel, "writeInt", 1,
+                                new LiteralExpression("1")));
+    ifpart->statements->Add(new MethodCall(v, "writeToParcel", 2,
+                                parcel, BuildWriteToParcelFlags(flags)));
+
+    addTo->Add(ifpart);
+}
+
+void
+ParcelableType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    // if (0 != parcel.readInt()) {
+    //     v = CLASS.CREATOR.createFromParcel(parcel)
+    // } else {
+    //     v = null;
+    // }
+    IfStatement* elsepart = new IfStatement();
+    elsepart->statements->Add(new Assignment(v, NULL_VALUE));
+
+    IfStatement* ifpart = new IfStatement();
+    ifpart->expression = new Comparison(new LiteralExpression("0"), "!=",
+                new MethodCall(parcel, "readInt"));
+    ifpart->elseif = elsepart;
+    ifpart->statements->Add(new Assignment(v,
+                new MethodCall(v->type, "CREATOR.createFromParcel", 1, parcel)));
+
+    addTo->Add(ifpart);
+}
+
+void
+ParcelableType::ReadFromParcel(StatementBlock* addTo, Variable* v,
+                    Variable* parcel)
+{
+    // TODO: really, we don't need to have this extra check, but we
+    // don't have two separate marshalling code paths
+    // if (0 != parcel.readInt()) {
+    //     v.readFromParcel(parcel)
+    // }
+    IfStatement* ifpart = new IfStatement();
+    ifpart->expression = new Comparison(new LiteralExpression("0"), "!=",
+                new MethodCall(parcel, "readInt"));
+    ifpart->statements->Add(new MethodCall(v, "readFromParcel", 1, parcel));
+    addTo->Add(ifpart);
+}
+
+bool
+ParcelableType::CanBeArray() const
+{
+    return true;
+}
+
+void
+ParcelableType::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    addTo->Add(new MethodCall(parcel, "writeTypedArray", 2, v,
+                BuildWriteToParcelFlags(flags)));
+}
+
+void
+ParcelableType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
+                            Variable* parcel)
+{
+    string creator = v->type->QualifiedName() + ".CREATOR";
+    addTo->Add(new Assignment(v, new MethodCall(parcel,
+                "createTypedArray", 1, new LiteralExpression(creator))));
+}
+
+void
+ParcelableType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    string creator = v->type->QualifiedName() + ".CREATOR";
+    addTo->Add(new MethodCall(parcel, "readTypedArray", 2,
+                    v, new LiteralExpression(creator)));
+}
+
+
+// ================================================================
+
+InterfaceType::InterfaceType(const string& package, const string& name,
+                        bool builtIn, bool oneway,
+                        const string& declFile, int declLine)
+    :Type(package, name, builtIn ? BUILT_IN : INTERFACE, true, false,
+                        declFile, declLine)
+    ,m_oneway(oneway)
+{
+}
+
+bool
+InterfaceType::OneWay() const
+{
+    return m_oneway;
+}
+
+void
+InterfaceType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    // parcel.writeStrongBinder(v != null ? v.asBinder() : null);
+    addTo->Add(new MethodCall(parcel, "writeStrongBinder", 1, 
+                new Ternary(
+                    new Comparison(v, "!=", NULL_VALUE),
+                    new MethodCall(v, "asBinder"),
+                    NULL_VALUE)));
+}
+
+void
+InterfaceType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    // v = Interface.asInterface(parcel.readStrongBinder());
+    string type = v->type->QualifiedName();
+    type += ".Stub";
+    addTo->Add(new Assignment(v,
+                new MethodCall( NAMES.Find(type), "asInterface", 1,
+                    new MethodCall(parcel, "readStrongBinder"))));
+}
+
+
+// ================================================================
+
+GenericType::GenericType(const string& package, const string& name,
+                         const vector<Type*>& args)
+    :Type(package, name, BUILT_IN, true, true)
+{
+    m_args = args;
+
+    m_importName = package + '.' + name;
+
+    string gen = "<";
+    int N = args.size();
+    for (int i=0; i<N; i++) {
+        Type* t = args[i];
+        gen += t->QualifiedName();
+        if (i != N-1) {
+            gen += ',';
+        }
+    }
+    gen += '>';
+    m_genericArguments = gen;
+    SetQualifiedName(m_importName + gen);
+}
+
+string
+GenericType::GenericArguments() const
+{
+    return m_genericArguments;
+}
+
+string
+GenericType::ImportType() const
+{
+    return m_importName;
+}
+
+void
+GenericType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    fprintf(stderr, "implement GenericType::WriteToParcel\n");
+}
+
+void
+GenericType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    fprintf(stderr, "implement GenericType::CreateFromParcel\n");
+}
+
+void
+GenericType::ReadFromParcel(StatementBlock* addTo, Variable* v,
+                            Variable* parcel)
+{
+    fprintf(stderr, "implement GenericType::ReadFromParcel\n");
+}
+
+
+// ================================================================
+
+GenericListType::GenericListType(const string& package, const string& name,
+                         const vector<Type*>& args)
+    :GenericType(package, name, args),
+     m_creator(args[0]->CreatorName())
+{
+}
+
+string
+GenericListType::CreatorName() const
+{
+    return "android.os.Parcel.arrayListCreator";
+}
+
+string
+GenericListType::InstantiableName() const
+{
+    return "java.util.ArrayList" + GenericArguments();
+}
+
+void
+GenericListType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+{
+    if (m_creator == STRING_TYPE->CreatorName()) {
+        addTo->Add(new MethodCall(parcel, "writeStringList", 1, v));
+    } else if (m_creator == IBINDER_TYPE->CreatorName()) {
+        addTo->Add(new MethodCall(parcel, "writeBinderList", 1, v));
+    } else {
+        // parcel.writeTypedListXX(arg);
+        addTo->Add(new MethodCall(parcel, "writeTypedList", 1, v));
+    }
+}
+
+void
+GenericListType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+{
+    if (m_creator == STRING_TYPE->CreatorName()) {
+        addTo->Add(new Assignment(v,
+                   new MethodCall(parcel, "createStringArrayList", 0)));
+    } else if (m_creator == IBINDER_TYPE->CreatorName()) {
+        addTo->Add(new Assignment(v,
+                   new MethodCall(parcel, "createBinderArrayList", 0)));
+    } else {
+        // v = _data.readTypedArrayList(XXX.creator);
+        addTo->Add(new Assignment(v,
+                   new MethodCall(parcel, "createTypedArrayList", 1,
+                   new LiteralExpression(m_creator))));
+    }
+}
+
+void
+GenericListType::ReadFromParcel(StatementBlock* addTo, Variable* v,
+                            Variable* parcel)
+{
+    if (m_creator == STRING_TYPE->CreatorName()) {
+        addTo->Add(new MethodCall(parcel, "readStringList", 1, v));
+    } else if (m_creator == IBINDER_TYPE->CreatorName()) {
+        addTo->Add(new MethodCall(parcel, "readBinderList", 1, v));
+    } else {
+        // v = _data.readTypedList(v, XXX.creator);
+        addTo->Add(new MethodCall(parcel, "readTypedList", 2,
+                       v,
+                       new LiteralExpression(m_creator)));
+    }
+}
+
+// ================================================================
+
+ClassLoaderType::ClassLoaderType()
+    :Type("java.lang", "ClassLoader", BUILT_IN, false, false)
+{
+}
+
+
+// ================================================================
+
+Namespace::Namespace()
+{
+}
+
+Namespace::~Namespace()
+{
+    int N = m_types.size();
+    for (int i=0; i<N; i++) {
+        delete m_types[i];
+    }
+}
+
+void
+Namespace::Add(Type* type)
+{
+    Type* t = Find(type->QualifiedName());
+    if (t == NULL) {
+        m_types.push_back(type);
+    }
+}
+
+void
+Namespace::AddGenericType(const string& package, const string& name, int args)
+{
+    Generic g;
+        g.package = package;
+        g.name = name;
+        g.qualified = package + '.' + name;
+        g.args = args;
+    m_generics.push_back(g);
+}
+
+Type*
+Namespace::Find(const string& name) const
+{
+    int N = m_types.size();
+    for (int i=0; i<N; i++) {
+        if (m_types[i]->QualifiedName() == name) {
+            return m_types[i];
+        }
+    }
+    return NULL;
+}
+
+Type*
+Namespace::Find(const char* package, const char* name) const
+{
+    string s;
+    if (package != NULL) {
+        s += package;
+        s += '.';
+    }
+    s += name;
+    return Find(s);
+}
+
+static string
+normalize_generic(const string& s)
+{
+    string r;
+    int N = s.size();
+    for (int i=0; i<N; i++) {
+        char c = s[i];
+        if (!isspace(c)) {
+            r += c;
+        }
+    }
+    return r;
+}
+
+Type*
+Namespace::Search(const string& name)
+{
+    // an exact match wins
+    Type* result = Find(name);
+    if (result != NULL) {
+        return result;
+    }
+
+    // try the class names
+    // our language doesn't allow you to not specify outer classes
+    // when referencing an inner class.  that could be changed, and this
+    // would be the place to do it, but I don't think the complexity in
+    // scoping rules is worth it.
+    int N = m_types.size();
+    for (int i=0; i<N; i++) {
+        if (m_types[i]->Name() == name) {
+            return m_types[i];
+        }
+    }
+
+    // we got to here and it's not a generic, give up
+    if (name.find('<') == name.npos) {
+        return NULL;
+    }
+
+    // remove any whitespace
+    string normalized = normalize_generic(name);
+
+    // find the part before the '<', find a generic for it
+    ssize_t baseIndex = normalized.find('<');
+    string base(normalized.c_str(), baseIndex);
+    const Generic* g = search_generic(base);
+    if (g == NULL) {
+        return NULL;
+    }
+
+    // For each of the args, do a recursive search on it.  We don't allow
+    // generics within generics like Java does, because we're really limiting
+    // them to just built-in container classes, at least for now.  Our syntax
+    // ensures this right now as well.
+    vector<Type*> args;
+    size_t start = baseIndex + 1;
+    size_t end = start;
+    while (normalized[start] != '\0') {
+        end = normalized.find(',', start);
+        if (end == normalized.npos) {
+            end = normalized.find('>', start);
+        }
+        string s(normalized.c_str()+start, end-start);
+        Type* t = this->Search(s);
+        if (t == NULL) {
+            // maybe we should print a warning here?
+            return NULL;
+        }
+        args.push_back(t);
+        start = end+1;
+    }
+
+    // construct a GenericType, add it to our name set so they always get
+    // the same object, and return it.
+    result = make_generic_type(g->package, g->name, args);
+    if (result == NULL) {
+        return NULL;
+    }
+
+    this->Add(result);
+    return this->Find(result->QualifiedName());
+}
+
+const Namespace::Generic*
+Namespace::search_generic(const string& name) const
+{
+    int N = m_generics.size();
+
+    // first exact match
+    for (int i=0; i<N; i++) {
+        const Generic& g = m_generics[i];
+        if (g.qualified == name) {
+            return &g;
+        }
+    }
+
+    // then name match
+    for (int i=0; i<N; i++) {
+        const Generic& g = m_generics[i];
+        if (g.name == name) {
+            return &g;
+        }
+    }
+
+    return NULL;
+}
+
+void
+Namespace::Dump() const
+{
+    int n = m_types.size();
+    for (int i=0; i<n; i++) {
+        Type* t = m_types[i];
+        printf("type: package=%s name=%s qualifiedName=%s\n",
+                t->Package().c_str(), t->Name().c_str(),
+                t->QualifiedName().c_str());
+    }
+}
diff --git a/tools/aidl/Type.h b/tools/aidl/Type.h
new file mode 100755
index 0000000..2ea3ac9
--- /dev/null
+++ b/tools/aidl/Type.h
@@ -0,0 +1,466 @@
+#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,
+        PARCELABLE,
+        INTERFACE,
+        GENERATED
+    };
+    
+    // WriteToParcel flags
+    enum {
+        PARCELABLE_WRITE_RETURN_VALUE = 0x0001
+    };
+
+                    Type(const string& name, int kind, bool canWriteToParcel,
+                            bool canBeOut);
+                    Type(const string& package, const string& name,
+                            int kind, bool canWriteToParcel, 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     CanBeMarshalled() const     { return m_canWriteToParcel; }
+    inline bool     CanBeOutParameter() const   { return m_canBeOut; }
+    
+    virtual string  ImportType() const;
+    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);
+    virtual void    ReadFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel);
+
+    virtual bool    CanBeArray() const;
+
+    virtual void    WriteArrayToParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, int flags);
+    virtual void    CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel);
+    virtual void    ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel);
+
+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_canBeOut;
+};
+
+class BasicType : public Type
+{
+public:
+                    BasicType(const string& name, const string& marshallMethod,
+                              const string& unmarshallMethod,
+                              const string& writeArray,
+                              const string& createArray,
+                              const string& readArray);
+
+    virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, int flags);
+    virtual void    CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel);
+
+    virtual bool    CanBeArray() const;
+
+    virtual void    WriteArrayToParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, int flags);
+    virtual void    CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel);
+    virtual void    ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel);
+
+private:
+    string m_marshallMethod;
+    string m_unmarshallMethod;
+    string m_writeArrayMethod;
+    string m_createArrayMethod;
+    string m_readArrayMethod;
+};
+
+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);
+
+    virtual bool    CanBeArray() const;
+
+    virtual void    WriteArrayToParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, int flags);
+    virtual void    CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel);
+    virtual void    ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel);
+};
+
+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);
+
+    virtual bool    CanBeArray() const;
+
+    virtual void    WriteArrayToParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, int flags);
+    virtual void    CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel);
+    virtual void    ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel);
+};
+
+
+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);
+
+    virtual bool    CanBeArray() const;
+
+    virtual void    WriteArrayToParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, int flags);
+    virtual void    CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel);
+    virtual void    ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel);
+};
+
+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);
+};
+
+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);
+};
+
+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);
+};
+
+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);
+
+    virtual void    WriteArrayToParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, int flags);
+    virtual void    CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel);
+    virtual void    ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel);
+};
+
+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);
+};
+
+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);
+};
+
+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);
+};
+
+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);
+};
+
+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);
+};
+
+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);
+    virtual void    ReadFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel);
+};
+
+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);
+    virtual void    ReadFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel);
+};
+
+class ParcelableType : public Type
+{
+public:
+                    ParcelableType(const string& package, const string& name,
+                            bool builtIn, const string& declFile, int declLine);
+
+    virtual string  CreatorName() const;
+
+    virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, int flags);
+    virtual void    CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel);
+    virtual void    ReadFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel);
+
+    virtual bool    CanBeArray() const;
+
+    virtual void    WriteArrayToParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, int flags);
+    virtual void    CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel);
+    virtual void    ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel);
+};
+
+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);
+                                    
+private:
+    bool m_oneway;
+};
+
+
+class GenericType : public Type
+{
+public:
+                    GenericType(const string& package, const string& name,
+                                 const vector<Type*>& args);
+
+    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);
+    virtual void    ReadFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel);
+
+private:
+    string m_genericArguments;
+    string m_importName;
+    vector<Type*> m_args;
+};
+
+
+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);
+    virtual void    ReadFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel);
+
+private:
+    string m_creator;
+};
+
+class ClassLoaderType : public Type
+{
+public:
+                    ClassLoaderType();
+};
+
+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* CHAR_TYPE;
+extern Type* INT_TYPE;
+extern Type* LONG_TYPE;
+extern Type* FLOAT_TYPE;
+extern Type* DOUBLE_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 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/tools/aidl/aidl.cpp b/tools/aidl/aidl.cpp
new file mode 100644
index 0000000..dc61567
--- /dev/null
+++ b/tools/aidl/aidl.cpp
@@ -0,0 +1,904 @@
+
+#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
+
+using namespace std;
+
+static void
+test_document(document_item_type* d)
+{
+    while (d) {
+        if (d->item_type == INTERFACE_TYPE) {
+            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 == PARCELABLE_TYPE) {
+            parcelable_type* b = (parcelable_type*)d;
+            printf("parcelable %s %s;\n", b->package, b->name.data);
+        }
+        else {
+            printf("UNKNOWN d=0x%08x d->item_type=%ld\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 == PARCELABLE_TYPE) {
+            parcelable_type* p = (parcelable_type*)items;
+            err |= check_filename(filename, p->package, &p->name);
+        }
+        else if (items->item_type == INTERFACE_TYPE) {
+            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::PARCELABLE:
+            return "a parcelable";
+        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 == PARCELABLE_TYPE) {
+            parcelable_type* p = (parcelable_type*)items;
+            type = new ParcelableType(p->package ? p->package : "",
+                            p->name.data, false, filename, p->name.lineno);
+        }
+        else if (items->item_type == INTERFACE_TYPE) {
+            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) {
+                // 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,
+                                        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,
+                                        filename, c->name.lineno);
+                NAMES.Add(proxy);
+            }
+        } 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, 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->CanBeMarshalled()) {
+        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->CanBeMarshalled()) {
+            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 (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 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 PARCELABLE_TYPE)
+        if (items->item_type == INTERFACE_TYPE) {
+            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, 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;
+    if (items->next != NULL) {
+        int lineno = -1;
+        if (next->item_type == INTERFACE_TYPE) {
+            lineno = ((interface_type*)next)->interface_token.lineno;
+        }
+        else if (next->item_type == PARCELABLE_TYPE) {
+            lineno = ((parcelable_type*)next)->parcelable_token.lineno;
+        }
+        fprintf(stderr, "%s:%d aidl can only handle one interface per file\n",
+                            filename, lineno);
+        return 1;
+    }
+
+    if (items->item_type == PARCELABLE_TYPE) {
+        *onlyParcelable = true;
+        if (options.failOnParcelable) {
+            fprintf(stderr, "%s:%d aidl can only generate code for interfaces, not"
+                            " parcelables,\n", filename,
+                            ((parcelable_type*)items)->parcelable_token.lineno);
+            fprintf(stderr, "%s:%d .aidl files that only declare parcelables "
+                            "don't need to go in the Makefile.\n", filename,
+                            ((parcelable_type*)items)->parcelable_token.lineno);
+            return 1;
+        }
+    } else {
+        *onlyParcelable = false;
+    }
+
+    return 0;
+}
+
+// ==========================================================
+void
+generate_dep_file(const Options& options)
+{
+   /* we open the file in binary mode to ensure that the same output is
+    * generated on all platforms !!
+    */
+    FILE* to = fopen(options.depFileName.c_str(), "wb");
+    if (to == NULL) {
+        return;
+    }
+
+    const char* slash = "\\";
+    import_info* import = g_imports;
+    if (import == NULL) {
+        slash = "";
+    }
+
+    fprintf(to, "%s: \\\n", options.outputFileName.c_str());
+    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");
+
+    fclose(to);
+}
+
+// ==========================================================
+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 preprocessd 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)) {
+            parcelable_type* parcl = (parcelable_type*)malloc(
+                    sizeof(parcelable_type));
+            memset(parcl, 0, sizeof(parcelable_type));
+            parcl->document_item.item_type = PARCELABLE_TYPE;
+            parcl->parcelable_token.lineno = lineno;
+            parcl->parcelable_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(";");
+            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;
+            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
+compile_aidl(const 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);
+
+    // after this, there shouldn't be any more errors because of the
+    // input.
+    if (err != 0 || mainDoc == NULL) {
+        return 1;
+    }
+
+    // they didn't ask to fail on parcelables, so just exit quietly.
+    if (onlyParcelable && !options.failOnParcelable) {
+        return 0;
+    }
+
+    // if we were asked to, generate a make dependency file
+    if (options.depFileName != "") {
+        generate_dep_file(options);
+    }
+
+    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 == PARCELABLE_TYPE) {
+            line = "parcelable ";
+            parcelable_type* parcelable = (parcelable_type*)doc;
+            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)
+{
+    int err = 0;
+
+    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/tools/aidl/aidl_language.cpp b/tools/aidl/aidl_language.cpp
new file mode 100644
index 0000000..cd6a3bd
--- /dev/null
+++ b/tools/aidl/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/tools/aidl/aidl_language.h b/tools/aidl/aidl_language.h
new file mode 100644
index 0000000..9ca5deb
--- /dev/null
+++ b/tools/aidl/aidl_language.h
@@ -0,0 +1,159 @@
+#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;
+    // XXX missing comments/copy text here
+    buffer_type semicolon_token;
+    buffer_type* comments_token; // points into this structure, DO NOT DELETE
+} method_type;
+
+enum {
+    PARCELABLE_TYPE = 12,
+    INTERFACE_TYPE
+};
+
+typedef struct document_item_type {
+    unsigned item_type;
+    struct document_item_type* next;
+} document_item_type;
+
+typedef struct parcelable_type {
+    document_item_type document_item;
+    buffer_type parcelable_token;
+    char* package;
+    buffer_type name;
+    buffer_type semicolon_token;
+} parcelable_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;
+    parcelable_type* parcelable;
+    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/tools/aidl/aidl_language_l.l b/tools/aidl/aidl_language_l.l
new file mode 100644
index 0000000..567b1cf
--- /dev/null
+++ b/tools/aidl/aidl_language_l.l
@@ -0,0 +1,210 @@
+%{
+#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}?\]
+
+%%
+
+
+\%\%\{              { 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 ','; }
+
+    /* keywords */
+parcelable      { SET_BUFFER(PARCELABLE); return PARCELABLE; }
+interface       { SET_BUFFER(INTERFACE); return INTERFACE; }
+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; }
+
+{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/tools/aidl/aidl_language_y.y b/tools/aidl/aidl_language_y.y
new file mode 100644
index 0000000..3d65f17
--- /dev/null
+++ b/tools/aidl/aidl_language_y.y
@@ -0,0 +1,288 @@
+%{
+#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 GENERIC
+%token ARRAY
+%token PARCELABLE
+%token INTERFACE
+%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.parcelable; }
+    |   interface_decl                             { $$.document_item = (document_item_type*)$1.interface_item; }
+    ;
+
+parcelable_decl:
+        PARCELABLE IDENTIFIER ';'                  { 
+                                                        parcelable_type* b = (parcelable_type*)malloc(sizeof(parcelable_type));
+                                                        b->document_item.item_type = PARCELABLE_TYPE;
+                                                        b->document_item.next = NULL;
+                                                        b->parcelable_token = $1.buffer;
+                                                        b->name = $2.buffer;
+                                                        b->package = g_currentPackage ? strdup(g_currentPackage) : NULL;
+                                                        b->semicolon_token = $3.buffer;
+                                                        $$.parcelable = b;
+                                                    }
+    |   PARCELABLE ';'                              {
+                                                        fprintf(stderr, "%s:%d syntax error in parcelable declaration. Expected type name.\n",
+                                                                     g_currentFilename, $1.buffer.lineno);
+                                                        $$.parcelable = 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);
+                                                        $$.parcelable = NULL;
+                                                    }
+    ;
+
+interface_header:
+        INTERFACE                                  {
+                                                        interface_type* c = (interface_type*)malloc(sizeof(interface_type));
+                                                        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->interface_token = $2.buffer;
+                                                        c->oneway = true;
+                                                        c->oneway_token = $1.buffer;
+                                                        c->comments_token = &c->oneway_token;
+                                                        $$.interface_obj = c;
+                                                   }
+    ;
+
+interface_decl:
+        interface_header IDENTIFIER '{' interface_items '}' { 
+                                                        interface_type* c = $1.interface_obj;
+                                                        c->document_item.item_type = INTERFACE_TYPE;
+                                                        c->document_item.next = NULL;
+                                                        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 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 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->type = $1.type;
+                                                        method->oneway = false;
+                                                        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->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->semicolon_token = $7.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/tools/aidl/generate_java.cpp b/tools/aidl/generate_java.cpp
new file mode 100644
index 0000000..e3c0af0
--- /dev/null
+++ b/tools/aidl/generate_java.cpp
@@ -0,0 +1,652 @@
+#include "generate_java.h"
+#include "AST.h"
+#include "Type.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+// =================================================
+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;
+};
+
+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];
+}
+
+// =================================================
+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;
+        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;
+        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->Name();
+        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, iinType);
+    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;
+        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 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;
+}
+
+static string
+append(const char* a, const char* b)
+{
+    string s = a;
+    s += b;
+    return s;
+}
+
+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)
+{
+    if (v->dimension == 0) {
+        t->CreateFromParcel(addTo, v, parcel);
+    }
+    if (v->dimension == 1) {
+        t->CreateArrayFromParcel(addTo, v, parcel);
+    }
+}
+
+static void
+generate_read_from_parcel(Type* t, StatementBlock* addTo, Variable* v,
+                            Variable* parcel)
+{
+    if (v->dimension == 0) {
+        t->ReadFromParcel(addTo, v, parcel);
+    }
+    if (v->dimension == 1) {
+        t->ReadArrayFromParcel(addTo, v, parcel);
+    }
+}
+
+
+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[50];
+    sprintf(transactCodeValue, "(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
+    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);
+        } 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;
+        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 ? "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);
+        }
+
+        // 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);
+            }
+            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);
+}
+
+static Class*
+generate_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) {
+            generate_method((method_type*)item, interface, stub, proxy, index);
+        }
+        item = item->next;
+        index++;
+    }
+
+    return interface;
+}
+
+int
+generate_java(const string& filename, const string& originalSrc,
+                interface_type* iface)
+{
+    Document* document = new Document;
+        document->comment = "";
+        if (iface->package) document->package = iface->package;
+        document->originalSrc = originalSrc;
+        document->classes.push_back(generate_interface_class(iface));
+
+//    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/tools/aidl/generate_java.h b/tools/aidl/generate_java.h
new file mode 100644
index 0000000..203fe23
--- /dev/null
+++ b/tools/aidl/generate_java.h
@@ -0,0 +1,14 @@
+#ifndef GENERATE_JAVA_H
+#define GENERATE_JAVA_H
+
+#include "aidl_language.h"
+
+#include <string>
+
+using namespace std;
+
+int generate_java(const string& filename, const string& originalSrc,
+                interface_type* iface);
+
+#endif // GENERATE_JAVA_H
+
diff --git a/tools/aidl/options.cpp b/tools/aidl/options.cpp
new file mode 100644
index 0000000..57b10ae
--- /dev/null
+++ b/tools/aidl/options.cpp
@@ -0,0 +1,138 @@
+
+#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"
+            "   -p<FILE> file created by --preprocess to import.\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. If omitted, the input filename is used, with the .aidl extension changed to a .java extension.\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
+    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] == '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 (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 {
+        // 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/tools/aidl/options.h b/tools/aidl/options.h
new file mode 100644
index 0000000..dc3c45a
--- /dev/null
+++ b/tools/aidl/options.h
@@ -0,0 +1,33 @@
+#ifndef DEVICE_TOOLS_AIDL_H
+#define DEVICE_TOOLS_AIDL_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 depFileName;
+
+    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/tools/aidl/options_test.cpp b/tools/aidl/options_test.cpp
new file mode 100644
index 0000000..bd106ce
--- /dev/null
+++ b/tools/aidl/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/tools/aidl/search_path.cpp b/tools/aidl/search_path.cpp
new file mode 100644
index 0000000..ffb6cb2
--- /dev/null
+++ b/tools/aidl/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/tools/aidl/search_path.h b/tools/aidl/search_path.h
new file mode 100644
index 0000000..2bf94b1
--- /dev/null
+++ b/tools/aidl/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
+