654 lines
22 KiB
C++
654 lines
22 KiB
C++
|
#include "generate_java.h"
|
||
|
#include "AST.h"
|
||
|
#include "Type.h"
|
||
|
#include <string.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
// =================================================
|
||
|
class VariableFactory
|
||
|
{
|
||
|
public:
|
||
|
VariableFactory(const string& base); // base must be short
|
||
|
Variable* Get(Type* type);
|
||
|
Variable* Get(int index);
|
||
|
private:
|
||
|
vector<Variable*> m_vars;
|
||
|
string m_base;
|
||
|
int m_index;
|
||
|
};
|
||
|
|
||
|
VariableFactory::VariableFactory(const string& base)
|
||
|
:m_base(base),
|
||
|
m_index(0)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
Variable*
|
||
|
VariableFactory::Get(Type* type)
|
||
|
{
|
||
|
char name[100];
|
||
|
sprintf(name, "%s%d", m_base.c_str(), m_index);
|
||
|
m_index++;
|
||
|
Variable* v = new Variable(type, name);
|
||
|
m_vars.push_back(v);
|
||
|
return v;
|
||
|
}
|
||
|
|
||
|
Variable*
|
||
|
VariableFactory::Get(int index)
|
||
|
{
|
||
|
return m_vars[index];
|
||
|
}
|
||
|
|
||
|
// =================================================
|
||
|
class StubClass : public Class
|
||
|
{
|
||
|
public:
|
||
|
StubClass(Type* type, Type* interfaceType);
|
||
|
virtual ~StubClass();
|
||
|
|
||
|
Variable* transact_code;
|
||
|
Variable* transact_data;
|
||
|
Variable* transact_reply;
|
||
|
Variable* transact_flags;
|
||
|
SwitchStatement* transact_switch;
|
||
|
private:
|
||
|
void make_as_interface(Type* interfaceType);
|
||
|
};
|
||
|
|
||
|
StubClass::StubClass(Type* type, Type* interfaceType)
|
||
|
:Class()
|
||
|
{
|
||
|
this->comment = "/** Local-side IPC implementation stub class. */";
|
||
|
this->modifiers = PUBLIC | ABSTRACT | STATIC;
|
||
|
this->what = Class::CLASS;
|
||
|
this->type = type;
|
||
|
this->extends = BINDER_NATIVE_TYPE;
|
||
|
this->interfaces.push_back(interfaceType);
|
||
|
|
||
|
// descriptor
|
||
|
Field* descriptor = new Field(STATIC | FINAL | PRIVATE,
|
||
|
new Variable(STRING_TYPE, "DESCRIPTOR"));
|
||
|
descriptor->value = "\"" + interfaceType->QualifiedName() + "\"";
|
||
|
this->elements.push_back(descriptor);
|
||
|
|
||
|
// ctor
|
||
|
Method* ctor = new Method;
|
||
|
ctor->modifiers = PUBLIC;
|
||
|
ctor->comment = "/** Construct the stub at attach it to the "
|
||
|
"interface. */";
|
||
|
ctor->name = "Stub";
|
||
|
ctor->statements = new StatementBlock;
|
||
|
MethodCall* attach = new MethodCall(THIS_VALUE, "attachInterface",
|
||
|
2, THIS_VALUE, new LiteralExpression("DESCRIPTOR"));
|
||
|
ctor->statements->Add(attach);
|
||
|
this->elements.push_back(ctor);
|
||
|
|
||
|
// asInterface
|
||
|
make_as_interface(interfaceType);
|
||
|
|
||
|
// asBinder
|
||
|
Method* asBinder = new Method;
|
||
|
asBinder->modifiers = PUBLIC;
|
||
|
asBinder->returnType = IBINDER_TYPE;
|
||
|
asBinder->name = "asBinder";
|
||
|
asBinder->statements = new StatementBlock;
|
||
|
asBinder->statements->Add(new ReturnStatement(THIS_VALUE));
|
||
|
this->elements.push_back(asBinder);
|
||
|
|
||
|
// onTransact
|
||
|
this->transact_code = new Variable(INT_TYPE, "code");
|
||
|
this->transact_data = new Variable(PARCEL_TYPE, "data");
|
||
|
this->transact_reply = new Variable(PARCEL_TYPE, "reply");
|
||
|
this->transact_flags = new Variable(INT_TYPE, "flags");
|
||
|
Method* onTransact = new Method;
|
||
|
onTransact->modifiers = PUBLIC | OVERRIDE;
|
||
|
onTransact->returnType = BOOLEAN_TYPE;
|
||
|
onTransact->name = "onTransact";
|
||
|
onTransact->parameters.push_back(this->transact_code);
|
||
|
onTransact->parameters.push_back(this->transact_data);
|
||
|
onTransact->parameters.push_back(this->transact_reply);
|
||
|
onTransact->parameters.push_back(this->transact_flags);
|
||
|
onTransact->statements = new StatementBlock;
|
||
|
onTransact->exceptions.push_back(REMOTE_EXCEPTION_TYPE);
|
||
|
this->elements.push_back(onTransact);
|
||
|
this->transact_switch = new SwitchStatement(this->transact_code);
|
||
|
|
||
|
onTransact->statements->Add(this->transact_switch);
|
||
|
MethodCall* superCall = new MethodCall(SUPER_VALUE, "onTransact", 4,
|
||
|
this->transact_code, this->transact_data,
|
||
|
this->transact_reply, this->transact_flags);
|
||
|
onTransact->statements->Add(new ReturnStatement(superCall));
|
||
|
}
|
||
|
|
||
|
StubClass::~StubClass()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
void
|
||
|
StubClass::make_as_interface(Type *interfaceType)
|
||
|
{
|
||
|
Variable* obj = new Variable(IBINDER_TYPE, "obj");
|
||
|
|
||
|
Method* m = new Method;
|
||
|
m->comment = "/**\n * Cast an IBinder object into an ";
|
||
|
m->comment += interfaceType->QualifiedName();
|
||
|
m->comment += " interface,\n";
|
||
|
m->comment += " * generating a proxy if needed.\n */";
|
||
|
m->modifiers = PUBLIC | STATIC;
|
||
|
m->returnType = interfaceType;
|
||
|
m->name = "asInterface";
|
||
|
m->parameters.push_back(obj);
|
||
|
m->statements = new StatementBlock;
|
||
|
|
||
|
IfStatement* ifstatement = new IfStatement();
|
||
|
ifstatement->expression = new Comparison(obj, "==", NULL_VALUE);
|
||
|
ifstatement->statements = new StatementBlock;
|
||
|
ifstatement->statements->Add(new ReturnStatement(NULL_VALUE));
|
||
|
m->statements->Add(ifstatement);
|
||
|
|
||
|
// IInterface iin = obj.queryLocalInterface(DESCRIPTOR)
|
||
|
MethodCall* queryLocalInterface = new MethodCall(obj, "queryLocalInterface");
|
||
|
queryLocalInterface->arguments.push_back(new LiteralExpression("DESCRIPTOR"));
|
||
|
IInterfaceType* iinType = new IInterfaceType();
|
||
|
Variable *iin = new Variable(iinType, "iin");
|
||
|
VariableDeclaration* iinVd = new VariableDeclaration(iin, queryLocalInterface, 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, "(android.os.IBinder.FIRST_CALL_TRANSACTION + %d)", index);
|
||
|
|
||
|
Field* transactCode = new Field(STATIC | FINAL,
|
||
|
new Variable(INT_TYPE, transactCodeName));
|
||
|
transactCode->value = transactCodeValue;
|
||
|
stubClass->elements.push_back(transactCode);
|
||
|
|
||
|
// == the declaration in the interface ===================================
|
||
|
Method* decl = new Method;
|
||
|
decl->comment = gather_comments(method->comments_token->extra);
|
||
|
decl->modifiers = PUBLIC;
|
||
|
decl->returnType = NAMES.Search(method->type.type.data);
|
||
|
decl->returnTypeDimension = method->type.dimension;
|
||
|
decl->name = method->name.data;
|
||
|
|
||
|
arg = method->args;
|
||
|
while (arg != NULL) {
|
||
|
decl->parameters.push_back(new Variable(
|
||
|
NAMES.Search(arg->type.type.data), arg->name.data,
|
||
|
arg->type.dimension));
|
||
|
arg = arg->next;
|
||
|
}
|
||
|
|
||
|
decl->exceptions.push_back(REMOTE_EXCEPTION_TYPE);
|
||
|
|
||
|
interface->elements.push_back(decl);
|
||
|
|
||
|
// == the stub method ====================================================
|
||
|
|
||
|
Case* c = new Case(transactCodeName);
|
||
|
|
||
|
MethodCall* realCall = new MethodCall(THIS_VALUE, method->name.data);
|
||
|
|
||
|
// interface token validation is the very first thing we do
|
||
|
c->statements->Add(new MethodCall(stubClass->transact_data,
|
||
|
"enforceInterface", 1, new LiteralExpression("DESCRIPTOR")));
|
||
|
|
||
|
// args
|
||
|
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 ? "android.os.IBinder.FLAG_ONEWAY" : "0"));
|
||
|
tryStatement->statements->Add(call);
|
||
|
|
||
|
// throw back exceptions.
|
||
|
if (_reply) {
|
||
|
MethodCall* ex = new MethodCall(_reply, "readException", 0);
|
||
|
tryStatement->statements->Add(ex);
|
||
|
}
|
||
|
|
||
|
// returning and cleanup
|
||
|
if (_reply != NULL) {
|
||
|
if (_result != NULL) {
|
||
|
generate_create_from_parcel(proxy->returnType,
|
||
|
tryStatement->statements, _result, _reply);
|
||
|
}
|
||
|
|
||
|
// 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;
|
||
|
}
|
||
|
|