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