summaryrefslogtreecommitdiffstats
path: root/tools/aidl
diff options
context:
space:
mode:
Diffstat (limited to 'tools/aidl')
-rwxr-xr-xtools/aidl/AST.cpp867
-rwxr-xr-xtools/aidl/AST.h346
-rw-r--r--tools/aidl/Android.mk24
-rwxr-xr-xtools/aidl/Type.cpp1228
-rwxr-xr-xtools/aidl/Type.h466
-rw-r--r--tools/aidl/aidl.cpp904
-rw-r--r--tools/aidl/aidl_language.cpp20
-rw-r--r--tools/aidl/aidl_language.h159
-rw-r--r--tools/aidl/aidl_language_l.l210
-rw-r--r--tools/aidl/aidl_language_y.y288
-rw-r--r--tools/aidl/generate_java.cpp652
-rw-r--r--tools/aidl/generate_java.h14
-rw-r--r--tools/aidl/options.cpp138
-rw-r--r--tools/aidl/options.h33
-rw-r--r--tools/aidl/options_test.cpp291
-rw-r--r--tools/aidl/search_path.cpp57
-rw-r--r--tools/aidl/search_path.h23
17 files changed, 5720 insertions, 0 deletions
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
+