diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
commit | 54b6cfa9a9e5b861a9930af873580d6dc20f773c (patch) | |
tree | 35051494d2af230dce54d6b31c6af8fc24091316 /tools/aidl | |
download | frameworks_base-54b6cfa9a9e5b861a9930af873580d6dc20f773c.zip frameworks_base-54b6cfa9a9e5b861a9930af873580d6dc20f773c.tar.gz frameworks_base-54b6cfa9a9e5b861a9930af873580d6dc20f773c.tar.bz2 |
Initial Contribution
Diffstat (limited to 'tools/aidl')
-rwxr-xr-x | tools/aidl/AST.cpp | 867 | ||||
-rwxr-xr-x | tools/aidl/AST.h | 346 | ||||
-rw-r--r-- | tools/aidl/Android.mk | 24 | ||||
-rwxr-xr-x | tools/aidl/Type.cpp | 1228 | ||||
-rwxr-xr-x | tools/aidl/Type.h | 466 | ||||
-rw-r--r-- | tools/aidl/aidl.cpp | 902 | ||||
-rw-r--r-- | tools/aidl/aidl_language.cpp | 20 | ||||
-rw-r--r-- | tools/aidl/aidl_language.h | 159 | ||||
-rw-r--r-- | tools/aidl/aidl_language_l.l | 210 | ||||
-rw-r--r-- | tools/aidl/aidl_language_y.y | 288 | ||||
-rw-r--r-- | tools/aidl/generate_java.cpp | 650 | ||||
-rw-r--r-- | tools/aidl/generate_java.h | 14 | ||||
-rw-r--r-- | tools/aidl/options.cpp | 134 | ||||
-rw-r--r-- | tools/aidl/options.h | 33 | ||||
-rw-r--r-- | tools/aidl/options_test.cpp | 291 | ||||
-rw-r--r-- | tools/aidl/search_path.cpp | 56 | ||||
-rw-r--r-- | tools/aidl/search_path.h | 22 |
17 files changed, 5710 insertions, 0 deletions
diff --git a/tools/aidl/AST.cpp b/tools/aidl/AST.cpp new file mode 100755 index 0000000..91802a9 --- /dev/null +++ b/tools/aidl/AST.cpp @@ -0,0 +1,867 @@ +#include "AST.h" +#include "Type.h" + +void +WriteModifiers(FILE* to, int mod, int mask) +{ + int m = mod & mask; + + if ((m & SCOPE_MASK) == PUBLIC) { + fprintf(to, "public "); + } + else if ((m & SCOPE_MASK) == PRIVATE) { + fprintf(to, "private "); + } + else if ((m & SCOPE_MASK) == PROTECTED) { + fprintf(to, "protected "); + } + + if (m & STATIC) { + fprintf(to, "static "); + } + + if (m & FINAL) { + fprintf(to, "final "); + } + + if (m & ABSTRACT) { + fprintf(to, "abstract "); + } +} + +void +WriteArgumentList(FILE* to, const vector<Expression*>& arguments) +{ + size_t N = arguments.size(); + for (size_t i=0; i<N; i++) { + arguments[i]->Write(to); + if (i != N-1) { + fprintf(to, ", "); + } + } +} + +ClassElement::ClassElement() +{ +} + +ClassElement::~ClassElement() +{ +} + +Field::Field() + :ClassElement(), + modifiers(0), + variable(NULL) +{ +} + +Field::Field(int m, Variable* v) + :ClassElement(), + modifiers(m), + variable(v) +{ +} + +Field::~Field() +{ +} + +void +Field::GatherTypes(set<Type*>* types) const +{ + types->insert(this->variable->type); +} + +void +Field::Write(FILE* to) +{ + if (this->comment.length() != 0) { + fprintf(to, "%s\n", this->comment.c_str()); + } + WriteModifiers(to, this->modifiers, SCOPE_MASK | STATIC | FINAL); + fprintf(to, "%s %s", this->variable->type->QualifiedName().c_str(), + this->variable->name.c_str()); + if (this->value.length() != 0) { + fprintf(to, " = %s", this->value.c_str()); + } + fprintf(to, ";\n"); +} + +Expression::~Expression() +{ +} + +LiteralExpression::LiteralExpression(const string& v) + :value(v) +{ +} + +LiteralExpression::~LiteralExpression() +{ +} + +void +LiteralExpression::Write(FILE* to) +{ + fprintf(to, "%s", this->value.c_str()); +} + +Variable::Variable() + :type(NULL), + name(), + dimension(0) +{ +} + +Variable::Variable(Type* t, const string& n) + :type(t), + name(n), + dimension(0) +{ +} + +Variable::Variable(Type* t, const string& n, int d) + :type(t), + name(n), + dimension(d) +{ +} + +Variable::~Variable() +{ +} + +void +Variable::GatherTypes(set<Type*>* types) const +{ + types->insert(this->type); +} + +void +Variable::WriteDeclaration(FILE* to) +{ + string dim; + for (int i=0; i<this->dimension; i++) { + dim += "[]"; + } + fprintf(to, "%s%s %s", this->type->QualifiedName().c_str(), dim.c_str(), + this->name.c_str()); +} + +void +Variable::Write(FILE* to) +{ + fprintf(to, "%s", name.c_str()); +} + +FieldVariable::FieldVariable(Expression* o, const string& n) + :object(o), + clazz(NULL), + name(n) +{ +} + +FieldVariable::FieldVariable(Type* c, const string& n) + :object(NULL), + clazz(c), + name(n) +{ +} + +FieldVariable::~FieldVariable() +{ +} + +void +FieldVariable::Write(FILE* to) +{ + if (this->object != NULL) { + this->object->Write(to); + } + else if (this->clazz != NULL) { + fprintf(to, "%s", this->clazz->QualifiedName().c_str()); + } + fprintf(to, ".%s", name.c_str()); +} + + +Statement::~Statement() +{ +} + +StatementBlock::StatementBlock() +{ +} + +StatementBlock::~StatementBlock() +{ +} + +void +StatementBlock::Write(FILE* to) +{ + fprintf(to, "{\n"); + int N = this->statements.size(); + for (int i=0; i<N; i++) { + this->statements[i]->Write(to); + } + fprintf(to, "}\n"); +} + +void +StatementBlock::Add(Statement* statement) +{ + this->statements.push_back(statement); +} + +void +StatementBlock::Add(Expression* expression) +{ + this->statements.push_back(new ExpressionStatement(expression)); +} + +ExpressionStatement::ExpressionStatement(Expression* e) + :expression(e) +{ +} + +ExpressionStatement::~ExpressionStatement() +{ +} + +void +ExpressionStatement::Write(FILE* to) +{ + this->expression->Write(to); + fprintf(to, ";\n"); +} + +Assignment::Assignment(Variable* l, Expression* r) + :lvalue(l), + rvalue(r), + cast(NULL) +{ +} + +Assignment::Assignment(Variable* l, Expression* r, Type* c) + :lvalue(l), + rvalue(r), + cast(c) +{ +} + +Assignment::~Assignment() +{ +} + +void +Assignment::Write(FILE* to) +{ + this->lvalue->Write(to); + fprintf(to, " = "); + if (this->cast != NULL) { + fprintf(to, "(%s)", this->cast->QualifiedName().c_str()); + } + this->rvalue->Write(to); +} + +MethodCall::MethodCall(const string& n) + :obj(NULL), + clazz(NULL), + name(n) +{ +} + +MethodCall::MethodCall(Expression* o, const string& n) + :obj(o), + clazz(NULL), + name(n) +{ +} + +MethodCall::MethodCall(Type* t, const string& n) + :obj(NULL), + clazz(t), + name(n) +{ +} + +MethodCall::MethodCall(Expression* o, const string& n, int argc = 0, ...) + :obj(o), + clazz(NULL), + name(n) +{ + va_list args; + va_start(args, argc); + init(argc, args); + va_end(args); +} + +MethodCall::MethodCall(Type* t, const string& n, int argc = 0, ...) + :obj(NULL), + clazz(t), + name(n) +{ + va_list args; + va_start(args, argc); + init(argc, args); + va_end(args); +} + +MethodCall::~MethodCall() +{ +} + +void +MethodCall::init(int n, va_list args) +{ + for (int i=0; i<n; i++) { + Expression* expression = (Expression*)va_arg(args, void*); + this->arguments.push_back(expression); + } +} + +void +MethodCall::Write(FILE* to) +{ + if (this->obj != NULL) { + this->obj->Write(to); + fprintf(to, "."); + } + else if (this->clazz != NULL) { + fprintf(to, "%s.", this->clazz->QualifiedName().c_str()); + } + fprintf(to, "%s(", this->name.c_str()); + WriteArgumentList(to, this->arguments); + fprintf(to, ")"); +} + +Comparison::Comparison(Expression* l, const string& o, Expression* r) + :lvalue(l), + op(o), + rvalue(r) +{ +} + +Comparison::~Comparison() +{ +} + +void +Comparison::Write(FILE* to) +{ + fprintf(to, "("); + this->lvalue->Write(to); + fprintf(to, "%s", this->op.c_str()); + this->rvalue->Write(to); + fprintf(to, ")"); +} + +NewExpression::NewExpression(Type* t) + :type(t) +{ +} + +NewExpression::~NewExpression() +{ +} + +void +NewExpression::Write(FILE* to) +{ + fprintf(to, "new %s(", this->type->InstantiableName().c_str()); + WriteArgumentList(to, this->arguments); + fprintf(to, ")"); +} + +NewArrayExpression::NewArrayExpression(Type* t, Expression* s) + :type(t), + size(s) +{ +} + +NewArrayExpression::~NewArrayExpression() +{ +} + +void +NewArrayExpression::Write(FILE* to) +{ + fprintf(to, "new %s[", this->type->QualifiedName().c_str()); + size->Write(to); + fprintf(to, "]"); +} + +Ternary::Ternary() + :condition(NULL), + ifpart(NULL), + elsepart(NULL) +{ +} + +Ternary::Ternary(Expression* a, Expression* b, Expression* c) + :condition(a), + ifpart(b), + elsepart(c) +{ +} + +Ternary::~Ternary() +{ +} + +void +Ternary::Write(FILE* to) +{ + fprintf(to, "(("); + this->condition->Write(to); + fprintf(to, ")?("); + this->ifpart->Write(to); + fprintf(to, "):("); + this->elsepart->Write(to); + fprintf(to, "))"); +} + +Cast::Cast() + :type(NULL), + expression(NULL) +{ +} + +Cast::Cast(Type* t, Expression* e) + :type(t), + expression(e) +{ +} + +Cast::~Cast() +{ +} + +void +Cast::Write(FILE* to) +{ + fprintf(to, "((%s)", this->type->QualifiedName().c_str()); + expression->Write(to); + fprintf(to, ")"); +} + +VariableDeclaration::VariableDeclaration(Variable* l, Expression* r, Type* c) + :lvalue(l), + cast(c), + rvalue(r) +{ +} + +VariableDeclaration::VariableDeclaration(Variable* l) + :lvalue(l), + cast(NULL), + rvalue(NULL) +{ +} + +VariableDeclaration::~VariableDeclaration() +{ +} + +void +VariableDeclaration::Write(FILE* to) +{ + this->lvalue->WriteDeclaration(to); + if (this->rvalue != NULL) { + fprintf(to, " = "); + if (this->cast != NULL) { + fprintf(to, "(%s)", this->cast->QualifiedName().c_str()); + } + this->rvalue->Write(to); + } + fprintf(to, ";\n"); +} + +IfStatement::IfStatement() + :expression(NULL), + statements(new StatementBlock), + elseif(NULL) +{ +} + +IfStatement::~IfStatement() +{ +} + +void +IfStatement::Write(FILE* to) +{ + if (this->expression != NULL) { + fprintf(to, "if ("); + this->expression->Write(to); + fprintf(to, ") "); + } + this->statements->Write(to); + if (this->elseif != NULL) { + fprintf(to, "else "); + this->elseif->Write(to); + } +} + +ReturnStatement::ReturnStatement(Expression* e) + :expression(e) +{ +} + +ReturnStatement::~ReturnStatement() +{ +} + +void +ReturnStatement::Write(FILE* to) +{ + fprintf(to, "return "); + this->expression->Write(to); + fprintf(to, ";\n"); +} + +TryStatement::TryStatement() + :statements(new StatementBlock) +{ +} + +TryStatement::~TryStatement() +{ +} + +void +TryStatement::Write(FILE* to) +{ + fprintf(to, "try "); + this->statements->Write(to); +} + +CatchStatement::CatchStatement(Variable* e) + :statements(new StatementBlock), + exception(e) +{ +} + +CatchStatement::~CatchStatement() +{ +} + +void +CatchStatement::Write(FILE* to) +{ + fprintf(to, "catch "); + if (this->exception != NULL) { + fprintf(to, "("); + this->exception->WriteDeclaration(to); + fprintf(to, ") "); + } + this->statements->Write(to); +} + +FinallyStatement::FinallyStatement() + :statements(new StatementBlock) +{ +} + +FinallyStatement::~FinallyStatement() +{ +} + +void +FinallyStatement::Write(FILE* to) +{ + fprintf(to, "finally "); + this->statements->Write(to); +} + +Case::Case() + :statements(new StatementBlock) +{ +} + +Case::Case(const string& c) + :statements(new StatementBlock) +{ + cases.push_back(c); +} + +Case::~Case() +{ +} + +void +Case::Write(FILE* to) +{ + int N = this->cases.size(); + if (N > 0) { + for (int i=0; i<N; i++) { + string s = this->cases[i]; + if (s.length() != 0) { + fprintf(to, "case %s:\n", s.c_str()); + } else { + fprintf(to, "default:\n"); + } + } + } else { + fprintf(to, "default:\n"); + } + statements->Write(to); +} + +SwitchStatement::SwitchStatement(Expression* e) + :expression(e) +{ +} + +SwitchStatement::~SwitchStatement() +{ +} + +void +SwitchStatement::Write(FILE* to) +{ + fprintf(to, "switch ("); + this->expression->Write(to); + fprintf(to, ")\n{\n"); + int N = this->cases.size(); + for (int i=0; i<N; i++) { + this->cases[i]->Write(to); + } + fprintf(to, "}\n"); +} + +Method::Method() + :ClassElement(), + modifiers(0), + returnType(NULL), // (NULL means constructor) + returnTypeDimension(0), + statements(NULL) +{ +} + +Method::~Method() +{ +} + +void +Method::GatherTypes(set<Type*>* types) const +{ + size_t N, i; + + if (this->returnType) { + types->insert(this->returnType); + } + + N = this->parameters.size(); + for (i=0; i<N; i++) { + this->parameters[i]->GatherTypes(types); + } + + N = this->exceptions.size(); + for (i=0; i<N; i++) { + types->insert(this->exceptions[i]); + } +} + +void +Method::Write(FILE* to) +{ + size_t N, i; + + if (this->comment.length() != 0) { + fprintf(to, "%s\n", this->comment.c_str()); + } + + WriteModifiers(to, this->modifiers, SCOPE_MASK | STATIC | FINAL); + + if (this->returnType != NULL) { + string dim; + for (i=0; i<this->returnTypeDimension; i++) { + dim += "[]"; + } + fprintf(to, "%s%s ", this->returnType->QualifiedName().c_str(), + dim.c_str()); + } + + fprintf(to, "%s(", this->name.c_str()); + + N = this->parameters.size(); + for (i=0; i<N; i++) { + this->parameters[i]->WriteDeclaration(to); + if (i != N-1) { + fprintf(to, ", "); + } + } + + fprintf(to, ")"); + + N = this->exceptions.size(); + for (i=0; i<N; i++) { + if (i == 0) { + fprintf(to, " throws "); + } else { + fprintf(to, ", "); + } + fprintf(to, "%s", this->exceptions[i]->QualifiedName().c_str()); + } + + if (this->statements == NULL) { + fprintf(to, ";\n"); + } else { + fprintf(to, "\n"); + this->statements->Write(to); + } +} + +Class::Class() + :modifiers(0), + what(CLASS), + type(NULL), + extends(NULL) +{ +} + +Class::~Class() +{ +} + +void +Class::GatherTypes(set<Type*>* types) const +{ + int N, i; + + types->insert(this->type); + if (this->extends != NULL) { + types->insert(this->extends); + } + + N = this->interfaces.size(); + for (i=0; i<N; i++) { + types->insert(this->interfaces[i]); + } + + N = this->elements.size(); + for (i=0; i<N; i++) { + this->elements[i]->GatherTypes(types); + } +} + +void +Class::Write(FILE* to) +{ + size_t N, i; + + if (this->comment.length() != 0) { + fprintf(to, "%s\n", this->comment.c_str()); + } + + WriteModifiers(to, this->modifiers, ALL_MODIFIERS); + + if (this->what == Class::CLASS) { + fprintf(to, "class "); + } else { + fprintf(to, "interface "); + } + + string name = this->type->Name(); + size_t pos = name.rfind('.'); + if (pos != string::npos) { + name = name.c_str() + pos + 1; + } + + fprintf(to, "%s", name.c_str()); + + if (this->extends != NULL) { + fprintf(to, " extends %s", this->extends->QualifiedName().c_str()); + } + + N = this->interfaces.size(); + if (N != 0) { + if (this->what == Class::CLASS) { + fprintf(to, " implements"); + } else { + fprintf(to, " extends"); + } + for (i=0; i<N; i++) { + fprintf(to, " %s", this->interfaces[i]->QualifiedName().c_str()); + } + } + + fprintf(to, "\n"); + fprintf(to, "{\n"); + + N = this->elements.size(); + for (i=0; i<N; i++) { + this->elements[i]->Write(to); + } + + fprintf(to, "}\n"); + +} + +Document::Document() +{ +} + +Document::~Document() +{ +} + +static string +escape_backslashes(const string& str) +{ + string result; + const size_t I=str.length(); + for (size_t i=0; i<I; i++) { + char c = str[i]; + if (c == '\\') { + result += "\\\\"; + } else { + result += c; + } + } + return result; +} + +void +Document::Write(FILE* to) +{ + size_t N, i; + + if (this->comment.length() != 0) { + fprintf(to, "%s\n", this->comment.c_str()); + } + fprintf(to, "/*\n" + " * This file is auto-generated. DO NOT MODIFY.\n" + " * Original file: %s\n" + " */\n", escape_backslashes(this->originalSrc).c_str()); + if (this->package.length() != 0) { + fprintf(to, "package %s;\n", this->package.c_str()); + } + + // gather the types for the import statements + set<Type*> types; + N = this->classes.size(); + for (i=0; i<N; i++) { + Class* c = this->classes[i]; + c->GatherTypes(&types); + } + + set<Type*>::iterator it; + for (it=types.begin(); it!=types.end(); it++) { + Type* t = *it; + string pkg = t->Package(); + if (pkg.length() != 0 && pkg != this->package) { + fprintf(to, "import %s;\n", t->ImportType().c_str()); + } + } + + N = this->classes.size(); + for (i=0; i<N; i++) { + Class* c = this->classes[i]; + c->Write(to); + } +} + diff --git a/tools/aidl/AST.h b/tools/aidl/AST.h new file mode 100755 index 0000000..1dedd04 --- /dev/null +++ b/tools/aidl/AST.h @@ -0,0 +1,346 @@ +#ifndef AIDL_AST_H +#define AIDL_AST_H + +#include <string> +#include <vector> +#include <set> +#include <stdarg.h> + +using namespace std; + +class Type; + +enum { + PACKAGE_PRIVATE = 0x00000000, + PUBLIC = 0x00000001, + PRIVATE = 0x00000002, + PROTECTED = 0x00000003, + SCOPE_MASK = 0x00000003, + + STATIC = 0x00000010, + FINAL = 0x00000020, + ABSTRACT = 0x00000040, + + ALL_MODIFIERS = 0xffffffff +}; + +// Write the modifiers that are set in both mod and mask +void WriteModifiers(FILE* to, int mod, int mask); + +struct ClassElement +{ + ClassElement(); + virtual ~ClassElement(); + + virtual void GatherTypes(set<Type*>* types) const = 0; + virtual void Write(FILE* to) = 0; +}; + +struct Expression +{ + virtual ~Expression(); + virtual void Write(FILE* to) = 0; +}; + +struct LiteralExpression : public Expression +{ + string value; + + LiteralExpression(const string& value); + virtual ~LiteralExpression(); + virtual void Write(FILE* to); +}; + +struct Variable : public Expression +{ + Type* type; + string name; + int dimension; + + Variable(); + Variable(Type* type, const string& name); + Variable(Type* type, const string& name, int dimension); + virtual ~Variable(); + + virtual void GatherTypes(set<Type*>* types) const; + void WriteDeclaration(FILE* to); + void Write(FILE* to); +}; + +struct FieldVariable : public Expression +{ + Expression* object; + Type* clazz; + string name; + + FieldVariable(Expression* object, const string& name); + FieldVariable(Type* clazz, const string& name); + virtual ~FieldVariable(); + + void Write(FILE* to); +}; + +struct Field : public ClassElement +{ + string comment; + int modifiers; + Variable *variable; + string value; + + Field(); + Field(int modifiers, Variable* variable); + virtual ~Field(); + + virtual void GatherTypes(set<Type*>* types) const; + virtual void Write(FILE* to); +}; + +struct Statement +{ + virtual ~Statement(); + virtual void Write(FILE* to) = 0; +}; + +struct StatementBlock +{ + vector<Statement*> statements; + + StatementBlock(); + virtual ~StatementBlock(); + virtual void Write(FILE* to); + + void Add(Statement* statement); + void Add(Expression* expression); +}; + +struct ExpressionStatement : public Statement +{ + Expression* expression; + + ExpressionStatement(Expression* expression); + virtual ~ExpressionStatement(); + virtual void Write(FILE* to); +}; + +struct Assignment : public Expression +{ + Variable* lvalue; + Expression* rvalue; + Type* cast; + + Assignment(Variable* lvalue, Expression* rvalue); + Assignment(Variable* lvalue, Expression* rvalue, Type* cast); + virtual ~Assignment(); + virtual void Write(FILE* to); +}; + +struct MethodCall : public Expression +{ + Expression* obj; + Type* clazz; + string name; + vector<Expression*> arguments; + vector<string> exceptions; + + MethodCall(const string& name); + MethodCall(Expression* obj, const string& name); + MethodCall(Type* clazz, const string& name); + MethodCall(Expression* obj, const string& name, int argc, ...); + MethodCall(Type* clazz, const string& name, int argc, ...); + virtual ~MethodCall(); + virtual void Write(FILE* to); + +private: + void init(int n, va_list args); +}; + +struct Comparison : public Expression +{ + Expression* lvalue; + string op; + Expression* rvalue; + + Comparison(Expression* lvalue, const string& op, Expression* rvalue); + virtual ~Comparison(); + virtual void Write(FILE* to); +}; + +struct NewExpression : public Expression +{ + Type* type; + vector<Expression*> arguments; + + NewExpression(Type* type); + virtual ~NewExpression(); + virtual void Write(FILE* to); +}; + +struct NewArrayExpression : public Expression +{ + Type* type; + Expression* size; + + NewArrayExpression(Type* type, Expression* size); + virtual ~NewArrayExpression(); + virtual void Write(FILE* to); +}; + +struct Ternary : public Expression +{ + Expression* condition; + Expression* ifpart; + Expression* elsepart; + + Ternary(); + Ternary(Expression* condition, Expression* ifpart, Expression* elsepart); + virtual ~Ternary(); + virtual void Write(FILE* to); +}; + +struct Cast : public Expression +{ + Type* type; + Expression* expression; + + Cast(); + Cast(Type* type, Expression* expression); + virtual ~Cast(); + virtual void Write(FILE* to); +}; + +struct VariableDeclaration : public Statement +{ + Variable* lvalue; + Type* cast; + Expression* rvalue; + + VariableDeclaration(Variable* lvalue); + VariableDeclaration(Variable* lvalue, Expression* rvalue, Type* cast = NULL); + virtual ~VariableDeclaration(); + virtual void Write(FILE* to); +}; + +struct IfStatement : public Statement +{ + Expression* expression; + StatementBlock* statements; + IfStatement* elseif; + + IfStatement(); + virtual ~IfStatement(); + virtual void Write(FILE* to); +}; + +struct ReturnStatement : public Statement +{ + Expression* expression; + + ReturnStatement(Expression* expression); + virtual ~ReturnStatement(); + virtual void Write(FILE* to); +}; + +struct TryStatement : public Statement +{ + StatementBlock* statements; + + TryStatement(); + virtual ~TryStatement(); + virtual void Write(FILE* to); +}; + +struct CatchStatement : public Statement +{ + StatementBlock* statements; + Variable* exception; + + CatchStatement(Variable* exception); + virtual ~CatchStatement(); + virtual void Write(FILE* to); +}; + +struct FinallyStatement : public Statement +{ + StatementBlock* statements; + + FinallyStatement(); + virtual ~FinallyStatement(); + virtual void Write(FILE* to); +}; + +struct Case +{ + vector<string> cases; + StatementBlock* statements; + + Case(); + Case(const string& c); + virtual ~Case(); + virtual void Write(FILE* to); +}; + +struct SwitchStatement : public Statement +{ + Expression* expression; + vector<Case*> cases; + + SwitchStatement(Expression* expression); + virtual ~SwitchStatement(); + virtual void Write(FILE* to); +}; + +struct Method : public ClassElement +{ + string comment; + int modifiers; + Type* returnType; + size_t returnTypeDimension; + string name; + vector<Variable*> parameters; + vector<Type*> exceptions; + StatementBlock* statements; + + Method(); + virtual ~Method(); + + virtual void GatherTypes(set<Type*>* types) const; + virtual void Write(FILE* to); +}; + +struct Class : public ClassElement +{ + enum { + CLASS, + INTERFACE + }; + + string comment; + int modifiers; + int what; // CLASS or INTERFACE + Type* type; + Type* extends; + vector<Type*> interfaces; + vector<ClassElement*> elements; + + Class(); + virtual ~Class(); + + virtual void GatherTypes(set<Type*>* types) const; + virtual void Write(FILE* to); +}; + +struct Document +{ + string comment; + string package; + string originalSrc; + set<Type*> imports; + vector<Class*> classes; + + Document(); + virtual ~Document(); + + virtual void Write(FILE* to); +}; + +#endif // AIDL_AST_H diff --git a/tools/aidl/Android.mk b/tools/aidl/Android.mk new file mode 100644 index 0000000..944aeb6 --- /dev/null +++ b/tools/aidl/Android.mk @@ -0,0 +1,24 @@ +# Copyright 2007 The Android Open Source Project +# +# Copies files into the directory structure described by a manifest + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + aidl_language_l.l \ + aidl_language_y.y \ + aidl.cpp \ + aidl_language.cpp \ + options.cpp \ + search_path.cpp \ + AST.cpp \ + Type.cpp \ + generate_java.cpp + +LOCAL_CFLAGS := -g +LOCAL_MODULE := aidl + +include $(BUILD_HOST_EXECUTABLE) + + diff --git a/tools/aidl/Type.cpp b/tools/aidl/Type.cpp new file mode 100755 index 0000000..a44072d --- /dev/null +++ b/tools/aidl/Type.cpp @@ -0,0 +1,1228 @@ +#include "Type.h" + +Namespace NAMES; + +Type* VOID_TYPE; +Type* BOOLEAN_TYPE; +Type* BYTE_TYPE; +Type* CHAR_TYPE; +Type* INT_TYPE; +Type* LONG_TYPE; +Type* FLOAT_TYPE; +Type* DOUBLE_TYPE; +Type* STRING_TYPE; +Type* CHAR_SEQUENCE_TYPE; +Type* TEXT_UTILS_TYPE; +Type* REMOTE_EXCEPTION_TYPE; +Type* RUNTIME_EXCEPTION_TYPE; +Type* IBINDER_TYPE; +Type* IINTERFACE_TYPE; +Type* BINDER_NATIVE_TYPE; +Type* BINDER_PROXY_TYPE; +Type* PARCEL_TYPE; +Type* PARCELABLE_INTERFACE_TYPE; +Type* MAP_TYPE; +Type* LIST_TYPE; +Type* CLASSLOADER_TYPE; + +Expression* NULL_VALUE; +Expression* THIS_VALUE; +Expression* SUPER_VALUE; +Expression* TRUE_VALUE; +Expression* FALSE_VALUE; + +void +register_base_types() +{ + VOID_TYPE = new BasicType("void", "XXX", "XXX", "XXX", "XXX", "XXX"); + NAMES.Add(VOID_TYPE); + + BOOLEAN_TYPE = new BooleanType(); + NAMES.Add(BOOLEAN_TYPE); + + BYTE_TYPE = new BasicType("byte", "writeByte", "readByte", + "writeByteArray", "createByteArray", "readByteArray"); + NAMES.Add(BYTE_TYPE); + + CHAR_TYPE = new CharType(); + NAMES.Add(CHAR_TYPE); + + INT_TYPE = new BasicType("int", "writeInt", "readInt", + "writeIntArray", "createIntArray", "readIntArray"); + NAMES.Add(INT_TYPE); + + LONG_TYPE = new BasicType("long", "writeLong", "readLong", + "writeLongArray", "createLongArray", "readLongArray"); + NAMES.Add(LONG_TYPE); + + FLOAT_TYPE = new BasicType("float", "writeFloat", "readFloat", + "writeFloatArray", "createFloatArray", "readFloatArray"); + NAMES.Add(FLOAT_TYPE); + + DOUBLE_TYPE = new BasicType("double", "writeDouble", "readDouble", + "writeDoubleArray", "createDoubleArray", "readDoubleArray"); + NAMES.Add(DOUBLE_TYPE); + + STRING_TYPE = new StringType(); + NAMES.Add(STRING_TYPE); + + CHAR_SEQUENCE_TYPE = new CharSequenceType(); + NAMES.Add(CHAR_SEQUENCE_TYPE); + + MAP_TYPE = new MapType(); + NAMES.Add(MAP_TYPE); + + LIST_TYPE = new ListType(); + NAMES.Add(LIST_TYPE); + + TEXT_UTILS_TYPE = new Type("android.text", "TextUtils", + Type::BUILT_IN, false, false); + NAMES.Add(TEXT_UTILS_TYPE); + + REMOTE_EXCEPTION_TYPE = new RemoteExceptionType(); + NAMES.Add(REMOTE_EXCEPTION_TYPE); + + RUNTIME_EXCEPTION_TYPE = new RuntimeExceptionType(); + NAMES.Add(RUNTIME_EXCEPTION_TYPE); + + IBINDER_TYPE = new IBinderType(); + NAMES.Add(IBINDER_TYPE); + + IINTERFACE_TYPE = new IInterfaceType(); + NAMES.Add(IINTERFACE_TYPE); + + BINDER_NATIVE_TYPE = new BinderType(); + NAMES.Add(BINDER_NATIVE_TYPE); + + BINDER_PROXY_TYPE = new BinderProxyType(); + NAMES.Add(BINDER_PROXY_TYPE); + + PARCEL_TYPE = new ParcelType(); + NAMES.Add(PARCEL_TYPE); + + PARCELABLE_INTERFACE_TYPE = new ParcelableInterfaceType(); + NAMES.Add(PARCELABLE_INTERFACE_TYPE); + + CLASSLOADER_TYPE = new ClassLoaderType(); + NAMES.Add(CLASSLOADER_TYPE); + + NULL_VALUE = new LiteralExpression("null"); + THIS_VALUE = new LiteralExpression("this"); + SUPER_VALUE = new LiteralExpression("super"); + TRUE_VALUE = new LiteralExpression("true"); + FALSE_VALUE = new LiteralExpression("false"); + + NAMES.AddGenericType("java.util", "List", 1); + NAMES.AddGenericType("java.util", "Map", 2); +} + +static Type* +make_generic_type(const string& package, const string& name, + const vector<Type*>& args) +{ + if (package == "java.util" && name == "List") { + return new GenericListType("java.util", "List", args); + } + return NULL; + //return new GenericType(package, name, args); +} + +// ================================================================ + +Type::Type(const string& name, int kind, bool canWriteToParcel, bool canBeOut) + :m_package(), + m_name(name), + m_declFile(""), + m_declLine(-1), + m_kind(kind), + m_canWriteToParcel(canWriteToParcel), + m_canBeOut(canBeOut) +{ + m_qualifiedName = name; +} + +Type::Type(const string& package, const string& name, + int kind, bool canWriteToParcel, bool canBeOut, + const string& declFile, int declLine) + :m_package(package), + m_name(name), + m_declFile(declFile), + m_declLine(declLine), + m_kind(kind), + m_canWriteToParcel(canWriteToParcel), + m_canBeOut(canBeOut) +{ + if (package.length() > 0) { + m_qualifiedName = package; + m_qualifiedName += '.'; + } + m_qualifiedName += name; +} + +Type::~Type() +{ +} + +bool +Type::CanBeArray() const +{ + return false; +} + +string +Type::ImportType() const +{ + return m_qualifiedName; +} + +string +Type::CreatorName() const +{ + return ""; +} + +string +Type::InstantiableName() const +{ + return QualifiedName(); +} + + +void +Type::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) +{ + fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%sn", + __FILE__, __LINE__, m_qualifiedName.c_str()); + addTo->Add(new LiteralExpression("/* WriteToParcel error " + + m_qualifiedName + " */")); +} + +void +Type::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel) +{ + fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n", + __FILE__, __LINE__, m_qualifiedName.c_str()); + addTo->Add(new LiteralExpression("/* CreateFromParcel error " + + m_qualifiedName + " */")); +} + +void +Type::ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel) +{ + fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n", + __FILE__, __LINE__, m_qualifiedName.c_str()); + addTo->Add(new LiteralExpression("/* ReadFromParcel error " + + m_qualifiedName + " */")); +} + +void +Type::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) +{ + fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n", + __FILE__, __LINE__, m_qualifiedName.c_str()); + addTo->Add(new LiteralExpression("/* WriteArrayToParcel error " + + m_qualifiedName + " */")); +} + +void +Type::CreateArrayFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel) +{ + fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n", + __FILE__, __LINE__, m_qualifiedName.c_str()); + addTo->Add(new LiteralExpression("/* CreateArrayFromParcel error " + + m_qualifiedName + " */")); +} + +void +Type::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel) +{ + fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n", + __FILE__, __LINE__, m_qualifiedName.c_str()); + addTo->Add(new LiteralExpression("/* ReadArrayFromParcel error " + + m_qualifiedName + " */")); +} + +void +Type::SetQualifiedName(const string& qualified) +{ + m_qualifiedName = qualified; +} + +Expression* +Type::BuildWriteToParcelFlags(int flags) +{ + if (flags == 0) { + return new LiteralExpression("0"); + } + if ((flags&PARCELABLE_WRITE_RETURN_VALUE) != 0) { + return new FieldVariable(PARCELABLE_INTERFACE_TYPE, + "PARCELABLE_WRITE_RETURN_VALUE"); + } + return new LiteralExpression("0"); +} + +// ================================================================ + +BasicType::BasicType(const string& name, const string& marshallMethod, + const string& unmarshallMethod, + const string& writeArray, const string& createArray, + const string& readArray) + :Type(name, BUILT_IN, true, false), + m_marshallMethod(marshallMethod), + m_unmarshallMethod(unmarshallMethod), + m_writeArrayMethod(writeArray), + m_createArrayMethod(createArray), + m_readArrayMethod(readArray) +{ +} + +void +BasicType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) +{ + addTo->Add(new MethodCall(parcel, m_marshallMethod, 1, v)); +} + +void +BasicType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel) +{ + addTo->Add(new Assignment(v, new MethodCall(parcel, m_unmarshallMethod))); +} + +bool +BasicType::CanBeArray() const +{ + return true; +} + +void +BasicType::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) +{ + addTo->Add(new MethodCall(parcel, m_writeArrayMethod, 1, v)); +} + +void +BasicType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel) +{ + addTo->Add(new Assignment(v, new MethodCall(parcel, m_createArrayMethod))); +} + +void +BasicType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel) +{ + addTo->Add(new MethodCall(parcel, m_readArrayMethod, 1, v)); +} + + +// ================================================================ + +BooleanType::BooleanType() + :Type("boolean", BUILT_IN, true, false) +{ +} + +void +BooleanType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) +{ + addTo->Add(new MethodCall(parcel, "writeInt", 1, + new Ternary(v, new LiteralExpression("1"), + new LiteralExpression("0")))); +} + +void +BooleanType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel) +{ + addTo->Add(new Assignment(v, new Comparison(new LiteralExpression("0"), + "!=", new MethodCall(parcel, "readInt")))); +} + +bool +BooleanType::CanBeArray() const +{ + return true; +} + +void +BooleanType::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) +{ + addTo->Add(new MethodCall(parcel, "writeBooleanArray", 1, v)); +} + +void +BooleanType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel) +{ + addTo->Add(new Assignment(v, new MethodCall(parcel, "createBooleanArray"))); +} + +void +BooleanType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel) +{ + addTo->Add(new MethodCall(parcel, "readBooleanArray", 1, v)); +} + + +// ================================================================ + +CharType::CharType() + :Type("char", BUILT_IN, true, false) +{ +} + +void +CharType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) +{ + addTo->Add(new MethodCall(parcel, "writeInt", 1, + new Cast(INT_TYPE, v))); +} + +void +CharType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel) +{ + addTo->Add(new Assignment(v, new MethodCall(parcel, "readInt"), this)); +} + +bool +CharType::CanBeArray() const +{ + return true; +} + +void +CharType::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) +{ + addTo->Add(new MethodCall(parcel, "writeCharArray", 1, v)); +} + +void +CharType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel) +{ + addTo->Add(new Assignment(v, new MethodCall(parcel, "createCharArray"))); +} + +void +CharType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel) +{ + addTo->Add(new MethodCall(parcel, "readCharArray", 1, v)); +} + +// ================================================================ + +StringType::StringType() + :Type("java.lang", "String", BUILT_IN, true, false) +{ +} + +string +StringType::CreatorName() const +{ + return "android.os.Parcel.STRING_CREATOR"; +} + +void +StringType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) +{ + addTo->Add(new MethodCall(parcel, "writeString", 1, v)); +} + +void +StringType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel) +{ + addTo->Add(new Assignment(v, new MethodCall(parcel, "readString"))); +} + +bool +StringType::CanBeArray() const +{ + return true; +} + +void +StringType::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) +{ + addTo->Add(new MethodCall(parcel, "writeStringArray", 1, v)); +} + +void +StringType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel) +{ + addTo->Add(new Assignment(v, new MethodCall(parcel, "createStringArray"))); +} + +void +StringType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel) +{ + addTo->Add(new MethodCall(parcel, "readStringArray", 1, v)); +} + +// ================================================================ + +CharSequenceType::CharSequenceType() + :Type("java.lang", "CharSequence", BUILT_IN, true, false) +{ +} + +string +CharSequenceType::CreatorName() const +{ + return "android.os.Parcel.STRING_CREATOR"; +} + +void +CharSequenceType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) +{ + // if (v != null) { + // parcel.writeInt(1); + // v.writeToParcel(parcel); + // } else { + // parcel.writeInt(0); + // } + IfStatement* elsepart = new IfStatement(); + elsepart->statements->Add(new MethodCall(parcel, "writeInt", 1, + new LiteralExpression("0"))); + IfStatement* ifpart = new IfStatement; + ifpart->expression = new Comparison(v, "!=", NULL_VALUE); + ifpart->elseif = elsepart; + ifpart->statements->Add(new MethodCall(parcel, "writeInt", 1, + new LiteralExpression("1"))); + ifpart->statements->Add(new MethodCall(TEXT_UTILS_TYPE, "writeToParcel", + 3, v, parcel, BuildWriteToParcelFlags(flags))); + + addTo->Add(ifpart); +} + +void +CharSequenceType::CreateFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel) +{ + // if (0 != parcel.readInt()) { + // v = TextUtils.createFromParcel(parcel) + // } else { + // v = null; + // } + IfStatement* elsepart = new IfStatement(); + elsepart->statements->Add(new Assignment(v, NULL_VALUE)); + + IfStatement* ifpart = new IfStatement(); + ifpart->expression = new Comparison(new LiteralExpression("0"), "!=", + new MethodCall(parcel, "readInt")); + ifpart->elseif = elsepart; + ifpart->statements->Add(new Assignment(v, + new MethodCall(TEXT_UTILS_TYPE, + "CHAR_SEQUENCE_CREATOR.createFromParcel", 1, parcel))); + + addTo->Add(ifpart); +} + + +// ================================================================ + +RemoteExceptionType::RemoteExceptionType() + :Type("android.os", "RemoteException", BUILT_IN, false, false) +{ +} + +void +RemoteExceptionType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) +{ + fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__); +} + +void +RemoteExceptionType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel) +{ + fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__); +} + +// ================================================================ + +RuntimeExceptionType::RuntimeExceptionType() + :Type("java.lang", "RuntimeException", BUILT_IN, false, false) +{ +} + +void +RuntimeExceptionType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) +{ + fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__); +} + +void +RuntimeExceptionType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel) +{ + fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__); +} + + +// ================================================================ + +IBinderType::IBinderType() + :Type("android.os", "IBinder", BUILT_IN, true, false) +{ +} + +void +IBinderType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) +{ + addTo->Add(new MethodCall(parcel, "writeStrongBinder", 1, v)); +} + +void +IBinderType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel) +{ + addTo->Add(new Assignment(v, new MethodCall(parcel, "readStrongBinder"))); +} + +void +IBinderType::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) +{ + addTo->Add(new MethodCall(parcel, "writeBinderArray", 1, v)); +} + +void +IBinderType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel) +{ + addTo->Add(new Assignment(v, new MethodCall(parcel, "createBinderArray"))); +} + +void +IBinderType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel) +{ + addTo->Add(new MethodCall(parcel, "readBinderArray", 1, v)); +} + + +// ================================================================ + +IInterfaceType::IInterfaceType() + :Type("android.os", "IInterface", BUILT_IN, false, false) +{ +} + +void +IInterfaceType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) +{ + fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__); +} + +void +IInterfaceType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel) +{ + fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__); +} + + +// ================================================================ + +BinderType::BinderType() + :Type("android.os", "Binder", BUILT_IN, false, false) +{ +} + +void +BinderType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) +{ + fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__); +} + +void +BinderType::CreateFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel) +{ + fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__); +} + + +// ================================================================ + +BinderProxyType::BinderProxyType() + :Type("android.os", "BinderProxy", BUILT_IN, false, false) +{ +} + +void +BinderProxyType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) +{ + fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__); +} + +void +BinderProxyType::CreateFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel) +{ + fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__); +} + + +// ================================================================ + +ParcelType::ParcelType() + :Type("android.os", "Parcel", BUILT_IN, false, false) +{ +} + +void +ParcelType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) +{ + fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__); +} + +void +ParcelType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel) +{ + fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__); +} + +// ================================================================ + +ParcelableInterfaceType::ParcelableInterfaceType() + :Type("android.os", "Parcelable", BUILT_IN, false, false) +{ +} + +void +ParcelableInterfaceType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) +{ + fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__); +} + +void +ParcelableInterfaceType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel) +{ + fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__); +} + +// ================================================================ + +MapType::MapType() + :Type("java.util", "Map", BUILT_IN, true, true) +{ +} + +void +MapType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) +{ + addTo->Add(new MethodCall(parcel, "writeMap", 1, v)); +} + +void +MapType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel) +{ + Variable *cl = new Variable(CLASSLOADER_TYPE, "cl"); + addTo->Add(new VariableDeclaration(cl, + new LiteralExpression("this.getClass().getClassLoader()"), + CLASSLOADER_TYPE)); + addTo->Add(new Assignment(v, new MethodCall(parcel, "readHashMap", 1, cl))); +} + +void +MapType::ReadFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel) +{ + Variable *cl = new Variable(CLASSLOADER_TYPE, "cl"); + addTo->Add(new VariableDeclaration(cl, + new LiteralExpression("this.getClass().getClassLoader()"), + CLASSLOADER_TYPE)); + addTo->Add(new MethodCall(parcel, "readMap", 2, v, cl)); +} + + +// ================================================================ + +ListType::ListType() + :Type("java.util", "List", BUILT_IN, true, true) +{ +} + +string +ListType::InstantiableName() const +{ + return "java.util.ArrayList"; +} + +void +ListType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) +{ + addTo->Add(new MethodCall(parcel, "writeList", 1, v)); +} + +void +ListType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel) +{ + Variable *cl = new Variable(CLASSLOADER_TYPE, "cl"); + addTo->Add(new VariableDeclaration(cl, + new LiteralExpression("this.getClass().getClassLoader()"), + CLASSLOADER_TYPE)); + addTo->Add(new Assignment(v, new MethodCall(parcel, "readArrayList", 1, cl))); +} + +void +ListType::ReadFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel) +{ + Variable *cl = new Variable(CLASSLOADER_TYPE, "cl"); + addTo->Add(new VariableDeclaration(cl, + new LiteralExpression("this.getClass().getClassLoader()"), + CLASSLOADER_TYPE)); + addTo->Add(new MethodCall(parcel, "readList", 2, v, cl)); +} + + +// ================================================================ + +ParcelableType::ParcelableType(const string& package, const string& name, + bool builtIn, const string& declFile, int declLine) + :Type(package, name, builtIn ? BUILT_IN : PARCELABLE, true, true, + declFile, declLine) +{ +} + +string +ParcelableType::CreatorName() const +{ + return QualifiedName() + ".CREATOR"; +} + +void +ParcelableType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) +{ + // if (v != null) { + // parcel.writeInt(1); + // v.writeToParcel(parcel); + // } else { + // parcel.writeInt(0); + // } + IfStatement* elsepart = new IfStatement(); + elsepart->statements->Add(new MethodCall(parcel, "writeInt", 1, + new LiteralExpression("0"))); + IfStatement* ifpart = new IfStatement; + ifpart->expression = new Comparison(v, "!=", NULL_VALUE); + ifpart->elseif = elsepart; + ifpart->statements->Add(new MethodCall(parcel, "writeInt", 1, + new LiteralExpression("1"))); + ifpart->statements->Add(new MethodCall(v, "writeToParcel", 2, + parcel, BuildWriteToParcelFlags(flags))); + + addTo->Add(ifpart); +} + +void +ParcelableType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel) +{ + // if (0 != parcel.readInt()) { + // v = CLASS.CREATOR.createFromParcel(parcel) + // } else { + // v = null; + // } + IfStatement* elsepart = new IfStatement(); + elsepart->statements->Add(new Assignment(v, NULL_VALUE)); + + IfStatement* ifpart = new IfStatement(); + ifpart->expression = new Comparison(new LiteralExpression("0"), "!=", + new MethodCall(parcel, "readInt")); + ifpart->elseif = elsepart; + ifpart->statements->Add(new Assignment(v, + new MethodCall(v->type, "CREATOR.createFromParcel", 1, parcel))); + + addTo->Add(ifpart); +} + +void +ParcelableType::ReadFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel) +{ + // TODO: really, we don't need to have this extra check, but we + // don't have two separate marshalling code paths + // if (0 != parcel.readInt()) { + // v.readFromParcel(parcel) + // } + IfStatement* ifpart = new IfStatement(); + ifpart->expression = new Comparison(new LiteralExpression("0"), "!=", + new MethodCall(parcel, "readInt")); + ifpart->statements->Add(new MethodCall(v, "readFromParcel", 1, parcel)); + addTo->Add(ifpart); +} + +bool +ParcelableType::CanBeArray() const +{ + return true; +} + +void +ParcelableType::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) +{ + addTo->Add(new MethodCall(parcel, "writeTypedArray", 2, v, + BuildWriteToParcelFlags(flags))); +} + +void +ParcelableType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel) +{ + string creator = v->type->QualifiedName() + ".CREATOR"; + addTo->Add(new Assignment(v, new MethodCall(parcel, + "createTypedArray", 1, new LiteralExpression(creator)))); +} + +void +ParcelableType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel) +{ + string creator = v->type->QualifiedName() + ".CREATOR"; + addTo->Add(new MethodCall(parcel, "readTypedArray", 2, + v, new LiteralExpression(creator))); +} + + +// ================================================================ + +InterfaceType::InterfaceType(const string& package, const string& name, + bool builtIn, bool oneway, + const string& declFile, int declLine) + :Type(package, name, builtIn ? BUILT_IN : INTERFACE, true, false, + declFile, declLine) + ,m_oneway(oneway) +{ +} + +bool +InterfaceType::OneWay() const +{ + return m_oneway; +} + +void +InterfaceType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) +{ + // parcel.writeStrongBinder(v != null ? v.asBinder() : null); + addTo->Add(new MethodCall(parcel, "writeStrongBinder", 1, + new Ternary( + new Comparison(v, "!=", NULL_VALUE), + new MethodCall(v, "asBinder"), + NULL_VALUE))); +} + +void +InterfaceType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel) +{ + // v = Interface.asInterface(parcel.readStrongBinder()); + string type = v->type->QualifiedName(); + type += ".Stub"; + addTo->Add(new Assignment(v, + new MethodCall( NAMES.Find(type), "asInterface", 1, + new MethodCall(parcel, "readStrongBinder")))); +} + + +// ================================================================ + +GenericType::GenericType(const string& package, const string& name, + const vector<Type*>& args) + :Type(package, name, BUILT_IN, true, true) +{ + m_args = args; + + m_importName = package + '.' + name; + + string gen = "<"; + int N = args.size(); + for (int i=0; i<N; i++) { + Type* t = args[i]; + gen += t->QualifiedName(); + if (i != N-1) { + gen += ','; + } + } + gen += '>'; + m_genericArguments = gen; + SetQualifiedName(m_importName + gen); +} + +string +GenericType::GenericArguments() const +{ + return m_genericArguments; +} + +string +GenericType::ImportType() const +{ + return m_importName; +} + +void +GenericType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) +{ + fprintf(stderr, "implement GenericType::WriteToParcel\n"); +} + +void +GenericType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel) +{ + fprintf(stderr, "implement GenericType::CreateFromParcel\n"); +} + +void +GenericType::ReadFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel) +{ + fprintf(stderr, "implement GenericType::ReadFromParcel\n"); +} + + +// ================================================================ + +GenericListType::GenericListType(const string& package, const string& name, + const vector<Type*>& args) + :GenericType(package, name, args), + m_creator(args[0]->CreatorName()) +{ +} + +string +GenericListType::CreatorName() const +{ + return "android.os.Parcel.arrayListCreator"; +} + +string +GenericListType::InstantiableName() const +{ + return "java.util.ArrayList" + GenericArguments(); +} + +void +GenericListType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) +{ + if (m_creator == STRING_TYPE->CreatorName()) { + addTo->Add(new MethodCall(parcel, "writeStringList", 1, v)); + } else if (m_creator == IBINDER_TYPE->CreatorName()) { + addTo->Add(new MethodCall(parcel, "writeBinderList", 1, v)); + } else { + // parcel.writeTypedListXX(arg); + addTo->Add(new MethodCall(parcel, "writeTypedList", 1, v)); + } +} + +void +GenericListType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel) +{ + if (m_creator == STRING_TYPE->CreatorName()) { + addTo->Add(new Assignment(v, + new MethodCall(parcel, "createStringArrayList", 0))); + } else if (m_creator == IBINDER_TYPE->CreatorName()) { + addTo->Add(new Assignment(v, + new MethodCall(parcel, "createBinderArrayList", 0))); + } else { + // v = _data.readTypedArrayList(XXX.creator); + addTo->Add(new Assignment(v, + new MethodCall(parcel, "createTypedArrayList", 1, + new LiteralExpression(m_creator)))); + } +} + +void +GenericListType::ReadFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel) +{ + if (m_creator == STRING_TYPE->CreatorName()) { + addTo->Add(new MethodCall(parcel, "readStringList", 1, v)); + } else if (m_creator == IBINDER_TYPE->CreatorName()) { + addTo->Add(new MethodCall(parcel, "readBinderList", 1, v)); + } else { + // v = _data.readTypedList(v, XXX.creator); + addTo->Add(new MethodCall(parcel, "readTypedList", 2, + v, + new LiteralExpression(m_creator))); + } +} + +// ================================================================ + +ClassLoaderType::ClassLoaderType() + :Type("java.lang", "ClassLoader", BUILT_IN, false, false) +{ +} + + +// ================================================================ + +Namespace::Namespace() +{ +} + +Namespace::~Namespace() +{ + int N = m_types.size(); + for (int i=0; i<N; i++) { + delete m_types[i]; + } +} + +void +Namespace::Add(Type* type) +{ + Type* t = Find(type->QualifiedName()); + if (t == NULL) { + m_types.push_back(type); + } +} + +void +Namespace::AddGenericType(const string& package, const string& name, int args) +{ + Generic g; + g.package = package; + g.name = name; + g.qualified = package + '.' + name; + g.args = args; + m_generics.push_back(g); +} + +Type* +Namespace::Find(const string& name) const +{ + int N = m_types.size(); + for (int i=0; i<N; i++) { + if (m_types[i]->QualifiedName() == name) { + return m_types[i]; + } + } + return NULL; +} + +Type* +Namespace::Find(const char* package, const char* name) const +{ + string s; + if (package != NULL) { + s += package; + s += '.'; + } + s += name; + return Find(s); +} + +static string +normalize_generic(const string& s) +{ + string r; + int N = s.size(); + for (int i=0; i<N; i++) { + char c = s[i]; + if (!isspace(c)) { + r += c; + } + } + return r; +} + +Type* +Namespace::Search(const string& name) +{ + // an exact match wins + Type* result = Find(name); + if (result != NULL) { + return result; + } + + // try the class names + // our language doesn't allow you to not specify outer classes + // when referencing an inner class. that could be changed, and this + // would be the place to do it, but I don't think the complexity in + // scoping rules is worth it. + int N = m_types.size(); + for (int i=0; i<N; i++) { + if (m_types[i]->Name() == name) { + return m_types[i]; + } + } + + // we got to here and it's not a generic, give up + if (name.find('<') == name.npos) { + return NULL; + } + + // remove any whitespace + string normalized = normalize_generic(name); + + // find the part before the '<', find a generic for it + ssize_t baseIndex = normalized.find('<'); + string base(normalized.c_str(), baseIndex); + const Generic* g = search_generic(base); + if (g == NULL) { + return NULL; + } + + // For each of the args, do a recursive search on it. We don't allow + // generics within generics like Java does, because we're really limiting + // them to just built-in container classes, at least for now. Our syntax + // ensures this right now as well. + vector<Type*> args; + size_t start = baseIndex + 1; + size_t end = start; + while (normalized[start] != '\0') { + end = normalized.find(',', start); + if (end == normalized.npos) { + end = normalized.find('>', start); + } + string s(normalized.c_str()+start, end-start); + Type* t = this->Search(s); + if (t == NULL) { + // maybe we should print a warning here? + return NULL; + } + args.push_back(t); + start = end+1; + } + + // construct a GenericType, add it to our name set so they always get + // the same object, and return it. + result = make_generic_type(g->package, g->name, args); + if (result == NULL) { + return NULL; + } + + this->Add(result); + return this->Find(result->QualifiedName()); +} + +const Namespace::Generic* +Namespace::search_generic(const string& name) const +{ + int N = m_generics.size(); + + // first exact match + for (int i=0; i<N; i++) { + const Generic& g = m_generics[i]; + if (g.qualified == name) { + return &g; + } + } + + // then name match + for (int i=0; i<N; i++) { + const Generic& g = m_generics[i]; + if (g.name == name) { + return &g; + } + } + + return NULL; +} + +void +Namespace::Dump() const +{ + int n = m_types.size(); + for (int i=0; i<n; i++) { + Type* t = m_types[i]; + printf("type: package=%s name=%s qualifiedName=%s\n", + t->Package().c_str(), t->Name().c_str(), + t->QualifiedName().c_str()); + } +} diff --git a/tools/aidl/Type.h b/tools/aidl/Type.h new file mode 100755 index 0000000..2ea3ac9 --- /dev/null +++ b/tools/aidl/Type.h @@ -0,0 +1,466 @@ +#ifndef AIDL_TYPE_H +#define AIDL_TYPE_H + +#include "AST.h" +#include <string> +#include <vector> + +using namespace std; + +class Type +{ +public: + // kinds + enum { + BUILT_IN, + PARCELABLE, + INTERFACE, + GENERATED + }; + + // WriteToParcel flags + enum { + PARCELABLE_WRITE_RETURN_VALUE = 0x0001 + }; + + Type(const string& name, int kind, bool canWriteToParcel, + bool canBeOut); + Type(const string& package, const string& name, + int kind, bool canWriteToParcel, bool canBeOut, + const string& declFile = "", int declLine = -1); + virtual ~Type(); + + inline string Package() const { return m_package; } + inline string Name() const { return m_name; } + inline string QualifiedName() const { return m_qualifiedName; } + inline int Kind() const { return m_kind; } + inline string DeclFile() const { return m_declFile; } + inline int DeclLine() const { return m_declLine; } + inline bool CanBeMarshalled() const { return m_canWriteToParcel; } + inline bool CanBeOutParameter() const { return m_canBeOut; } + + virtual string ImportType() const; + virtual string CreatorName() const; + virtual string InstantiableName() const; + + virtual void WriteToParcel(StatementBlock* addTo, Variable* v, + Variable* parcel, int flags); + virtual void CreateFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel); + virtual void ReadFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel); + + virtual bool CanBeArray() const; + + virtual void WriteArrayToParcel(StatementBlock* addTo, Variable* v, + Variable* parcel, int flags); + virtual void CreateArrayFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel); + virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel); + +protected: + void SetQualifiedName(const string& qualified); + Expression* BuildWriteToParcelFlags(int flags); + +private: + Type(); + Type(const Type&); + + string m_package; + string m_name; + string m_qualifiedName; + string m_declFile; + int m_declLine; + int m_kind; + bool m_canWriteToParcel; + bool m_canBeOut; +}; + +class BasicType : public Type +{ +public: + BasicType(const string& name, const string& marshallMethod, + const string& unmarshallMethod, + const string& writeArray, + const string& createArray, + const string& readArray); + + virtual void WriteToParcel(StatementBlock* addTo, Variable* v, + Variable* parcel, int flags); + virtual void CreateFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel); + + virtual bool CanBeArray() const; + + virtual void WriteArrayToParcel(StatementBlock* addTo, Variable* v, + Variable* parcel, int flags); + virtual void CreateArrayFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel); + virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel); + +private: + string m_marshallMethod; + string m_unmarshallMethod; + string m_writeArrayMethod; + string m_createArrayMethod; + string m_readArrayMethod; +}; + +class BooleanType : public Type +{ +public: + BooleanType(); + + virtual void WriteToParcel(StatementBlock* addTo, Variable* v, + Variable* parcel, int flags); + virtual void CreateFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel); + + virtual bool CanBeArray() const; + + virtual void WriteArrayToParcel(StatementBlock* addTo, Variable* v, + Variable* parcel, int flags); + virtual void CreateArrayFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel); + virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel); +}; + +class CharType : public Type +{ +public: + CharType(); + + virtual void WriteToParcel(StatementBlock* addTo, Variable* v, + Variable* parcel, int flags); + virtual void CreateFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel); + + virtual bool CanBeArray() const; + + virtual void WriteArrayToParcel(StatementBlock* addTo, Variable* v, + Variable* parcel, int flags); + virtual void CreateArrayFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel); + virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel); +}; + + +class StringType : public Type +{ +public: + StringType(); + + virtual string CreatorName() const; + + virtual void WriteToParcel(StatementBlock* addTo, Variable* v, + Variable* parcel, int flags); + virtual void CreateFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel); + + virtual bool CanBeArray() const; + + virtual void WriteArrayToParcel(StatementBlock* addTo, Variable* v, + Variable* parcel, int flags); + virtual void CreateArrayFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel); + virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel); +}; + +class CharSequenceType : public Type +{ +public: + CharSequenceType(); + + virtual string CreatorName() const; + + virtual void WriteToParcel(StatementBlock* addTo, Variable* v, + Variable* parcel, int flags); + virtual void CreateFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel); +}; + +class RemoteExceptionType : public Type +{ +public: + RemoteExceptionType(); + + virtual void WriteToParcel(StatementBlock* addTo, Variable* v, + Variable* parcel, int flags); + virtual void CreateFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel); +}; + +class RuntimeExceptionType : public Type +{ +public: + RuntimeExceptionType(); + + virtual void WriteToParcel(StatementBlock* addTo, Variable* v, + Variable* parcel, int flags); + virtual void CreateFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel); +}; + +class IBinderType : public Type +{ +public: + IBinderType(); + + virtual void WriteToParcel(StatementBlock* addTo, Variable* v, + Variable* parcel, int flags); + virtual void CreateFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel); + + virtual void WriteArrayToParcel(StatementBlock* addTo, Variable* v, + Variable* parcel, int flags); + virtual void CreateArrayFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel); + virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel); +}; + +class IInterfaceType : public Type +{ +public: + IInterfaceType(); + + virtual void WriteToParcel(StatementBlock* addTo, Variable* v, + Variable* parcel, int flags); + virtual void CreateFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel); +}; + +class BinderType : public Type +{ +public: + BinderType(); + + virtual void WriteToParcel(StatementBlock* addTo, Variable* v, + Variable* parcel, int flags); + virtual void CreateFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel); +}; + +class BinderProxyType : public Type +{ +public: + BinderProxyType(); + + virtual void WriteToParcel(StatementBlock* addTo, Variable* v, + Variable* parcel, int flags); + virtual void CreateFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel); +}; + +class ParcelType : public Type +{ +public: + ParcelType(); + + virtual void WriteToParcel(StatementBlock* addTo, Variable* v, + Variable* parcel, int flags); + virtual void CreateFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel); +}; + +class ParcelableInterfaceType : public Type +{ +public: + ParcelableInterfaceType(); + + virtual void WriteToParcel(StatementBlock* addTo, Variable* v, + Variable* parcel, int flags); + virtual void CreateFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel); +}; + +class MapType : public Type +{ +public: + MapType(); + + virtual void WriteToParcel(StatementBlock* addTo, Variable* v, + Variable* parcel, int flags); + virtual void CreateFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel); + virtual void ReadFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel); +}; + +class ListType : public Type +{ +public: + ListType(); + + virtual string InstantiableName() const; + + virtual void WriteToParcel(StatementBlock* addTo, Variable* v, + Variable* parcel, int flags); + virtual void CreateFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel); + virtual void ReadFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel); +}; + +class ParcelableType : public Type +{ +public: + ParcelableType(const string& package, const string& name, + bool builtIn, const string& declFile, int declLine); + + virtual string CreatorName() const; + + virtual void WriteToParcel(StatementBlock* addTo, Variable* v, + Variable* parcel, int flags); + virtual void CreateFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel); + virtual void ReadFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel); + + virtual bool CanBeArray() const; + + virtual void WriteArrayToParcel(StatementBlock* addTo, Variable* v, + Variable* parcel, int flags); + virtual void CreateArrayFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel); + virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel); +}; + +class InterfaceType : public Type +{ +public: + InterfaceType(const string& package, const string& name, + bool builtIn, bool oneway, + const string& declFile, int declLine); + + bool OneWay() const; + + virtual void WriteToParcel(StatementBlock* addTo, Variable* v, + Variable* parcel, int flags); + virtual void CreateFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel); + +private: + bool m_oneway; +}; + + +class GenericType : public Type +{ +public: + GenericType(const string& package, const string& name, + const vector<Type*>& args); + + string GenericArguments() const; + + virtual string ImportType() const; + + virtual void WriteToParcel(StatementBlock* addTo, Variable* v, + Variable* parcel, int flags); + virtual void CreateFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel); + virtual void ReadFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel); + +private: + string m_genericArguments; + string m_importName; + vector<Type*> m_args; +}; + + +class GenericListType : public GenericType +{ +public: + GenericListType(const string& package, const string& name, + const vector<Type*>& args); + + virtual string CreatorName() const; + virtual string InstantiableName() const; + + virtual void WriteToParcel(StatementBlock* addTo, Variable* v, + Variable* parcel, int flags); + virtual void CreateFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel); + virtual void ReadFromParcel(StatementBlock* addTo, Variable* v, + Variable* parcel); + +private: + string m_creator; +}; + +class ClassLoaderType : public Type +{ +public: + ClassLoaderType(); +}; + +class Namespace +{ +public: + Namespace(); + ~Namespace(); + void Add(Type* type); + + // args is the number of template types (what is this called?) + void AddGenericType(const string& package, const string& name, int args); + + // lookup a specific class name + Type* Find(const string& name) const; + Type* Find(const char* package, const char* name) const; + + // try to search by either a full name or a partial name + Type* Search(const string& name); + + void Dump() const; + +private: + struct Generic { + string package; + string name; + string qualified; + int args; + }; + + const Generic* search_generic(const string& name) const; + + vector<Type*> m_types; + vector<Generic> m_generics; +}; + +extern Namespace NAMES; + +extern Type* VOID_TYPE; +extern Type* BOOLEAN_TYPE; +extern Type* CHAR_TYPE; +extern Type* INT_TYPE; +extern Type* LONG_TYPE; +extern Type* FLOAT_TYPE; +extern Type* DOUBLE_TYPE; +extern Type* STRING_TYPE; +extern Type* CHAR_SEQUENCE_TYPE; +extern Type* TEXT_UTILS_TYPE; +extern Type* REMOTE_EXCEPTION_TYPE; +extern Type* RUNTIME_EXCEPTION_TYPE; +extern Type* IBINDER_TYPE; +extern Type* IINTERFACE_TYPE; +extern Type* BINDER_NATIVE_TYPE; +extern Type* BINDER_PROXY_TYPE; +extern Type* PARCEL_TYPE; +extern Type* PARCELABLE_INTERFACE_TYPE; + +extern Expression* NULL_VALUE; +extern Expression* THIS_VALUE; +extern Expression* SUPER_VALUE; +extern Expression* TRUE_VALUE; +extern Expression* FALSE_VALUE; + +void register_base_types(); + +#endif // AIDL_TYPE_H diff --git a/tools/aidl/aidl.cpp b/tools/aidl/aidl.cpp new file mode 100644 index 0000000..927d21e --- /dev/null +++ b/tools/aidl/aidl.cpp @@ -0,0 +1,902 @@ + +#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 <map> + +#ifdef HAVE_MS_C_RUNTIME +#include <io.h> +#include <sys/stat.h> +#endif + +#ifndef O_BINARY +# define O_BINARY 0 +#endif + +using namespace std; + +static void +test_document(document_item_type* d) +{ + while (d) { + if (d->item_type == INTERFACE_TYPE) { + interface_type* c = (interface_type*)d; + printf("interface %s %s {\n", c->package, c->name.data); + interface_item_type *q = (interface_item_type*)c->interface_items; + while (q) { + if (q->item_type == METHOD_TYPE) { + method_type *m = (method_type*)q; + printf(" %s %s(", m->type.type.data, m->name.data); + arg_type *p = m->args; + while (p) { + printf("%s %s",p->type.type.data,p->name.data); + if (p->next) printf(", "); + p=p->next; + } + printf(")"); + printf(";\n"); + } + q=q->next; + } + printf("}\n"); + } + else if (d->item_type == PARCELABLE_TYPE) { + parcelable_type* b = (parcelable_type*)d; + printf("parcelable %s %s;\n", b->package, b->name.data); + } + else { + printf("UNKNOWN d=0x%08x d->item_type=%ld\n", (long)d, d->item_type); + } + d = d->next; + } +} + +// ========================================================== +int +convert_direction(const char* direction) +{ + if (direction == NULL) { + return IN_PARAMETER; + } + if (0 == strcmp(direction, "in")) { + return IN_PARAMETER; + } + if (0 == strcmp(direction, "out")) { + return OUT_PARAMETER; + } + return INOUT_PARAMETER; +} + +// ========================================================== +struct import_info { + const char* from; + const char* filename; + buffer_type statement; + const char* neededClass; + document_item_type* doc; + struct import_info* next; +}; + +document_item_type* g_document = NULL; +import_info* g_imports = NULL; + +static void +main_document_parsed(document_item_type* d) +{ + g_document = d; +} + +static void +main_import_parsed(buffer_type* statement) +{ + import_info* import = (import_info*)malloc(sizeof(import_info)); + memset(import, 0, sizeof(import_info)); + import->from = strdup(g_currentFilename); + import->statement.lineno = statement->lineno; + import->statement.data = strdup(statement->data); + import->statement.extra = NULL; + import->next = g_imports; + import->neededClass = parse_import_statement(statement->data); + g_imports = import; +} + +static ParserCallbacks g_mainCallbacks = { + &main_document_parsed, + &main_import_parsed +}; + +char* +parse_import_statement(const char* text) +{ + const char* end; + int len; + + while (isspace(*text)) { + text++; + } + while (!isspace(*text)) { + text++; + } + while (isspace(*text)) { + text++; + } + end = text; + while (!isspace(*end) && *end != ';') { + end++; + } + len = end-text; + + char* rv = (char*)malloc(len+1); + memcpy(rv, text, len); + rv[len] = '\0'; + + return rv; +} + +// ========================================================== +static void +import_import_parsed(buffer_type* statement) +{ +} + +static ParserCallbacks g_importCallbacks = { + &main_document_parsed, + &import_import_parsed +}; + +// ========================================================== +static int +check_filename(const char* filename, const char* package, buffer_type* name) +{ + const char* p; + string expected; + string fn; + size_t len; + char cwd[MAXPATHLEN]; + bool valid = false; + +#ifdef HAVE_WINDOWS_PATHS + if (isalpha(filename[0]) && filename[1] == ':' + && filename[2] == OS_PATH_SEPARATOR) { +#else + if (filename[0] == OS_PATH_SEPARATOR) { +#endif + fn = filename; + } else { + fn = getcwd(cwd, sizeof(cwd)); + len = fn.length(); + if (fn[len-1] != OS_PATH_SEPARATOR) { + fn += OS_PATH_SEPARATOR; + } + fn += filename; + } + + if (package) { + expected = package; + expected += '.'; + } + + len = expected.length(); + for (size_t i=0; i<len; i++) { + if (expected[i] == '.') { + expected[i] = OS_PATH_SEPARATOR; + } + } + + p = strchr(name->data, '.'); + len = p ? p-name->data : strlen(name->data); + expected.append(name->data, len); + + expected += ".aidl"; + + len = fn.length(); + valid = (len >= expected.length()); + + if (valid) { + p = fn.c_str() + (len - expected.length()); + +#ifdef HAVE_WINDOWS_PATHS + if (OS_PATH_SEPARATOR != '/') { + // Input filename under cygwin most likely has / separators + // whereas the expected string uses \\ separators. Adjust + // them accordingly. + for (char *c = const_cast<char *>(p); *c; ++c) { + if (*c == '/') *c = OS_PATH_SEPARATOR; + } + } +#endif + +#ifdef OS_CASE_SENSITIVE + valid = (expected == p); +#else + valid = !strcasecmp(expected.c_str(), p); +#endif + } + + if (!valid) { + fprintf(stderr, "%s:%d interface %s should be declared in a file" + " called %s.\n", + filename, name->lineno, name->data, expected.c_str()); + return 1; + } + + return 0; +} + +static int +check_filenames(const char* filename, document_item_type* items) +{ + int err = 0; + while (items) { + if (items->item_type == PARCELABLE_TYPE) { + parcelable_type* p = (parcelable_type*)items; + err |= check_filename(filename, p->package, &p->name); + } + else if (items->item_type == INTERFACE_TYPE) { + interface_type* c = (interface_type*)items; + err |= check_filename(filename, c->package, &c->name); + } + else { + fprintf(stderr, "aidl: internal error unkown document type %d.\n", + items->item_type); + return 1; + } + items = items->next; + } + return err; +} + +// ========================================================== +static const char* +kind_to_string(int kind) +{ + switch (kind) + { + case Type::INTERFACE: + return "an interface"; + case Type::PARCELABLE: + return "a parcelable"; + default: + return "ERROR"; + } +} + +static char* +rfind(char* str, char c) +{ + char* p = str + strlen(str) - 1; + while (p >= str) { + if (*p == c) { + return p; + } + p--; + } + return NULL; +} + +static int +gather_types(const char* filename, document_item_type* items) +{ + int err = 0; + while (items) { + Type* type; + if (items->item_type == PARCELABLE_TYPE) { + parcelable_type* p = (parcelable_type*)items; + type = new ParcelableType(p->package ? p->package : "", + p->name.data, false, filename, p->name.lineno); + } + else if (items->item_type == INTERFACE_TYPE) { + interface_type* c = (interface_type*)items; + type = new InterfaceType(c->package ? c->package : "", + c->name.data, false, c->oneway, + filename, c->name.lineno); + } + else { + fprintf(stderr, "aidl: internal error %s:%d\n", __FILE__, __LINE__); + return 1; + } + + Type* old = NAMES.Find(type->QualifiedName()); + if (old == NULL) { + NAMES.Add(type); + + if (items->item_type == INTERFACE_TYPE) { + // for interfaces, also add the stub and proxy types, we don't + // bother checking these for duplicates, because the parser + // won't let us do it. + interface_type* c = (interface_type*)items; + + string name = c->name.data; + name += ".Stub"; + Type* stub = new Type(c->package ? c->package : "", + name, Type::GENERATED, false, false, + filename, c->name.lineno); + NAMES.Add(stub); + + name = c->name.data; + name += ".Stub.Proxy"; + Type* proxy = new Type(c->package ? c->package : "", + name, Type::GENERATED, false, false, + filename, c->name.lineno); + NAMES.Add(proxy); + } + } else { + if (old->Kind() == Type::BUILT_IN) { + fprintf(stderr, "%s:%d attempt to redefine built in class %s\n", + filename, type->DeclLine(), + type->QualifiedName().c_str()); + err = 1; + } + else if (type->Kind() != old->Kind()) { + const char* oldKind = kind_to_string(old->Kind()); + const char* newKind = kind_to_string(type->Kind()); + + fprintf(stderr, "%s:%d attempt to redefine %s as %s,\n", + filename, type->DeclLine(), + type->QualifiedName().c_str(), newKind); + fprintf(stderr, "%s:%d previously defined here as %s.\n", + old->DeclFile().c_str(), old->DeclLine(), oldKind); + err = 1; + } + } + + items = items->next; + } + return err; +} + +// ========================================================== +static bool +matches_keyword(const char* str) +{ + static const char* KEYWORDS[] = { "abstract", "assert", "boolean", "break", + "byte", "case", "catch", "char", "class", "const", "continue", + "default", "do", "double", "else", "enum", "extends", "final", + "finally", "float", "for", "goto", "if", "implements", "import", + "instanceof", "int", "interface", "long", "native", "new", "package", + "private", "protected", "public", "return", "short", "static", + "strictfp", "super", "switch", "synchronized", "this", "throw", + "throws", "transient", "try", "void", "volatile", "while", + "true", "false", "null", + NULL + }; + const char** k = KEYWORDS; + while (*k) { + if (0 == strcmp(str, *k)) { + return true; + } + k++; + } + return false; +} + +static int +check_method(const char* filename, method_type* m) +{ + int err = 0; + + // return type + Type* returnType = NAMES.Search(m->type.type.data); + if (returnType == NULL) { + fprintf(stderr, "%s:%d unknown return type %s\n", filename, + m->type.type.lineno, m->type.type.data); + err = 1; + return err; + } + + if (!returnType->CanBeMarshalled()) { + fprintf(stderr, "%s:%d return type %s can't be marshalled.\n", filename, + m->type.type.lineno, m->type.type.data); + err = 1; + } + + if (m->type.dimension > 0 && !returnType->CanBeArray()) { + fprintf(stderr, "%s:%d return type %s%s can't be an array.\n", filename, + m->type.array_token.lineno, m->type.type.data, + m->type.array_token.data); + err = 1; + } + + if (m->type.dimension > 1) { + fprintf(stderr, "%s:%d return type %s%s only one" + " dimensional arrays are supported\n", filename, + m->type.array_token.lineno, m->type.type.data, + m->type.array_token.data); + err = 1; + } + + int index = 1; + + arg_type* arg = m->args; + while (arg) { + Type* t = NAMES.Search(arg->type.type.data); + + // check the arg type + if (t == NULL) { + fprintf(stderr, "%s:%d parameter %s (%d) unknown type %s\n", + filename, m->type.type.lineno, arg->name.data, index, + arg->type.type.data); + err = 1; + goto next; + } + + if (!t->CanBeMarshalled()) { + fprintf(stderr, "%s:%d parameter %d: '%s %s' can't be marshalled.\n", + filename, m->type.type.lineno, index, + arg->type.type.data, arg->name.data); + err = 1; + } + + if (arg->direction.data == NULL + && (arg->type.dimension != 0 || t->CanBeOutParameter())) { + fprintf(stderr, "%s:%d parameter %d: '%s %s' can be an out" + " parameter, so you must declare it as in," + " out or inout.\n", + filename, m->type.type.lineno, index, + arg->type.type.data, arg->name.data); + err = 1; + } + + if (convert_direction(arg->direction.data) != IN_PARAMETER + && !t->CanBeOutParameter() + && arg->type.dimension == 0) { + fprintf(stderr, "%s:%d parameter %d: '%s %s %s' can only be an in" + " parameter.\n", + filename, m->type.type.lineno, index, + arg->direction.data, arg->type.type.data, + arg->name.data); + err = 1; + } + + if (arg->type.dimension > 0 && !t->CanBeArray()) { + fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' can't be an" + " array.\n", filename, + m->type.array_token.lineno, index, arg->direction.data, + arg->type.type.data, arg->type.array_token.data, + arg->name.data); + err = 1; + } + + if (arg->type.dimension > 1) { + fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' only one" + " dimensional arrays are supported\n", filename, + m->type.array_token.lineno, index, arg->direction.data, + arg->type.type.data, arg->type.array_token.data, + arg->name.data); + err = 1; + } + + // check that the name doesn't match a keyword + if (matches_keyword(arg->name.data)) { + fprintf(stderr, "%s:%d parameter %d %s is named the same as a" + " Java keyword\n", + filename, m->name.lineno, index, arg->name.data); + err = 1; + } + +next: + index++; + arg = arg->next; + } + + return err; +} + +static int +check_types(const char* filename, document_item_type* items) +{ + int err = 0; + while (items) { + // (nothing to check for PARCELABLE_TYPE) + if (items->item_type == INTERFACE_TYPE) { + map<string,method_type*> methodNames; + interface_type* c = (interface_type*)items; + + interface_item_type* member = c->interface_items; + while (member) { + if (member->item_type == METHOD_TYPE) { + method_type* m = (method_type*)member; + + err |= check_method(filename, m); + + // prevent duplicate methods + if (methodNames.find(m->name.data) == methodNames.end()) { + methodNames[m->name.data] = m; + } else { + fprintf(stderr,"%s:%d attempt to redefine method %s,\n", + filename, m->name.lineno, m->name.data); + method_type* old = methodNames[m->name.data]; + fprintf(stderr, "%s:%d previously defined here.\n", + filename, old->name.lineno); + err = 1; + } + } + member = member->next; + } + } + + items = items->next; + } + return err; +} + +// ========================================================== +static int +exactly_one_interface(const char* filename, const document_item_type* items, const Options& options, + bool* onlyParcelable) +{ + if (items == NULL) { + fprintf(stderr, "%s: file does not contain any interfaces\n", + filename); + return 1; + } + + const document_item_type* next = items->next; + if (items->next != NULL) { + int lineno = -1; + if (next->item_type == INTERFACE_TYPE) { + lineno = ((interface_type*)next)->interface_token.lineno; + } + else if (next->item_type == PARCELABLE_TYPE) { + lineno = ((parcelable_type*)next)->parcelable_token.lineno; + } + fprintf(stderr, "%s:%d aidl can only handle one interface per file\n", + filename, lineno); + return 1; + } + + if (items->item_type == PARCELABLE_TYPE) { + *onlyParcelable = true; + if (options.failOnParcelable) { + fprintf(stderr, "%s:%d aidl can only generate code for interfaces, not" + " parcelables,\n", filename, + ((parcelable_type*)items)->parcelable_token.lineno); + fprintf(stderr, "%s:%d .aidl files that only declare parcelables " + "don't need to go in the Makefile.\n", filename, + ((parcelable_type*)items)->parcelable_token.lineno); + return 1; + } + } else { + *onlyParcelable = false; + } + + return 0; +} + +// ========================================================== +void +generate_dep_file(const Options& options) +{ + /* we open the file in binary mode to ensure that the same output is + * generated on all platforms !! + */ + FILE* to = fopen(options.depFileName.c_str(), "wb"); + if (to == NULL) { + return; + } + + const char* slash = "\\"; + import_info* import = g_imports; + if (import == NULL) { + slash = ""; + } + + fprintf(to, "%s: \\\n", options.outputFileName.c_str()); + fprintf(to, " %s %s\n", options.inputFileName.c_str(), slash); + + while (import) { + if (import->next == NULL) { + slash = ""; + } + if (import->filename) { + fprintf(to, " %s %s\n", import->filename, slash); + } + import = import->next; + } + + fprintf(to, "\n"); + + fclose(to); +} + +// ========================================================== +static int +parse_preprocessed_file(const string& filename) +{ + int err; + + FILE* f = fopen(filename.c_str(), "rb"); + if (f == NULL) { + fprintf(stderr, "aidl: can't open preprocessd file: %s\n", + filename.c_str()); + return 1; + } + + int lineno = 1; + char line[1024]; + char type[1024]; + char fullname[1024]; + while (fgets(line, sizeof(line), f)) { + // skip comments and empty lines + if (!line[0] || strncmp(line, "//", 2) == 0) { + continue; + } + + sscanf(line, "%s %[^; \r\n\t];", type, fullname); + + char* packagename; + char* classname = rfind(fullname, '.'); + if (classname != NULL) { + *classname = '\0'; + classname++; + packagename = fullname; + } else { + classname = fullname; + packagename = NULL; + } + + //printf("%s:%d:...%s...%s...%s...\n", filename.c_str(), lineno, + // type, packagename, classname); + document_item_type* doc; + + if (0 == strcmp("parcelable", type)) { + parcelable_type* parcl = (parcelable_type*)malloc( + sizeof(parcelable_type)); + memset(parcl, 0, sizeof(parcelable_type)); + parcl->document_item.item_type = PARCELABLE_TYPE; + parcl->parcelable_token.lineno = lineno; + parcl->parcelable_token.data = strdup(type); + parcl->package = packagename ? strdup(packagename) : NULL; + parcl->name.lineno = lineno; + parcl->name.data = strdup(classname); + parcl->semicolon_token.lineno = lineno; + parcl->semicolon_token.data = strdup(";"); + doc = (document_item_type*)parcl; + } + else if (0 == strcmp("interface", type)) { + interface_type* iface = (interface_type*)malloc( + sizeof(interface_type)); + memset(iface, 0, sizeof(interface_type)); + iface->document_item.item_type = INTERFACE_TYPE; + iface->interface_token.lineno = lineno; + iface->interface_token.data = strdup(type); + iface->package = packagename ? strdup(packagename) : NULL; + iface->name.lineno = lineno; + iface->name.data = strdup(classname); + iface->open_brace_token.lineno = lineno; + iface->open_brace_token.data = strdup("{"); + iface->close_brace_token.lineno = lineno; + iface->close_brace_token.data = strdup("}"); + doc = (document_item_type*)iface; + } + else { + fprintf(stderr, "%s:%d: bad type in line: %s\n", + filename.c_str(), lineno, line); + return 1; + } + err = gather_types(filename.c_str(), doc); + lineno++; + } + + if (!feof(f)) { + fprintf(stderr, "%s:%d: error reading file, line to long.\n", + filename.c_str(), lineno); + return 1; + } + + fclose(f); + return 0; +} + +// ========================================================== +static int +compile_aidl(const Options& options) +{ + int err = 0, N; + + set_import_paths(options.importPaths); + + register_base_types(); + + // import the preprocessed file + N = options.preprocessedFiles.size(); + for (int i=0; i<N; i++) { + const string& s = options.preprocessedFiles[i]; + err |= parse_preprocessed_file(s); + } + if (err != 0) { + return err; + } + + // parse the main file + g_callbacks = &g_mainCallbacks; + err = parse_aidl(options.inputFileName.c_str()); + document_item_type* mainDoc = g_document; + g_document = NULL; + + // parse the imports + g_callbacks = &g_mainCallbacks; + import_info* import = g_imports; + while (import) { + if (NAMES.Find(import->neededClass) == NULL) { + import->filename = find_import_file(import->neededClass); + if (!import->filename) { + fprintf(stderr, "%s:%d: couldn't find import for class %s\n", + import->from, import->statement.lineno, + import->neededClass); + err |= 1; + } else { + err |= parse_aidl(import->filename); + import->doc = g_document; + if (import->doc == NULL) { + err |= 1; + } + } + } + import = import->next; + } + // bail out now if parsing wasn't successful + if (err != 0 || mainDoc == NULL) { + //fprintf(stderr, "aidl: parsing failed, stopping.\n"); + return 1; + } + + // complain about ones that aren't in the right files + err |= check_filenames(options.inputFileName.c_str(), mainDoc); + import = g_imports; + while (import) { + err |= check_filenames(import->filename, import->doc); + import = import->next; + } + + // gather the types that have been declared + err |= gather_types(options.inputFileName.c_str(), mainDoc); + import = g_imports; + while (import) { + err |= gather_types(import->filename, import->doc); + import = import->next; + } + +#if 0 + printf("---- main doc ----\n"); + test_document(mainDoc); + + import = g_imports; + while (import) { + printf("---- import doc ----\n"); + test_document(import->doc); + import = import->next; + } + NAMES.Dump(); +#endif + + // check the referenced types in mainDoc to make sure we've imported them + err |= check_types(options.inputFileName.c_str(), mainDoc); + + // finally, there really only needs to be one thing in mainDoc, and it + // needs to be an interface. + bool onlyParcelable = false; + err |= exactly_one_interface(options.inputFileName.c_str(), mainDoc, options, &onlyParcelable); + + // after this, there shouldn't be any more errors because of the + // input. + if (err != 0 || mainDoc == NULL) { + return 1; + } + + // they didn't ask to fail on parcelables, so just exit quietly. + if (onlyParcelable && !options.failOnParcelable) { + return 0; + } + + // if we were asked to, generate a make dependency file + if (options.depFileName != "") { + generate_dep_file(options); + } + + err = generate_java(options.outputFileName, options.inputFileName.c_str(), + (interface_type*)mainDoc); + + return err; +} + +static int +preprocess_aidl(const Options& options) +{ + vector<string> lines; + int err; + + // read files + int N = options.filesToPreprocess.size(); + for (int i=0; i<N; i++) { + g_callbacks = &g_mainCallbacks; + err = parse_aidl(options.filesToPreprocess[i].c_str()); + if (err != 0) { + return err; + } + document_item_type* doc = g_document; + string line; + if (doc->item_type == PARCELABLE_TYPE) { + line = "parcelable "; + parcelable_type* parcelable = (parcelable_type*)doc; + if (parcelable->package) { + line += parcelable->package; + line += '.'; + } + line += parcelable->name.data; + } else { + line = "interface "; + interface_type* iface = (interface_type*)doc; + if (iface->package) { + line += iface->package; + line += '.'; + } + line += iface->name.data; + } + line += ";\n"; + lines.push_back(line); + } + + // write preprocessed file + int fd = open( options.outputFileName.c_str(), + O_RDWR|O_CREAT|O_TRUNC|O_BINARY, +#ifdef HAVE_MS_C_RUNTIME + _S_IREAD|_S_IWRITE); +#else + S_IRUSR|S_IWUSR|S_IRGRP); +#endif + if (fd == -1) { + fprintf(stderr, "aidl: could not open file for write: %s\n", + options.outputFileName.c_str()); + return 1; + } + + N = lines.size(); + for (int i=0; i<N; i++) { + const string& s = lines[i]; + int len = s.length(); + if (len != write(fd, s.c_str(), len)) { + fprintf(stderr, "aidl: error writing to file %s\n", + options.outputFileName.c_str()); + close(fd); + unlink(options.outputFileName.c_str()); + return 1; + } + } + + close(fd); + return 0; +} + +// ========================================================== +int +main(int argc, const char **argv) +{ + int err = 0; + + Options options; + int result = parse_options(argc, argv, &options); + if (result) { + return result; + } + + switch (options.task) + { + case COMPILE_AIDL: + return compile_aidl(options); + case PREPROCESS_AIDL: + return preprocess_aidl(options); + } + fprintf(stderr, "aidl: internal error\n"); + return 1; +} + + diff --git a/tools/aidl/aidl_language.cpp b/tools/aidl/aidl_language.cpp new file mode 100644 index 0000000..cd6a3bd --- /dev/null +++ b/tools/aidl/aidl_language.cpp @@ -0,0 +1,20 @@ +#include "aidl_language.h" +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#ifdef HAVE_MS_C_RUNTIME +int isatty(int fd) +{ + return (fd == 0); +} +#endif + +#if 0 +ParserCallbacks k_parserCallbacks = { + NULL +}; +#endif + +ParserCallbacks* g_callbacks = NULL; // &k_parserCallbacks; + diff --git a/tools/aidl/aidl_language.h b/tools/aidl/aidl_language.h new file mode 100644 index 0000000..9ca5deb --- /dev/null +++ b/tools/aidl/aidl_language.h @@ -0,0 +1,159 @@ +#ifndef DEVICE_TOOLS_AIDL_AIDL_LANGUAGE_H +#define DEVICE_TOOLS_AIDL_AIDL_LANGUAGE_H + + +typedef enum { + NO_EXTRA_TEXT = 0, + SHORT_COMMENT, + LONG_COMMENT, + COPY_TEXT, + WHITESPACE +} which_extra_text; + +typedef struct extra_text_type { + unsigned lineno; + which_extra_text which; + char* data; + unsigned len; + struct extra_text_type* next; +} extra_text_type; + +typedef struct buffer_type { + unsigned lineno; + unsigned token; + char *data; + extra_text_type* extra; +} buffer_type; + +typedef struct type_type { + buffer_type type; + buffer_type array_token; + int dimension; +} type_type; + +typedef struct arg_type { + buffer_type comma_token; // empty in the first one in the list + buffer_type direction; + type_type type; + buffer_type name; + struct arg_type *next; +} arg_type; + +enum { + METHOD_TYPE +}; + +typedef struct interface_item_type { + unsigned item_type; + struct interface_item_type* next; +} interface_item_type; + +typedef struct method_type { + interface_item_type interface_item; + type_type type; + bool oneway; + buffer_type oneway_token; + buffer_type name; + buffer_type open_paren_token; + arg_type* args; + buffer_type close_paren_token; + // XXX missing comments/copy text here + buffer_type semicolon_token; + buffer_type* comments_token; // points into this structure, DO NOT DELETE +} method_type; + +enum { + PARCELABLE_TYPE = 12, + INTERFACE_TYPE +}; + +typedef struct document_item_type { + unsigned item_type; + struct document_item_type* next; +} document_item_type; + +typedef struct parcelable_type { + document_item_type document_item; + buffer_type parcelable_token; + char* package; + buffer_type name; + buffer_type semicolon_token; +} parcelable_type; + +typedef struct interface_type { + document_item_type document_item; + buffer_type interface_token; + bool oneway; + buffer_type oneway_token; + char* package; + buffer_type name; + buffer_type open_brace_token; + interface_item_type* interface_items; + buffer_type close_brace_token; + buffer_type* comments_token; // points into this structure, DO NOT DELETE +} interface_type; + +typedef union lexer_type { + buffer_type buffer; + type_type type; + arg_type *arg; + method_type* method; + interface_item_type* interface_item; + interface_type* interface_obj; + parcelable_type* parcelable; + document_item_type* document_item; +} lexer_type; + + +#define YYSTYPE lexer_type + +#if __cplusplus +extern "C" { +#endif + +int parse_aidl(char const *); + +// strips off the leading whitespace, the "import" text +// also returns whether it's a local or system import +// we rely on the input matching the import regex from below +char* parse_import_statement(const char* text); + +// in, out or inout +enum { + IN_PARAMETER = 1, + OUT_PARAMETER = 2, + INOUT_PARAMETER = 3 +}; +int convert_direction(const char* direction); + +// callbacks from within the parser +// these functions all take ownership of the strings +typedef struct ParserCallbacks { + void (*document)(document_item_type* items); + void (*import)(buffer_type* statement); +} ParserCallbacks; + +extern ParserCallbacks* g_callbacks; + +// true if there was an error parsing, false otherwise +extern int g_error; + +// the name of the file we're currently parsing +extern char const* g_currentFilename; + +// the package name for our current file +extern char const* g_currentPackage; + +typedef enum { + STATEMENT_INSIDE_INTERFACE +} error_type; + +void init_buffer_type(buffer_type* buf, int lineno); + + +#if __cplusplus +} +#endif + + +#endif // DEVICE_TOOLS_AIDL_AIDL_LANGUAGE_H diff --git a/tools/aidl/aidl_language_l.l b/tools/aidl/aidl_language_l.l new file mode 100644 index 0000000..567b1cf --- /dev/null +++ b/tools/aidl/aidl_language_l.l @@ -0,0 +1,210 @@ +%{ +#include "aidl_language.h" +#include "aidl_language_y.h" +#include "search_path.h" +#include <string.h> +#include <stdlib.h> + +extern YYSTYPE yylval; + +// comment and whitespace handling +// these functions save a copy of the buffer +static void begin_extra_text(unsigned lineno, which_extra_text which); +static void append_extra_text(char* text); +static extra_text_type* get_extra_text(void); // you now own the object + // this returns +static void drop_extra_text(void); + +// package handling +static void do_package_statement(const char* importText); + +#define SET_BUFFER(t) \ + do { \ + yylval.buffer.lineno = yylineno; \ + yylval.buffer.token = (t); \ + yylval.buffer.data = strdup(yytext); \ + yylval.buffer.extra = get_extra_text(); \ + } while(0) + +%} + +%option yylineno +%option noyywrap + +%x COPYING LONG_COMMENT + +identifier [_a-zA-Z][_a-zA-Z0-9\.]* +whitespace ([ \t\n\r]+) +brackets \[{whitespace}?\] + +%% + + +\%\%\{ { begin_extra_text(yylineno, COPY_TEXT); BEGIN(COPYING); } +<COPYING>\}\%\% { BEGIN(INITIAL); } +<COPYING>.*\n { append_extra_text(yytext); } +<COPYING>.* { append_extra_text(yytext); } +<COPYING>\n+ { append_extra_text(yytext); } + + +\/\* { begin_extra_text(yylineno, (which_extra_text)LONG_COMMENT); + BEGIN(LONG_COMMENT); } +<LONG_COMMENT>[^*]* { append_extra_text(yytext); } +<LONG_COMMENT>\*+[^/] { append_extra_text(yytext); } +<LONG_COMMENT>\n { append_extra_text(yytext); } +<LONG_COMMENT>\**\/ { BEGIN(INITIAL); } + +^{whitespace}?import{whitespace}[^ \t\r\n]+{whitespace}?; { + SET_BUFFER(IMPORT); + return IMPORT; + } +^{whitespace}?package{whitespace}[^ \t\r\n]+{whitespace}?; { + do_package_statement(yytext); + SET_BUFFER(PACKAGE); + return PACKAGE; + } +<<EOF>> { yyterminate(); } + +\/\/.*\n { begin_extra_text(yylineno, SHORT_COMMENT); + append_extra_text(yytext); } + +{whitespace} { /* begin_extra_text(yylineno, WHITESPACE); + append_extra_text(yytext); */ } + +; { SET_BUFFER(';'); return ';'; } +\{ { SET_BUFFER('{'); return '{'; } +\} { SET_BUFFER('}'); return '}'; } +\( { SET_BUFFER('('); return '('; } +\) { SET_BUFFER(')'); return ')'; } +, { SET_BUFFER(','); return ','; } + + /* keywords */ +parcelable { SET_BUFFER(PARCELABLE); return PARCELABLE; } +interface { SET_BUFFER(INTERFACE); return INTERFACE; } +in { SET_BUFFER(IN); return IN; } +out { SET_BUFFER(OUT); return OUT; } +inout { SET_BUFFER(INOUT); return INOUT; } +oneway { SET_BUFFER(ONEWAY); return ONEWAY; } + +{brackets}+ { SET_BUFFER(ARRAY); return ARRAY; } + +{identifier} { SET_BUFFER(IDENTIFIER); return IDENTIFIER; } +{identifier}\<{whitespace}*{identifier}({whitespace}*,{whitespace}*{identifier})*{whitespace}*\> { + SET_BUFFER(GENERIC); return GENERIC; } + + /* syntax error! */ +. { printf("UNKNOWN(%s)", yytext); + yylval.buffer.lineno = yylineno; + yylval.buffer.token = IDENTIFIER; + yylval.buffer.data = strdup(yytext); + return IDENTIFIER; + } + +%% + +// comment and whitespace handling +// ================================================ +extra_text_type* g_extraText = NULL; +extra_text_type* g_nextExtraText = NULL; + +void begin_extra_text(unsigned lineno, which_extra_text which) +{ + extra_text_type* text = (extra_text_type*)malloc(sizeof(extra_text_type)); + text->lineno = lineno; + text->which = which; + text->data = NULL; + text->len = 0; + text->next = NULL; + if (g_nextExtraText == NULL) { + g_extraText = text; + } else { + g_nextExtraText->next = text; + } + g_nextExtraText = text; +} + +void append_extra_text(char* text) +{ + if (g_nextExtraText->data == NULL) { + g_nextExtraText->data = strdup(text); + g_nextExtraText->len = strlen(text); + } else { + char* orig = g_nextExtraText->data; + unsigned oldLen = g_nextExtraText->len; + unsigned len = strlen(text); + g_nextExtraText->len += len; + g_nextExtraText->data = (char*)malloc(g_nextExtraText->len+1); + memcpy(g_nextExtraText->data, orig, oldLen); + memcpy(g_nextExtraText->data+oldLen, text, len); + g_nextExtraText->data[g_nextExtraText->len] = '\0'; + free(orig); + } +} + +extra_text_type* +get_extra_text(void) +{ + extra_text_type* result = g_extraText; + g_extraText = NULL; + g_nextExtraText = NULL; + return result; +} + +void drop_extra_text(void) +{ + extra_text_type* p = g_extraText; + while (p) { + extra_text_type* next = p->next; + free(p->data); + free(p); + free(next); + } + g_extraText = NULL; + g_nextExtraText = NULL; +} + + +// package handling +// ================================================ +void do_package_statement(const char* importText) +{ + if (g_currentPackage) free((void*)g_currentPackage); + g_currentPackage = parse_import_statement(importText); +} + + +// main parse function +// ================================================ +char const* g_currentFilename = NULL; +char const* g_currentPackage = NULL; + +int yyparse(void); + +int parse_aidl(char const *filename) +{ + yyin = fopen(filename, "r"); + if (yyin) { + char const* oldFilename = g_currentFilename; + char const* oldPackage = g_currentPackage; + g_currentFilename = strdup(filename); + + g_error = 0; + yylineno = 1; + int rv = yyparse(); + if (g_error != 0) { + rv = g_error; + } + + free((void*)g_currentFilename); + g_currentFilename = oldFilename; + + if (g_currentPackage) free((void*)g_currentPackage); + g_currentPackage = oldPackage; + + return rv; + } else { + fprintf(stderr, "aidl: unable to open file for read: %s\n", filename); + return 1; + } +} + diff --git a/tools/aidl/aidl_language_y.y b/tools/aidl/aidl_language_y.y new file mode 100644 index 0000000..3d65f17 --- /dev/null +++ b/tools/aidl/aidl_language_y.y @@ -0,0 +1,288 @@ +%{ +#include "aidl_language.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +int yyerror(char* errstr); +int yylex(void); +extern int yylineno; + +static int count_brackets(const char*); + +%} + +%token IMPORT +%token PACKAGE +%token IDENTIFIER +%token GENERIC +%token ARRAY +%token PARCELABLE +%token INTERFACE +%token IN +%token OUT +%token INOUT +%token ONEWAY + +%% +document: + document_items { g_callbacks->document($1.document_item); } + | headers document_items { g_callbacks->document($2.document_item); } + ; + +headers: + package { } + | imports { } + | package imports { } + ; + +package: + PACKAGE { } + ; + +imports: + IMPORT { g_callbacks->import(&($1.buffer)); } + | IMPORT imports { g_callbacks->import(&($1.buffer)); } + ; + +document_items: + { $$.document_item = NULL; } + | document_items declaration { + if ($2.document_item == NULL) { + // error cases only + $$ = $1; + } else { + document_item_type* p = $1.document_item; + while (p && p->next) { + p=p->next; + } + if (p) { + p->next = (document_item_type*)$2.document_item; + $$ = $1; + } else { + $$.document_item = (document_item_type*)$2.document_item; + } + } + } + | document_items error { + fprintf(stderr, "%s:%d: syntax error don't know what to do with \"%s\"\n", g_currentFilename, + $2.buffer.lineno, $2.buffer.data); + $$ = $1; + } + ; + +declaration: + parcelable_decl { $$.document_item = (document_item_type*)$1.parcelable; } + | interface_decl { $$.document_item = (document_item_type*)$1.interface_item; } + ; + +parcelable_decl: + PARCELABLE IDENTIFIER ';' { + parcelable_type* b = (parcelable_type*)malloc(sizeof(parcelable_type)); + b->document_item.item_type = PARCELABLE_TYPE; + b->document_item.next = NULL; + b->parcelable_token = $1.buffer; + b->name = $2.buffer; + b->package = g_currentPackage ? strdup(g_currentPackage) : NULL; + b->semicolon_token = $3.buffer; + $$.parcelable = b; + } + | PARCELABLE ';' { + fprintf(stderr, "%s:%d syntax error in parcelable declaration. Expected type name.\n", + g_currentFilename, $1.buffer.lineno); + $$.parcelable = NULL; + } + | PARCELABLE error ';' { + fprintf(stderr, "%s:%d syntax error in parcelable declaration. Expected type name, saw \"%s\".\n", + g_currentFilename, $2.buffer.lineno, $2.buffer.data); + $$.parcelable = NULL; + } + ; + +interface_header: + INTERFACE { + interface_type* c = (interface_type*)malloc(sizeof(interface_type)); + c->interface_token = $1.buffer; + c->oneway = false; + memset(&c->oneway_token, 0, sizeof(buffer_type)); + c->comments_token = &c->interface_token; + $$.interface_obj = c; + } + | ONEWAY INTERFACE { + interface_type* c = (interface_type*)malloc(sizeof(interface_type)); + c->interface_token = $2.buffer; + c->oneway = true; + c->oneway_token = $1.buffer; + c->comments_token = &c->oneway_token; + $$.interface_obj = c; + } + ; + +interface_decl: + interface_header IDENTIFIER '{' interface_items '}' { + interface_type* c = $1.interface_obj; + c->document_item.item_type = INTERFACE_TYPE; + c->document_item.next = NULL; + c->name = $2.buffer; + c->package = g_currentPackage ? strdup(g_currentPackage) : NULL; + c->open_brace_token = $3.buffer; + c->interface_items = $4.interface_item; + c->close_brace_token = $5.buffer; + $$.interface_obj = c; + } + | INTERFACE error '{' interface_items '}' { + fprintf(stderr, "%s:%d: syntax error in interface declaration. Expected type name, saw \"%s\"\n", + g_currentFilename, $2.buffer.lineno, $2.buffer.data); + $$.document_item = NULL; + } + | INTERFACE error '}' { + fprintf(stderr, "%s:%d: syntax error in interface declaration. Expected type name, saw \"%s\"\n", + g_currentFilename, $2.buffer.lineno, $2.buffer.data); + $$.document_item = NULL; + } + + ; + +interface_items: + { $$.interface_item = NULL; } + | interface_items method_decl { + interface_item_type* p=$1.interface_item; + while (p && p->next) { + p=p->next; + } + if (p) { + p->next = (interface_item_type*)$2.method; + $$ = $1; + } else { + $$.interface_item = (interface_item_type*)$2.method; + } + } + | interface_items error ';' { + fprintf(stderr, "%s:%d: syntax error before ';' (expected method declaration)\n", + g_currentFilename, $3.buffer.lineno); + $$ = $1; + } + ; + +method_decl: + type IDENTIFIER '(' arg_list ')' ';' { + method_type *method = (method_type*)malloc(sizeof(method_type)); + method->interface_item.item_type = METHOD_TYPE; + method->interface_item.next = NULL; + method->type = $1.type; + method->oneway = false; + memset(&method->oneway_token, 0, sizeof(buffer_type)); + method->name = $2.buffer; + method->open_paren_token = $3.buffer; + method->args = $4.arg; + method->close_paren_token = $5.buffer; + method->semicolon_token = $6.buffer; + method->comments_token = &method->type.type; + $$.method = method; + } + | ONEWAY type IDENTIFIER '(' arg_list ')' ';' { + method_type *method = (method_type*)malloc(sizeof(method_type)); + method->interface_item.item_type = METHOD_TYPE; + method->interface_item.next = NULL; + method->oneway = true; + method->oneway_token = $1.buffer; + method->type = $2.type; + method->name = $3.buffer; + method->open_paren_token = $4.buffer; + method->args = $5.arg; + method->close_paren_token = $6.buffer; + method->semicolon_token = $7.buffer; + method->comments_token = &method->oneway_token; + $$.method = method; + } + ; + +arg_list: + { $$.arg = NULL; } + | arg { $$ = $1; } + | arg_list ',' arg { + if ($$.arg != NULL) { + // only NULL on error + $$ = $1; + arg_type *p = $1.arg; + while (p && p->next) { + p=p->next; + } + $3.arg->comma_token = $2.buffer; + p->next = $3.arg; + } + } + | error { + fprintf(stderr, "%s:%d: syntax error in parameter list\n", g_currentFilename, $1.buffer.lineno); + $$.arg = NULL; + } + ; + +arg: + direction type IDENTIFIER { + arg_type* arg = (arg_type*)malloc(sizeof(arg_type)); + memset(&arg->comma_token, 0, sizeof(buffer_type)); + arg->direction = $1.buffer; + arg->type = $2.type; + arg->name = $3.buffer; + arg->next = NULL; + $$.arg = arg; + } + ; + +type: + IDENTIFIER { + $$.type.type = $1.buffer; + init_buffer_type(&$$.type.array_token, yylineno); + $$.type.dimension = 0; + } + | IDENTIFIER ARRAY { + $$.type.type = $1.buffer; + $$.type.array_token = $2.buffer; + $$.type.dimension = count_brackets($2.buffer.data); + } + | GENERIC { + $$.type.type = $1.buffer; + init_buffer_type(&$$.type.array_token, yylineno); + $$.type.dimension = 0; + } + ; + +direction: + { init_buffer_type(&$$.buffer, yylineno); } + | IN { $$.buffer = $1.buffer; } + | OUT { $$.buffer = $1.buffer; } + | INOUT { $$.buffer = $1.buffer; } + ; + +%% + +#include <ctype.h> +#include <stdio.h> + +int g_error = 0; + +int yyerror(char* errstr) +{ + fprintf(stderr, "%s:%d: %s\n", g_currentFilename, yylineno, errstr); + g_error = 1; + return 1; +} + +void init_buffer_type(buffer_type* buf, int lineno) +{ + buf->lineno = lineno; + buf->token = 0; + buf->data = NULL; + buf->extra = NULL; +} + +static int count_brackets(const char* s) +{ + int n=0; + while (*s) { + if (*s == '[') n++; + s++; + } + return n; +} diff --git a/tools/aidl/generate_java.cpp b/tools/aidl/generate_java.cpp new file mode 100644 index 0000000..7f84ff4 --- /dev/null +++ b/tools/aidl/generate_java.cpp @@ -0,0 +1,650 @@ +#include "generate_java.h" +#include "AST.h" +#include "Type.h" +#include <stdio.h> + +// ================================================= +class VariableFactory +{ +public: + VariableFactory(const string& base); // base must be short + Variable* Get(Type* type); + Variable* Get(int index); +private: + vector<Variable*> m_vars; + string m_base; + int m_index; +}; + +VariableFactory::VariableFactory(const string& base) + :m_base(base), + m_index(0) +{ +} + +Variable* +VariableFactory::Get(Type* type) +{ + char name[100]; + sprintf(name, "%s%d", m_base.c_str(), m_index); + m_index++; + Variable* v = new Variable(type, name); + m_vars.push_back(v); + return v; +} + +Variable* +VariableFactory::Get(int index) +{ + return m_vars[index]; +} + +// ================================================= +class StubClass : public Class +{ +public: + StubClass(Type* type, Type* interfaceType); + virtual ~StubClass(); + + Variable* transact_code; + Variable* transact_data; + Variable* transact_reply; + Variable* transact_flags; + SwitchStatement* transact_switch; +private: + void make_as_interface(Type* interfaceType); +}; + +StubClass::StubClass(Type* type, Type* interfaceType) + :Class() +{ + this->comment = "/** Local-side IPC implementation stub class. */"; + this->modifiers = PUBLIC | ABSTRACT | STATIC; + this->what = Class::CLASS; + this->type = type; + this->extends = BINDER_NATIVE_TYPE; + this->interfaces.push_back(interfaceType); + + // descriptor + Field* descriptor = new Field(STATIC | FINAL | PRIVATE, + new Variable(STRING_TYPE, "DESCRIPTOR")); + descriptor->value = "\"" + interfaceType->QualifiedName() + "\""; + this->elements.push_back(descriptor); + + // ctor + Method* ctor = new Method; + ctor->modifiers = PUBLIC; + ctor->comment = "/** Construct the stub at attach it to the " + "interface. */"; + ctor->name = "Stub"; + ctor->statements = new StatementBlock; + MethodCall* attach = new MethodCall(THIS_VALUE, "attachInterface", + 2, THIS_VALUE, new LiteralExpression("DESCRIPTOR")); + ctor->statements->Add(attach); + this->elements.push_back(ctor); + + // asInterface + make_as_interface(interfaceType); + + // asBinder + Method* asBinder = new Method; + asBinder->modifiers = PUBLIC; + asBinder->returnType = IBINDER_TYPE; + asBinder->name = "asBinder"; + asBinder->statements = new StatementBlock; + asBinder->statements->Add(new ReturnStatement(THIS_VALUE)); + this->elements.push_back(asBinder); + + // onTransact + this->transact_code = new Variable(INT_TYPE, "code"); + this->transact_data = new Variable(PARCEL_TYPE, "data"); + this->transact_reply = new Variable(PARCEL_TYPE, "reply"); + this->transact_flags = new Variable(INT_TYPE, "flags"); + Method* onTransact = new Method; + onTransact->modifiers = PUBLIC; + onTransact->returnType = BOOLEAN_TYPE; + onTransact->name = "onTransact"; + onTransact->parameters.push_back(this->transact_code); + onTransact->parameters.push_back(this->transact_data); + onTransact->parameters.push_back(this->transact_reply); + onTransact->parameters.push_back(this->transact_flags); + onTransact->statements = new StatementBlock; + onTransact->exceptions.push_back(REMOTE_EXCEPTION_TYPE); + this->elements.push_back(onTransact); + this->transact_switch = new SwitchStatement(this->transact_code); + + onTransact->statements->Add(this->transact_switch); + MethodCall* superCall = new MethodCall(SUPER_VALUE, "onTransact", 4, + this->transact_code, this->transact_data, + this->transact_reply, this->transact_flags); + onTransact->statements->Add(new ReturnStatement(superCall)); +} + +StubClass::~StubClass() +{ +} + +void +StubClass::make_as_interface(Type *interfaceType) +{ + Variable* obj = new Variable(IBINDER_TYPE, "obj"); + + Method* m = new Method; + m->comment = "/**\n * Cast an IBinder object into an "; + m->comment += interfaceType->Name(); + m->comment += " interface,\n"; + m->comment += " * generating a proxy if needed.\n */"; + m->modifiers = PUBLIC | STATIC; + m->returnType = interfaceType; + m->name = "asInterface"; + m->parameters.push_back(obj); + m->statements = new StatementBlock; + + IfStatement* ifstatement = new IfStatement(); + ifstatement->expression = new Comparison(obj, "==", NULL_VALUE); + ifstatement->statements = new StatementBlock; + ifstatement->statements->Add(new ReturnStatement(NULL_VALUE)); + m->statements->Add(ifstatement); + + // IInterface iin = obj.queryLocalInterface(DESCRIPTOR) + MethodCall* queryLocalInterface = new MethodCall(obj, "queryLocalInterface"); + queryLocalInterface->arguments.push_back(new LiteralExpression("DESCRIPTOR")); + IInterfaceType* iinType = new IInterfaceType(); + Variable *iin = new Variable(iinType, "iin"); + VariableDeclaration* iinVd = new VariableDeclaration(iin, queryLocalInterface, iinType); + m->statements->Add(iinVd); + + // Ensure the instance type of the local object is as expected. + // One scenario where this is needed is if another package (with a + // different class loader) runs in the same process as the service. + + // if (iin != null && iin instanceof <interfaceType>) return (<interfaceType>) iin; + Comparison* iinNotNull = new Comparison(iin, "!=", NULL_VALUE); + Comparison* instOfCheck = new Comparison(iin, " instanceof ", + new LiteralExpression(interfaceType->QualifiedName())); + IfStatement* instOfStatement = new IfStatement(); + instOfStatement->expression = new Comparison(iinNotNull, "&&", instOfCheck); + instOfStatement->statements = new StatementBlock; + instOfStatement->statements->Add(new ReturnStatement(new Cast(interfaceType, iin))); + m->statements->Add(instOfStatement); + + string proxyType = interfaceType->QualifiedName(); + proxyType += ".Stub.Proxy"; + NewExpression* ne = new NewExpression(NAMES.Find(proxyType)); + ne->arguments.push_back(obj); + m->statements->Add(new ReturnStatement(ne)); + + this->elements.push_back(m); +} + + + +// ================================================= +class ProxyClass : public Class +{ +public: + ProxyClass(Type* type, InterfaceType* interfaceType); + virtual ~ProxyClass(); + + Variable* mRemote; + bool mOneWay; +}; + +ProxyClass::ProxyClass(Type* type, InterfaceType* interfaceType) + :Class() +{ + this->modifiers = PRIVATE | STATIC; + this->what = Class::CLASS; + this->type = type; + this->interfaces.push_back(interfaceType); + + mOneWay = interfaceType->OneWay(); + + // IBinder mRemote + mRemote = new Variable(IBINDER_TYPE, "mRemote"); + this->elements.push_back(new Field(PRIVATE, mRemote)); + + // Proxy() + Variable* remote = new Variable(IBINDER_TYPE, "remote"); + Method* ctor = new Method; + ctor->name = "Proxy"; + ctor->statements = new StatementBlock; + ctor->parameters.push_back(remote); + ctor->statements->Add(new Assignment(mRemote, remote)); + this->elements.push_back(ctor); + + // IBinder asBinder() + Method* asBinder = new Method; + asBinder->modifiers = PUBLIC; + asBinder->returnType = IBINDER_TYPE; + asBinder->name = "asBinder"; + asBinder->statements = new StatementBlock; + asBinder->statements->Add(new ReturnStatement(mRemote)); + this->elements.push_back(asBinder); +} + +ProxyClass::~ProxyClass() +{ +} + +// ================================================= +static string +gather_comments(extra_text_type* extra) +{ + string s; + while (extra) { + if (extra->which == SHORT_COMMENT) { + s += extra->data; + } + else if (extra->which == LONG_COMMENT) { + s += "/*"; + s += extra->data; + s += "*/"; + } + extra = extra->next; + } + return s; +} + +static string +append(const char* a, const char* b) +{ + string s = a; + s += b; + return s; +} + +static void +generate_new_array(Type* t, StatementBlock* addTo, Variable* v, + Variable* parcel) +{ + Variable* len = new Variable(INT_TYPE, v->name + "_length"); + addTo->Add(new VariableDeclaration(len, new MethodCall(parcel, "readInt"))); + IfStatement* lencheck = new IfStatement(); + lencheck->expression = new Comparison(len, "<", new LiteralExpression("0")); + lencheck->statements->Add(new Assignment(v, NULL_VALUE)); + lencheck->elseif = new IfStatement(); + lencheck->elseif->statements->Add(new Assignment(v, + new NewArrayExpression(t, len))); + addTo->Add(lencheck); +} + +static void +generate_write_to_parcel(Type* t, StatementBlock* addTo, Variable* v, + Variable* parcel, int flags) +{ + if (v->dimension == 0) { + t->WriteToParcel(addTo, v, parcel, flags); + } + if (v->dimension == 1) { + t->WriteArrayToParcel(addTo, v, parcel, flags); + } +} + +static void +generate_create_from_parcel(Type* t, StatementBlock* addTo, Variable* v, + Variable* parcel) +{ + if (v->dimension == 0) { + t->CreateFromParcel(addTo, v, parcel); + } + if (v->dimension == 1) { + t->CreateArrayFromParcel(addTo, v, parcel); + } +} + +static void +generate_read_from_parcel(Type* t, StatementBlock* addTo, Variable* v, + Variable* parcel) +{ + if (v->dimension == 0) { + t->ReadFromParcel(addTo, v, parcel); + } + if (v->dimension == 1) { + t->ReadArrayFromParcel(addTo, v, parcel); + } +} + + +static void +generate_method(const method_type* method, Class* interface, + StubClass* stubClass, ProxyClass* proxyClass, int index) +{ + arg_type* arg; + int i; + bool hasOutParams = false; + + const bool oneway = proxyClass->mOneWay || method->oneway; + + // == the TRANSACT_ constant ============================================= + string transactCodeName = "TRANSACTION_"; + transactCodeName += method->name.data; + + char transactCodeValue[50]; + sprintf(transactCodeValue, "(IBinder.FIRST_CALL_TRANSACTION + %d)", index); + + Field* transactCode = new Field(STATIC | FINAL, + new Variable(INT_TYPE, transactCodeName)); + transactCode->value = transactCodeValue; + stubClass->elements.push_back(transactCode); + + // == the declaration in the interface =================================== + Method* decl = new Method; + decl->comment = gather_comments(method->comments_token->extra); + decl->modifiers = PUBLIC; + decl->returnType = NAMES.Search(method->type.type.data); + decl->returnTypeDimension = method->type.dimension; + decl->name = method->name.data; + + arg = method->args; + while (arg != NULL) { + decl->parameters.push_back(new Variable( + NAMES.Search(arg->type.type.data), arg->name.data, + arg->type.dimension)); + arg = arg->next; + } + + decl->exceptions.push_back(REMOTE_EXCEPTION_TYPE); + + interface->elements.push_back(decl); + + // == the stub method ==================================================== + + Case* c = new Case(transactCodeName); + + MethodCall* realCall = new MethodCall(THIS_VALUE, method->name.data); + + // interface token validation is the very first thing we do + c->statements->Add(new MethodCall(stubClass->transact_data, + "enforceInterface", 1, new LiteralExpression("DESCRIPTOR"))); + + // args + VariableFactory stubArgs("_arg"); + arg = method->args; + while (arg != NULL) { + Type* t = NAMES.Search(arg->type.type.data); + Variable* v = stubArgs.Get(t); + v->dimension = arg->type.dimension; + + c->statements->Add(new VariableDeclaration(v)); + + if (convert_direction(arg->direction.data) & IN_PARAMETER) { + generate_create_from_parcel(t, c->statements, v, + stubClass->transact_data); + } else { + if (arg->type.dimension == 0) { + c->statements->Add(new Assignment( + v, new NewExpression(v->type))); + } + else if (arg->type.dimension == 1) { + generate_new_array(v->type, c->statements, v, + stubClass->transact_data); + } + else { + fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, + __LINE__); + } + } + + realCall->arguments.push_back(v); + + arg = arg->next; + } + + // the real call + Variable* _result = NULL; + if (0 == strcmp(method->type.type.data, "void")) { + c->statements->Add(realCall); + + if (!oneway) { + // report that there were no exceptions + MethodCall* ex = new MethodCall(stubClass->transact_reply, + "writeNoException", 0); + c->statements->Add(ex); + } + } else { + _result = new Variable(decl->returnType, "_result", + decl->returnTypeDimension); + c->statements->Add(new VariableDeclaration(_result, realCall)); + + if (!oneway) { + // report that there were no exceptions + MethodCall* ex = new MethodCall(stubClass->transact_reply, + "writeNoException", 0); + c->statements->Add(ex); + } + + // marshall the return value + generate_write_to_parcel(decl->returnType, c->statements, _result, + stubClass->transact_reply, + Type::PARCELABLE_WRITE_RETURN_VALUE); + } + + // out parameters + i = 0; + arg = method->args; + while (arg != NULL) { + Type* t = NAMES.Search(arg->type.type.data); + Variable* v = stubArgs.Get(i++); + + if (convert_direction(arg->direction.data) & OUT_PARAMETER) { + generate_write_to_parcel(t, c->statements, v, + stubClass->transact_reply, + Type::PARCELABLE_WRITE_RETURN_VALUE); + hasOutParams = true; + } + + arg = arg->next; + } + + // return true + c->statements->Add(new ReturnStatement(TRUE_VALUE)); + stubClass->transact_switch->cases.push_back(c); + + // == the proxy method =================================================== + Method* proxy = new Method; + proxy->comment = gather_comments(method->comments_token->extra); + proxy->modifiers = PUBLIC; + proxy->returnType = NAMES.Search(method->type.type.data); + proxy->returnTypeDimension = method->type.dimension; + proxy->name = method->name.data; + proxy->statements = new StatementBlock; + arg = method->args; + while (arg != NULL) { + proxy->parameters.push_back(new Variable( + NAMES.Search(arg->type.type.data), arg->name.data, + arg->type.dimension)); + arg = arg->next; + } + proxy->exceptions.push_back(REMOTE_EXCEPTION_TYPE); + proxyClass->elements.push_back(proxy); + + // the parcels + Variable* _data = new Variable(PARCEL_TYPE, "_data"); + proxy->statements->Add(new VariableDeclaration(_data, + new MethodCall(PARCEL_TYPE, "obtain"))); + Variable* _reply = NULL; + if (!oneway) { + _reply = new Variable(PARCEL_TYPE, "_reply"); + proxy->statements->Add(new VariableDeclaration(_reply, + new MethodCall(PARCEL_TYPE, "obtain"))); + } + + // the return value + _result = NULL; + if (0 != strcmp(method->type.type.data, "void")) { + _result = new Variable(proxy->returnType, "_result", + method->type.dimension); + proxy->statements->Add(new VariableDeclaration(_result)); + } + + // try and finally + TryStatement* tryStatement = new TryStatement(); + proxy->statements->Add(tryStatement); + FinallyStatement* finallyStatement = new FinallyStatement(); + proxy->statements->Add(finallyStatement); + + // the interface identifier token: the DESCRIPTOR constant, marshalled as a string + tryStatement->statements->Add(new MethodCall(_data, "writeInterfaceToken", + 1, new LiteralExpression("DESCRIPTOR"))); + + // the parameters + arg = method->args; + while (arg != NULL) { + Type* t = NAMES.Search(arg->type.type.data); + Variable* v = new Variable(t, arg->name.data, arg->type.dimension); + int dir = convert_direction(arg->direction.data); + if (dir == OUT_PARAMETER && arg->type.dimension != 0) { + IfStatement* checklen = new IfStatement(); + checklen->expression = new Comparison(v, "==", NULL_VALUE); + checklen->statements->Add(new MethodCall(_data, "writeInt", 1, + new LiteralExpression("-1"))); + checklen->elseif = new IfStatement(); + checklen->elseif->statements->Add(new MethodCall(_data, "writeInt", + 1, new FieldVariable(v, "length"))); + tryStatement->statements->Add(checklen); + } + else if (dir & IN_PARAMETER) { + generate_write_to_parcel(t, tryStatement->statements, v, _data, 0); + } + arg = arg->next; + } + + // the transact call + MethodCall* call = new MethodCall(proxyClass->mRemote, "transact", 4, + new LiteralExpression("Stub." + transactCodeName), + _data, _reply ? _reply : NULL_VALUE, + new LiteralExpression( + oneway ? "IBinder.FLAG_ONEWAY" : "0")); + tryStatement->statements->Add(call); + + // throw back exceptions. + if (_reply) { + MethodCall* ex = new MethodCall(_reply, "readException", 0); + tryStatement->statements->Add(ex); + } + + // returning and cleanup + if (_reply != NULL) { + if (_result != NULL) { + generate_create_from_parcel(proxy->returnType, + tryStatement->statements, _result, _reply); + } + + // the out/inout parameters + arg = method->args; + while (arg != NULL) { + Type* t = NAMES.Search(arg->type.type.data); + Variable* v = new Variable(t, arg->name.data, arg->type.dimension); + if (convert_direction(arg->direction.data) & OUT_PARAMETER) { + generate_read_from_parcel(t, tryStatement->statements, + v, _reply); + } + arg = arg->next; + } + + finallyStatement->statements->Add(new MethodCall(_reply, "recycle")); + } + finallyStatement->statements->Add(new MethodCall(_data, "recycle")); + + if (_result != NULL) { + proxy->statements->Add(new ReturnStatement(_result)); + } +} + +static void +generate_interface_descriptors(StubClass* stub, ProxyClass* proxy) +{ + // the interface descriptor transaction handler + Case* c = new Case("INTERFACE_TRANSACTION"); + c->statements->Add(new MethodCall(stub->transact_reply, "writeString", + 1, new LiteralExpression("DESCRIPTOR"))); + c->statements->Add(new ReturnStatement(TRUE_VALUE)); + stub->transact_switch->cases.push_back(c); + + // and the proxy-side method returning the descriptor directly + Method* getDesc = new Method; + getDesc->modifiers = PUBLIC; + getDesc->returnType = STRING_TYPE; + getDesc->returnTypeDimension = 0; + getDesc->name = "getInterfaceDescriptor"; + getDesc->statements = new StatementBlock; + getDesc->statements->Add(new ReturnStatement(new LiteralExpression("DESCRIPTOR"))); + proxy->elements.push_back(getDesc); +} + +static Class* +generate_interface_class(const interface_type* iface) +{ + InterfaceType* interfaceType = static_cast<InterfaceType*>( + NAMES.Find(iface->package, iface->name.data)); + + // the interface class + Class* interface = new Class; + interface->comment = gather_comments(iface->comments_token->extra); + interface->modifiers = PUBLIC; + interface->what = Class::INTERFACE; + interface->type = interfaceType; + interface->interfaces.push_back(IINTERFACE_TYPE); + + // the stub inner class + StubClass* stub = new StubClass( + NAMES.Find(iface->package, append(iface->name.data, ".Stub").c_str()), + interfaceType); + interface->elements.push_back(stub); + + // the proxy inner class + ProxyClass* proxy = new ProxyClass( + NAMES.Find(iface->package, + append(iface->name.data, ".Stub.Proxy").c_str()), + interfaceType); + stub->elements.push_back(proxy); + + // stub and proxy support for getInterfaceDescriptor() + generate_interface_descriptors(stub, proxy); + + // all the declared methods of the interface + int index = 0; + interface_item_type* item = iface->interface_items; + while (item != NULL) { + if (item->item_type == METHOD_TYPE) { + generate_method((method_type*)item, interface, stub, proxy, index); + } + item = item->next; + index++; + } + + return interface; +} + +int +generate_java(const string& filename, const string& originalSrc, + interface_type* iface) +{ + Document* document = new Document; + document->comment = ""; + if (iface->package) document->package = iface->package; + document->originalSrc = originalSrc; + document->classes.push_back(generate_interface_class(iface)); + +// printf("outputting... filename=%s\n", filename.c_str()); + FILE* to; + if (filename == "-") { + to = stdout; + } else { + /* open file in binary mode to ensure that the tool produces the + * same output on all platforms !! + */ + to = fopen(filename.c_str(), "wb"); + if (to == NULL) { + fprintf(stderr, "unable to open %s for write\n", filename.c_str()); + return 1; + } + } + + document->Write(to); + + fclose(to); + return 0; +} + diff --git a/tools/aidl/generate_java.h b/tools/aidl/generate_java.h new file mode 100644 index 0000000..203fe23 --- /dev/null +++ b/tools/aidl/generate_java.h @@ -0,0 +1,14 @@ +#ifndef GENERATE_JAVA_H +#define GENERATE_JAVA_H + +#include "aidl_language.h" + +#include <string> + +using namespace std; + +int generate_java(const string& filename, const string& originalSrc, + interface_type* iface); + +#endif // GENERATE_JAVA_H + diff --git a/tools/aidl/options.cpp b/tools/aidl/options.cpp new file mode 100644 index 0000000..a890556 --- /dev/null +++ b/tools/aidl/options.cpp @@ -0,0 +1,134 @@ + +#include "options.h" + +static int +usage() +{ + fprintf(stderr, + "usage: aidl OPTIONS INPUT [OUTPUT]\n" + " aidl --preprocess OUTPUT INPUT...\n" + "\n" + "OPTIONS:\n" + " -I<DIR> search path for import statements.\n" + " -d<FILE> generate dependency file.\n" + " -p<FILE> file created by --preprocess to import.\n" + " -b fail when trying to compile a parcelable.\n" + "\n" + "INPUT:\n" + " An aidl interface file.\n" + "\n" + "OUTPUT:\n" + " The generated interface files. If omitted, the input filename is used, with the .aidl extension changed to a .java extension.\n" + ); + return 1; +} + +int +parse_options(int argc, const char* const* argv, Options *options) +{ + int i = 1; + + if (argc >= 2 && 0 == strcmp(argv[1], "--preprocess")) { + if (argc < 4) { + return usage(); + } + options->outputFileName = argv[2]; + for (int i=3; i<argc; i++) { + options->filesToPreprocess.push_back(argv[i]); + } + options->task = PREPROCESS_AIDL; + return 0; + } + + options->task = COMPILE_AIDL; + options->failOnParcelable = false; + + // OPTIONS + while (i < argc) { + const char* s = argv[i]; + int len = strlen(s); + if (s[0] == '-') { + if (len > 1) { + // -I<system-import-path> + if (s[1] == 'I') { + if (len > 2) { + options->importPaths.push_back(s+2); + } else { + fprintf(stderr, "-I option (%d) requires a path.\n", i); + return usage(); + } + } + else if (s[1] == 'd') { + if (len > 2) { + options->depFileName = s+2; + } else { + fprintf(stderr, "-d option (%d) requires a file.\n", i); + return usage(); + } + } + else if (s[1] == 'p') { + if (len > 2) { + options->preprocessedFiles.push_back(s+2); + } else { + fprintf(stderr, "-p option (%d) requires a file.\n", i); + return usage(); + } + } + else if (len == 2 && s[1] == 'b') { + options->failOnParcelable = true; + } + else { + // s[1] is not known + fprintf(stderr, "unknown option (%d): %s\n", i, s); + return usage(); + } + } else { + // len <= 1 + fprintf(stderr, "unknown option (%d): %s\n", i, s); + return usage(); + } + } else { + // s[0] != '-' + break; + } + i++; + } + + // INPUT + if (i < argc) { + options->inputFileName = argv[i]; + i++; + } else { + fprintf(stderr, "INPUT required\n"); + return usage(); + } + + // OUTPUT + if (i < argc) { + options->outputFileName = argv[i]; + i++; + } else { + // copy input into output and change the extension from .aidl to .java + options->outputFileName = options->inputFileName; + string::size_type pos = options->outputFileName.size()-5; + if (options->outputFileName.compare(pos, 5, ".aidl") == 0) { // 5 = strlen(".aidl") + options->outputFileName.replace(pos, 5, ".java"); // 5 = strlen(".aidl") + } else { + fprintf(stderr, "INPUT is not an .aidl file.\n"); + return usage(); + } + } + + // anything remaining? + if (i != argc) { + fprintf(stderr, "unknown option%s:", (i==argc-1?(const char*)"":(const char*)"s")); + for (; i<argc-1; i++) { + fprintf(stderr, " %s", argv[i]); + } + fprintf(stderr, "\n"); + return usage(); + } + + return 0; +} + diff --git a/tools/aidl/options.h b/tools/aidl/options.h new file mode 100644 index 0000000..dc3c45a --- /dev/null +++ b/tools/aidl/options.h @@ -0,0 +1,33 @@ +#ifndef DEVICE_TOOLS_AIDL_H +#define DEVICE_TOOLS_AIDL_H + +#include <string> +#include <vector> + +using namespace std; + +enum { + COMPILE_AIDL, + PREPROCESS_AIDL +}; + +// This struct is the parsed version of the command line options +struct Options +{ + int task; + bool failOnParcelable; + vector<string> importPaths; + vector<string> preprocessedFiles; + string inputFileName; + string outputFileName; + string depFileName; + + vector<string> filesToPreprocess; +}; + +// takes the inputs from the command line and fills in the Options struct +// Returns 0 on success, and nonzero on failure. +// It also prints the usage statement on failure. +int parse_options(int argc, const char* const* argv, Options *options); + +#endif // DEVICE_TOOLS_AIDL_H diff --git a/tools/aidl/options_test.cpp b/tools/aidl/options_test.cpp new file mode 100644 index 0000000..bd106ce --- /dev/null +++ b/tools/aidl/options_test.cpp @@ -0,0 +1,291 @@ +#include <iostream> +#include "options.h" + +const bool VERBOSE = false; + +using namespace std; + +struct Answer { + const char* argv[8]; + int result; + const char* systemSearchPath[8]; + const char* localSearchPath[8]; + const char* inputFileName; + language_t nativeLanguage; + const char* outputH; + const char* outputCPP; + const char* outputJava; +}; + +bool +match_arrays(const char* const*expected, const vector<string> &got) +{ + int count = 0; + while (expected[count] != NULL) { + count++; + } + if (got.size() != count) { + return false; + } + for (int i=0; i<count; i++) { + if (got[i] != expected[i]) { + return false; + } + } + return true; +} + +void +print_array(const char* prefix, const char* const*expected) +{ + while (*expected) { + cout << prefix << *expected << endl; + expected++; + } +} + +void +print_array(const char* prefix, const vector<string> &got) +{ + size_t count = got.size(); + for (size_t i=0; i<count; i++) { + cout << prefix << got[i] << endl; + } +} + +static int +test(const Answer& answer) +{ + int argc = 0; + while (answer.argv[argc]) { + argc++; + } + + int err = 0; + + Options options; + int result = parse_options(argc, answer.argv, &options); + + // result + if (((bool)result) != ((bool)answer.result)) { + cout << "mismatch: result: got " << result << " expected " << + answer.result << endl; + err = 1; + } + + if (result != 0) { + // if it failed, everything is invalid + return err; + } + + // systemSearchPath + if (!match_arrays(answer.systemSearchPath, options.systemSearchPath)) { + cout << "mismatch: systemSearchPath: got" << endl; + print_array(" ", options.systemSearchPath); + cout << " expected" << endl; + print_array(" ", answer.systemSearchPath); + err = 1; + } + + // localSearchPath + if (!match_arrays(answer.localSearchPath, options.localSearchPath)) { + cout << "mismatch: localSearchPath: got" << endl; + print_array(" ", options.localSearchPath); + cout << " expected" << endl; + print_array(" ", answer.localSearchPath); + err = 1; + } + + // inputFileName + if (answer.inputFileName != options.inputFileName) { + cout << "mismatch: inputFileName: got " << options.inputFileName + << " expected " << answer.inputFileName << endl; + err = 1; + } + + // nativeLanguage + if (answer.nativeLanguage != options.nativeLanguage) { + cout << "mismatch: nativeLanguage: got " << options.nativeLanguage + << " expected " << answer.nativeLanguage << endl; + err = 1; + } + + // outputH + if (answer.outputH != options.outputH) { + cout << "mismatch: outputH: got " << options.outputH + << " expected " << answer.outputH << endl; + err = 1; + } + + // outputCPP + if (answer.outputCPP != options.outputCPP) { + cout << "mismatch: outputCPP: got " << options.outputCPP + << " expected " << answer.outputCPP << endl; + err = 1; + } + + // outputJava + if (answer.outputJava != options.outputJava) { + cout << "mismatch: outputJava: got " << options.outputJava + << " expected " << answer.outputJava << endl; + err = 1; + } + + return err; +} + +const Answer g_tests[] = { + + { + /* argv */ { "test", "-i/moof", "-I/blah", "-Ibleh", "-imoo", "inputFileName.aidl_cpp", NULL, NULL }, + /* result */ 0, + /* systemSearchPath */ { "/blah", "bleh", NULL, NULL, NULL, NULL, NULL, NULL }, + /* localSearchPath */ { "/moof", "moo", NULL, NULL, NULL, NULL, NULL, NULL }, + /* inputFileName */ "inputFileName.aidl_cpp", + /* nativeLanguage */ CPP, + /* outputH */ "", + /* outputCPP */ "", + /* outputJava */ "" + }, + + { + /* argv */ { "test", "inputFileName.aidl_cpp", "-oh", "outputH", NULL, NULL, NULL, NULL }, + /* result */ 0, + /* systemSearchPath */ { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, + /* localSearchPath */ { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, + /* inputFileName */ "inputFileName.aidl_cpp", + /* nativeLanguage */ CPP, + /* outputH */ "outputH", + /* outputCPP */ "", + /* outputJava */ "" + }, + + { + /* argv */ { "test", "inputFileName.aidl_cpp", "-ocpp", "outputCPP", NULL, NULL, NULL, NULL }, + /* result */ 0, + /* systemSearchPath */ { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, + /* localSearchPath */ { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, + /* inputFileName */ "inputFileName.aidl_cpp", + /* nativeLanguage */ CPP, + /* outputH */ "", + /* outputCPP */ "outputCPP", + /* outputJava */ "" + }, + + { + /* argv */ { "test", "inputFileName.aidl_cpp", "-ojava", "outputJava", NULL, NULL, NULL, NULL }, + /* result */ 0, + /* systemSearchPath */ { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, + /* localSearchPath */ { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, + /* inputFileName */ "inputFileName.aidl_cpp", + /* nativeLanguage */ CPP, + /* outputH */ "", + /* outputCPP */ "", + /* outputJava */ "outputJava" + }, + + { + /* argv */ { "test", "inputFileName.aidl_cpp", "-oh", "outputH", "-ocpp", "outputCPP", "-ojava", "outputJava" }, + /* result */ 0, + /* systemSearchPath */ { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, + /* localSearchPath */ { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, + /* inputFileName */ "inputFileName.aidl_cpp", + /* nativeLanguage */ CPP, + /* outputH */ "outputH", + /* outputCPP */ "outputCPP", + /* outputJava */ "outputJava" + }, + + { + /* argv */ { "test", "inputFileName.aidl_cpp", "-oh", "outputH", "-oh", "outputH1", NULL, NULL }, + /* result */ 1, + /* systemSearchPath */ { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, + /* localSearchPath */ { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, + /* inputFileName */ "", + /* nativeLanguage */ CPP, + /* outputH */ "", + /* outputCPP */ "", + /* outputJava */ "" + }, + + { + /* argv */ { "test", "inputFileName.aidl_cpp", "-ocpp", "outputCPP", "-ocpp", "outputCPP1", NULL, NULL }, + /* result */ 1, + /* systemSearchPath */ { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, + /* localSearchPath */ { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, + /* inputFileName */ "", + /* nativeLanguage */ CPP, + /* outputH */ "", + /* outputCPP */ "", + /* outputJava */ "" + }, + + { + /* argv */ { "test", "inputFileName.aidl_cpp", "-ojava", "outputJava", "-ojava", "outputJava1", NULL, NULL }, + /* result */ 1, + /* systemSearchPath */ { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, + /* localSearchPath */ { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, + /* inputFileName */ "", + /* nativeLanguage */ CPP, + /* outputH */ "", + /* outputCPP */ "", + /* outputJava */ "" + }, + +}; + +int +main(int argc, const char** argv) +{ + const int count = sizeof(g_tests)/sizeof(g_tests[0]); + int matches[count]; + + int result = 0; + for (int i=0; i<count; i++) { + if (VERBOSE) { + cout << endl; + cout << "---------------------------------------------" << endl; + const char* const* p = g_tests[i].argv; + while (*p) { + cout << " " << *p; + p++; + } + cout << endl; + cout << "---------------------------------------------" << endl; + } + matches[i] = test(g_tests[i]); + if (VERBOSE) { + if (0 == matches[i]) { + cout << "passed" << endl; + } else { + cout << "failed" << endl; + } + result |= matches[i]; + } + } + + cout << endl; + cout << "=============================================" << endl; + cout << "options_test summary" << endl; + cout << "=============================================" << endl; + + if (!result) { + cout << "passed" << endl; + } else { + cout << "failed the following tests:" << endl; + for (int i=0; i<count; i++) { + if (matches[i]) { + cout << " "; + const char* const* p = g_tests[i].argv; + while (*p) { + cout << " " << *p; + p++; + } + cout << endl; + } + } + } + + return result; +} + diff --git a/tools/aidl/search_path.cpp b/tools/aidl/search_path.cpp new file mode 100644 index 0000000..3c4e14b --- /dev/null +++ b/tools/aidl/search_path.cpp @@ -0,0 +1,56 @@ +#include <unistd.h> +#include "search_path.h" +#include "options.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..8d85d81 --- /dev/null +++ b/tools/aidl/search_path.h @@ -0,0 +1,22 @@ +#ifndef DEVICE_TOOLS_AIDL_SEARCH_PATH_H +#define DEVICE_TOOLS_AIDL_SEARCH_PATH_H + +#include <stdio.h> + +#if __cplusplus +#include <vector> +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 + |