/*
 * Copyright (c) 1992-1993 Silicon Graphics, Inc.
 * Copyright (c) 1993 Fujitsu, Ltd.
 *
 * Permission to use, copy, modify, distribute, and sell this software and 
 * its documentation for any purpose is hereby granted without fee, provided
 * that (i) the above copyright notices and this permission notice appear in
 * all copies of the software and related documentation, and (ii) the names of
 * Silicon Graphics and Fujitsu may not be used in any advertising or
 * publicity relating to the software without the specific, prior written
 * permission of Silicon Graphics and Fujitsu.
 *
 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
 *
 * IN NO EVENT SHALL SILICON GRAPHICS OR FUJITSU BE LIABLE FOR
 * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
 * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
 * OF THIS SOFTWARE.
 */

/*
 * Generate code
 */

#include "generator.h"

Boolean ExprImpl::generate_stub(Generator*) { return false; }
Boolean ExprImpl::generate_marshal(Generator*) { return false; }
Boolean ExprImpl::generate_unmarshal(Generator*) { return false; }

Boolean IdentifierImpl::generate_stub(Generator* g) { return generate(g); }
Boolean IdentifierImpl::generate_marshal(Generator* g) { return generate(g); }

Boolean IdentifierImpl::generate_unmarshal(Generator* g) {
    return generate(g);
}

void InterfaceDef::put_stub_hdr(Generator* g) {
    String* s = ident_->string();
    g->emit("\nclass %I%C : public %I {\n", s);
    g->emit("public:\n%i%I%C(%O*);\n~%I%C();\n\n", s);
#ifdef notdef
    g->emit("static %S%p _create(%O*);\n");
#endif
    g->emit("%O* _exchange();\n");
    g->emit("%uprotected:\n%i");
    g->emit("%O* exch_;\n");
    g->emit("%u};\n");
}

Boolean InterfaceDef::generate_stub(Generator* g) {
    String* s = ident_->string();
    g->emit("%Q%C::%I%C(%O* e) { exch_ = e; }\n", s);
    g->emit("%Q%C::~%I%C() { }\n", s);
//  g->emit("%S%p %Q%C::_create(%O* e) {%i\n", s);
    g->emit("%S%p _%_%I%C_create(%O* e) {%i\n", s);
    g->emit("return (%S%p)(void*)new %Q%C(e);\n%u}\n", s);
    g->emit("%O* %Q%C::_exchange() {%i\nreturn exch_;\n%u}\n", s);
    if (defs_ != nil) {
	g->enter_scope(info_->block);
	for (ListItr(ExprList) i(*defs_); i.more(); i.next()) {
	    Expr* e = i.cur();
	    Symbol* sym = e->symbol();
	    if (sym != nil) {
		switch (sym->tag()) {
		case Symbol::sym_operation:
		case Symbol::sym_attribute:
		    e->generate_stub(g);
		    break;
		default:
		    break;
		}
	    }
	}
	g->leave_scope();
    }
    return true;
}

Boolean Operation::generate_stub(Generator* g) {
    String* s = ident_->string();
    Boolean has_return_value = !g->void_type(type_);
    Boolean has_marshal = has_marshal_funcs(g);
    long nparams = (params_ == nil) ? 1 : params_->count() + 1;
    long rdesc;
    if (oneway_) {
	rdesc = g->symbol_table()->oneway_type()->typename()->kind();
    } else {
	rdesc = type_desc(g, type_);
    }
    g->emit("%B::ArgDesc _%_%N_pdesc[", nil, this);
    g->emit_integer(nparams + 1);
    g->emit("] = { ");
    g->emit_integer(nparams);
    g->emit(", ");
    g->emit_integer(rdesc << 2);
    if (params_ != nil) {
	generate_param_desc(g);
    }
    g->emit(" };\n");
    if (has_marshal) {
	g->emit("%B::ArgMarshal _%_%N_pfunc[] = {\n%i", nil, this);
	g->need_sep(false);
	if (params_ != nil) {
	    generate_param_marshal(g);
	}
	if (g->need_sep(false)) {
	    g->emit(",\n");
	}
	g->need_sep(generate_marshal_func(g, type_));
	g->emit("\n%u};\n");
    }

    g->emit("%B::ArgInfo _%_%N_pinfo = {\n%i", nil, this);
    g->emit("&_%_tid, ");
    g->emit_integer(index_);
    g->emit(", _%_%N_pdesc, ", nil, this);
    if (has_marshal) {
	g->emit("_%_%N_pfunc", nil, this);
    } else {
	g->emit("0");
    }
    g->emit("\n%u};\n");

    g->emit("%F %:%I", s, type_);
    g->emit_param_list(params_, Generator::emit_env_formals_body);
    g->emit(" {\n%i%B _b;\n");
    g->emit("extern %MId _%_tid;\n");
    g->emit("%B::ArgValue ");
    generate_arg(g, nparams, ";\n");
    if (rdesc == 0) {
	/* pass address of return value */
	g->emit("%F _result;\n", nil, type_);
	generate_arg(g, 0, ".u_addr = &_result;\n");
    }
    if (params_ != nil) {
	generate_param_value(g);
    }
    g->emit("_b.invoke(");
    interface_->put_cast_up(g);
    g->emit("this, _%_%N_pinfo, _arg%,%a);\n", nil, this);
    if (has_return_value) {
	generate_return_value(g, type_);
    }
    g->emit("%u}\n");
    if (g->cstubs()) {
	g->emit("extern \"C\" %F ", nil, type_);
	g->emit("%_%N(%b%i", nil, this);
	g->emit("%F%p _this", nil, interface_->ident());
	if (params_ != nil) {
	    g->emit(", ");
	    g->emit_param_decls(params_, Generator::emit_env_formals_body);
	}
	g->emit("%b%u) {\n%i");
	if (has_return_value) {
	    g->emit("return ");
	}
	g->emit("_this->%I", s);
	g->emit_param_list(params_, Generator::emit_env_actuals);
	g->emit(";\n%u}\n");
    }
    return true;
}

long Operation::type_desc(Generator* g, Expr* e) {
    Symbol* s = g->actual_type(e);
    long rdesc;
    switch (s->tag()) {
    case Symbol::sym_enum:
	rdesc = g->symbol_table()->long_type()->typename()->kind();
	break;
    case Symbol::sym_string:
	rdesc = g->symbol_table()->string_type()->typename()->kind();
	break;
    case Symbol::sym_typedef:
	rdesc = s->typename()->kind();
	break;
    case Symbol::sym_interface:
	rdesc = s->interface()->kind();
	break;
    default:
	rdesc = 0;
	break;
    }
    return rdesc;
}

Boolean Operation::generate_marshal_func(Generator* g, Expr* e) {
    Boolean b = true;
    Symbol* s = g->actual_type(e);
    switch (s->tag()) {
    case Symbol::sym_string:
    case Symbol::sym_typedef:
    case Symbol::sym_enum:
	/* don't need marshal functions */
	b = false;
	break;
    case Symbol::sym_interface:
	b = g->interface_is_ref(false);
	g->emit("&_%Y%C_create", nil, e);
	g->interface_is_ref(b);
	break;
    case Symbol::sym_sequence:
	g->emit("&_%Y_put, &_%Y_get", nil, s->sequence_type());
	break;
    default:
	g->emit("&_%Y_put, &_%Y_get", nil, e);
	break;
    }
    return b;
}

Boolean Operation::has_marshal(Generator* g, Expr* e) {
    switch (g->actual_type(e)->tag()) {
    case Symbol::sym_string:
    case Symbol::sym_typedef:
    case Symbol::sym_enum:
	return false;
    }
    return true;
}

Boolean Operation::has_marshal_funcs(Generator* g) {
    if (has_marshal(g, type_)) {
	return true;
    }
    if (params_ != nil) {
	for (ListItr(ExprList) e(*params_); e.more(); e.next()) {
	    Parameter* p = e.cur()->symbol()->parameter();
	    /* valid params_ => p != nil */
	    Declarator* d = p->declarator();
	    Expr* t = (d->subscripts() != nil) ? d : p->type();
	    if (has_marshal(g, t)) {
		return true;
	    }
	}
    }
    return false;
}

void Operation::generate_param_desc(Generator* g) {
    for (ListItr(ExprList) e(*params_); e.more(); e.next()) {
	g->emit(", ");
	Parameter* p = e.cur()->symbol()->parameter();
	/* valid params_ => p != nil */
	g->emit_integer(p->attr() | (type_desc(g, p) << 2));
    }
}

void Operation::generate_param_marshal(Generator* g) {
    for (ListItr(ExprList) e(*params_); e.more(); e.next()) {
	if (g->need_sep(false)) {
	    g->emit(",\n");
	}
	Parameter* p = e.cur()->symbol()->parameter();
	/* valid params_ => p != nil */
	Declarator* d = p->declarator();
	Expr* t = (d->subscripts() != nil) ? d : p->type();
	g->need_sep(generate_marshal_func(g, t));
    }
}

void Operation::generate_param_value(Generator* g) {
    int n = 1;
    for (ListItr(ExprList) e(*params_); e.more(); e.next(), n++) {
	Parameter* p = e.cur()->symbol()->parameter();
	/* valid params_ => p != nil */
	Boolean in_param = (p->attr() == ExprKit::in_param);
	Declarator* d = p->declarator();
	Identifier* name = d->ident();
	Symbol* s = g->actual_type(d);
	switch (s->tag()) {
	case Symbol::sym_string:
	    if (in_param) {
		generate_arg(g, n, ".u_string = ");
		g->emit("%E;\n", nil, name);
	    }
	    break;
	case Symbol::sym_typedef:
	    if (in_param) {
		generate_arg(g, n, ".u_");
		g->emit("%I = %E;\n", s->typename()->str(), name);
	    }
	    break;
	case Symbol::sym_enum:
	    if (in_param) {
		generate_arg(g, n, ".u_long = ");
		g->emit("%E;\n", nil, name);
	    }
	    break;
	case Symbol::sym_interface:
	    if (in_param) {
		generate_arg(g, n, ".u_objref = ");
		g->emit("%E;\n", nil, name);
	    }
	    break;
	default:
	    in_param = false;
	    break;
	}
	if (!in_param) {
	    generate_arg(g, n, ".u_addr = ");
	    if (s->tag() != Symbol::sym_array) {
		g->emit("&");
	    }
	    g->emit("%E;\n", nil, name);
	}
    }
}

void Operation::generate_return_value(Generator* g, Expr* t) {
    Symbol* s = g->actual_type(t);
    g->emit("return ");
    switch (s->tag()) {
    case Symbol::sym_enum:
	g->emit("(%F)_arg[0].u_long", nil, t);
	break;
    case Symbol::sym_interface:
	g->emit("(%F)_arg[0].u_objref", nil, t);
	break;
    case Symbol::sym_string:
	g->emit("_arg[0].u_string");
	break;
    case Symbol::sym_typedef:
	g->emit("_arg[0].u_%I", s->typename()->str());
	break;
    default:
	g->emit("_result");
	break;
    }
    g->emit(";\n");
}

void Operation::generate_arg(Generator* g, long n, const char* str) {
    g->emit("_arg[");
    g->emit_integer(n);
    g->emit("]");
    g->emit(str);
}

Boolean Parameter::generate_stub(Generator* g) {
    if (attr_ != ExprKit::out_param) {
	g->emit_put(type_, "%E", declarator_);
	return true;
    }
    return false;
}

/*
 * Generate extern decls for stubs for data types.
 */

Boolean ExprImpl::generate_extern_stubs(Generator*) { return false; }
Boolean IdentifierImpl::generate_extern_stubs(Generator*) { return false; }

Boolean InterfaceDef::generate_extern_stubs(Generator* g) {
    Boolean b = false;
    if (defs_ != nil) {
	g->enter_scope(info_->block);
	if (generate_list(defs_, &Expr::generate_extern_stubs, g)) {
	    g->emit("\n");
	    b = true;
	}
	g->leave_scope();
    }
    return b;
}

Boolean TypeName::generate_extern_stubs(Generator* g) {
    Boolean (Expr::*func)(Generator*) = &Expr::generate_extern_stubs;
    return (
	type_ != nil && (
	    g->emit_extern_stubs(type_) |
	    generate_list(declarators_, func, g)
	)
    );
}

Boolean StructDecl::generate_extern_stubs(Generator* g) {
    return generate_list(members_, &Expr::generate_extern_stubs, g);
}

Boolean StructMember::generate_extern_stubs(Generator* g) {
    Boolean (Expr::*func)(Generator*) = &Expr::generate_extern_stubs;
    return (
	g->emit_extern_stubs(type_) |
	generate_list(declarators_, func, g)
    );
}

Boolean UnionDecl::generate_extern_stubs(Generator* g) {
    Boolean b = g->emit_extern_stubs(type_);
    for (ListItr(CaseList) i(*cases_); i.more(); i.next()) {
	b |= i.cur()->element()->generate_extern_stubs(g);
    }
    return b;
}

Boolean SequenceDecl::generate_extern_stubs(Generator* g) {
    return g->emit_extern_stubs(type_);
}

Boolean Operation::generate_extern_stubs(Generator* g) {
    Boolean (Expr::*func)(Generator*) = &Expr::generate_extern_stubs;
    return (
	g->emit_extern_stubs(type_) |
	generate_list(params_, func, g)
    );
}

Boolean Parameter::generate_extern_stubs(Generator* g) {
    return (
	g->emit_extern_stubs(type_) | declarator_->generate_extern_stubs(g)
    );
}

Boolean Declarator::generate_extern_stubs(Generator* g) {
    long f = g->file_mask();
    if (subscripts_ != nil && !symbol_->declared_stub(f)) {
	g->emit("extern void _%Y_put(\n%i%B&, %b", nil, this);
	g->emit("const %F ", nil, element_type_);
	g->emit("%E\n%u);\n", nil, this);
	g->emit("extern void _%Y_get(\n%i%B&, %b", nil, this);
	g->emit("%F ", nil, element_type_);
	g->emit("%E\n%u);\n", nil, this);
	symbol_->declare_stub(f);
	return true;
    }
    return false;
}

/*
 * Generate stubs for types.  These are separated out because,
 * unlike the method/attribute stubs, these should be shared between
 * client and server code.
 */

Boolean ExprImpl::generate_types(Generator*) { return false; }
Boolean IdentifierImpl::generate_types(Generator*) { return false; }

Boolean Module::generate_types(Generator* g) {
    Boolean b = false;
    if (defs_ != nil) {
	Boolean excepts = block_->except_index > 0;
	g->emit_type_info(ident_->string(), "Ref", nil, false, excepts, false);
	g->enter_scope(block_);
	if (excepts) {
	    put_except_list(defs_, g);
	}
	if (generate_list(defs_, &Expr::generate_def, g)) {
	    g->emit("\n");
	}
	b = RootExpr::put_list(defs_, &RootExpr::put_stubs, g);
	g->leave_scope();
    }
    return b;
}

Boolean InterfaceDef::generate_types(Generator* g) {
    Boolean b = false;
    if (defs_ != nil) {
	g->enter_scope(info_->block);
	b = generate_list(defs_, &Expr::generate_types, g);
	if (info_->block->except_index != 0) {
	    b = put_except_list(defs_, g);
	}
	g->leave_scope();
    }
    return b;
}

Boolean ExprImpl::put_except_list(ExprList* defs, Generator* g) {
    g->emit("%M_UnmarshalException _%_excepts[] = {\n%i");
    g->need_sep(false);
    for (ListItr(ExprList) i(*defs); i.more(); i.next()) {
	Symbol* s = i.cur()->symbol();
	if (s != nil && s->tag() == Symbol::sym_exception) {
	    if (g->need_sep(true)) {
		g->emit(",\n");
	    }
	    ExceptDecl* e = s->except_type();
	    g->emit("&%:%I::_get", e->ident()->string());
	}
    }
    g->emit("\n%u};\n");
    return true;
}

Boolean TypeName::generate_types(Generator* g) {
    Boolean (Expr::*func)(Generator*) = &Expr::generate_types;
    return (
	type_->generate_types(g) ||
	generate_list(declarators_, func, g)
    );
}

Boolean StructDecl::generate_types(Generator* g) {
    g->enter_scope(block_);
    generate_list(members_, &Expr::generate_types, g);
    g->leave_scope();

    String* s = ident_->string();
    g->emit("void _%_%I_put(%B& _b, const %F& _this) {\n%i", s, this);
    generate_list(members_, &Expr::generate_marshal, g);
    g->emit("%u}\n");

    g->emit("void _%_%I_get(%B& _b, %F& _this) {\n%i", s, this);
    generate_list(members_, &Expr::generate_unmarshal, g);
    g->emit("%u}\n");
    return true;
}

Boolean StructMember::generate_types(Generator* g) {
    Boolean (Expr::*func)(Generator*) = &Expr::generate_types;
    return (
	type_->generate_types(g) ||
	generate_list(declarators_, func, g)
    );
}

Boolean StructMember::generate_marshal(Generator* g) {
    for (ListItr(ExprList) i(*declarators_); i.more(); i.next()) {
	g->emit_put(type_, "_this.%E", i.cur());
    }
    return true;
}

Boolean StructMember::generate_unmarshal(Generator* g) {
    for (ListItr(ExprList) i(*declarators_); i.more(); i.next()) {
	g->emit_get(type_, "_this.%E", i.cur());
    }
    return true;
}

Boolean UnionDecl::generate_types(Generator* g) {
    g->enter_scope(block_);
    for (ListItr(CaseList) c(*cases_); c.more(); c.next()) {
	c.cur()->element()->generate_types(g);
    }
    /*
     * Need two leave scopes for extra union scope.
     */
    g->leave_scope();
    g->leave_scope();

    String* s = ident_->string();
    g->emit("void _%_%I_put(%B& _b, const %F& _this) {\n%i", s, this);
    g->emit_put(type_, "_this._d()", type_);
    g->emit("switch (_this._d()) {\n");
    for (ListItr(CaseList) i(*cases_); i.more(); i.next()) {
	i.cur()->generate_copy(&Expr::generate_marshal, g);
    }
    g->emit("}\n%u}\n");

    g->emit("void _%_%I_get(%B& _b, %F& _this) {\n%i", s, this);
    g->emit_get(type_, "_this._d()", type_);
    g->emit("switch (_this._d()) {\n");
    for (ListItr(CaseList) j(*cases_); j.more(); j.next()) {
	j.cur()->generate_copy(&Expr::generate_unmarshal, g);
    }
    g->emit("}\n%u}\n");
    return true;
}

Boolean CaseElement::generate_copy(
    Boolean (Expr::*func)(Generator*), Generator* g
) {
    generate_list(labels_, func, g);
    g->emit("%i");
    (element_->*func)(g);
    g->emit("break;\n%u");
    return true;
}

Boolean UnionMember::generate_marshal(Generator* g) {
    for (ListItr(ExprList) i(*declarators_); i.more(); i.next()) {
	g->emit_put(type_, "_this.%E()", i.cur());
    }
    return true;
}

Boolean UnionMember::generate_unmarshal(Generator* g) {
    for (ListItr(ExprList) i(*declarators_); i.more(); i.next()) {
	g->emit_get(type_, "_this.%E()", i.cur());
    }
    return true;
}

Boolean CaseLabel::label(Generator* g) {
    g->emit("case %X:\n", nil, value_);
    return true;
}

Boolean DefaultLabel::generate_marshal(Generator* g) { return label(g); }
Boolean DefaultLabel::generate_unmarshal(Generator* g) { return label(g); }

Boolean DefaultLabel::label(Generator* g) {
    g->emit("default:\n");
    return true;
}

Boolean SequenceDecl::generate_types(Generator* g) {
    g->emit("void _%Y_put(%B& _b, const %F& _this) {\n%i", nil, this);
    generate_marshal(g);
    g->emit("%u}\n");

    g->emit("void _%Y_get(%B& _b, %F& _this) {\n%i", nil, this);
    generate_unmarshal(g);
    g->emit("%u}\n");
    return true;
}

Boolean SequenceDecl::generate_marshal(Generator* g) {
    Symbol* s = g->actual_type(type_);
    if (s->tag() == Symbol::sym_typedef &&
	s != g->symbol_table()->string_type()
    ) {
	/* builtin type */
	g->emit("_b.put_seq(&_this, ");
	g->emit("sizeof(%F));\n", nil, type_);
    } else {
	g->emit("long _i;\n");
	g->emit("_b.put_seq_hdr(&_this);\n");
	g->emit("for (_i = 0; _i < _this._length; _i++) {\n%i");
	g->emit_put(type_, "_this._buffer[_i]", type_);
	g->emit("%u}\n");
    }
    return true;
}

Boolean SequenceDecl::generate_unmarshal(Generator* g) {
    Symbol* s = g->actual_type(type_);
    if (s->tag() == Symbol::sym_typedef &&
	s != g->symbol_table()->string_type()
    ) {
	/* builtin type */
	g->emit("_b.get_seq(&_this, sizeof(%F));\n", nil, type_);
    } else {
	g->emit("Long _i;\n");
	g->emit("_b.get_seq_hdr(&_this);\n_this._buffer = ");
	g->emit(
	    "(_this._maximum == 0) ? 0 : new %F[_this._maximum];\n",
	    nil, type_
	);
	g->emit("for (_i = 0; _i < _this._length; _i++) {\n%i");
	g->emit_get(type_, "_this._buffer[_i]", type_);
	g->emit("%u}\n");
    }
    return true;
}

Boolean ExceptDecl::generate_types(Generator* g) {
    g->enter_scope(block_);
    generate_list(members_, &Expr::generate_types, g);
    g->leave_scope();

    String* s = ident_->string();
    g->emit("void %Q::_put(%B& _b) const {\n%i", s);
    g->emit("_b.put_long(_%_tid);\n", s);
    g->emit("_b.put_long(_major_);\n");
    if (members_ != nil) {
	g->emit("const %F& _this = *this;\n", nil, this);
	generate_list(members_, &Expr::generate_marshal, g);
    }
    g->emit("%u}\n");

    /*
     * The output code is a little strange because it uses
     * a reference temporary and then returns its address.
     * This usage is necessary because the member unmarshal code
     * assumes _this is an object rather than a pointer.
     */
    g->emit("%x* %Q::_get(%B&", s);
    if (members_ == nil) {
	g->emit(") { return new %I; }\n", s);
    } else {
	g->emit(" _b) {\n%i%F& _this = *(new %I);\n", s, this);
	generate_list(members_, &Expr::generate_unmarshal, g);
	g->emit("return &_this;\n%u}\n");
    }
    return true;
}

Boolean Operation::generate_types(Generator* g) {
    Boolean (Expr::*func)(Generator*) = &Expr::generate_types;
    return (
	type_->generate_types(g) ||
	generate_list(params_, func, g)
    );
}

Boolean Parameter::generate_types(Generator* g) {
    return type_->generate_types(g) || declarator_->generate_types(g);
}

Boolean Declarator::generate_types(Generator* g) {
    if (subscripts_ != nil) {
	Expr* t = element_type_;
	g->emit("void _%Y_put(%b%i%B& _b, ", nil, this);
	g->emit("const %F _array[", nil, t);
	generate_list(subscripts_, &Expr::generate, g, "][");
	g->emit("]%b%u) {%i\n", nil, this);
	g->emit_array_setup(this, t, true);
	g->emit_put(t, "_tmp", t);
	g->emit_array_loop_finish(subscripts_->count());
	g->emit("%u}\n");

	g->emit("void _%Y_get(%b%i%B& _b, ", nil, this);
	g->emit("%F _array[", nil, t);
	generate_list(subscripts_, &Expr::generate, g, "][");
	g->emit("]%b%u) {%i\n", nil, this);
	g->emit_array_setup(this, t, false);
	g->emit_get(t, "_tmp", t);
	g->emit_array_loop_finish(subscripts_->count());
	g->emit("%u}\n");
	return true;
    }
    return false;
}

/*
 * Put out the code to perform a call accessing the parameters
 * through a MarshalBuffer.
 */

void InterfaceDef::put_receive(Generator* g) {
    String* s = ident_->string();
    g->emit("void _%_%I_receive(", s);
    g->emit("%S%p _object, ULong _m, %B& _b) {\n%i");
    g->emit("extern %MId %T;\n", s);
    g->emit("%:%I%p _this = (%:%I%p)_%S_tcast(_object, %T);\n", s);
    if (g->envclass() != nil) {
	g->emit(g->envclass());
	g->emit("* _env = _b.env();\n");
    }
    g->emit("switch (_m) {\n%i");
    g->enter_scope(info_->block);
    if (!generate_list(defs_, &Expr::generate_receive, g)) {
	g->emit("default:\n%ibreak;\n%u");
    }
    g->leave_scope();
    g->emit("%u}\n%u}\n");
}

Boolean ExprImpl::generate_receive(Generator*) { return false; }
Boolean IdentifierImpl::generate_receive(Generator*) { return false; }

Boolean Operation::generate_receive(Generator* g) {
    String* s = ident_->string();
    Boolean has_return = !g->void_type(type_);
    Boolean param_marshal = has_marshal_funcs(g);
    g->emit("case /* %N */ ", nil, this);
    g->emit_integer(index_);
    g->emit(": {\n%i");
    g->emit("extern %B::ArgInfo _%_%N_pinfo;\n", nil, this);
    g->emit("%B::ArgValue ");
    long nparams = params_ == nil ? 1 : params_->count() + 1;
    generate_arg(g, nparams, ";\n");
    if (params_ != nil) {
	long n = 1;
	for (ListItr(ExprList) e(*params_); e.more(); e.next(), n++) {
	    Parameter* p = e.cur()->symbol()->parameter();
	    /* valid params_ => p != nil */
	    generate_receive_addr(g, n, p->type(), p->declarator());
	}
	g->emit("_b.receive(_%_%N_pinfo, _arg);\n", nil, this);
    }
    long rdesc = type_desc(g, type_);
    if (has_return) {
	if (rdesc == 0) {
	    g->emit("%F _result = ", nil, type_);
	} else {
	    generate_receive_asg(g, type_);
	}
    }
    g->emit("_this->%I", s);
    Boolean b = g->array_decl(false);
    g->emit_param_list(params_, Generator::emit_env_actuals);
    g->array_decl(b);
    g->emit(";\n");
    if (has_return && rdesc == 0) {
	generate_receive_asg(g, type_);
	g->emit("_result;\n");
    }
    g->emit("_b.reply(_%_%N_pinfo, _arg);\n", nil, this);
    g->emit("break;\n%u}\n");
    return true;
}

void Operation::generate_receive_addr(
    Generator* g, long arg, Expr* type, Expr* value
) {
    g->emit("%F ", nil, type);
    g->emit("%E;\n", nil, value);
    generate_arg(g, arg, ".u_addr = ");
    if (g->actual_type(value)->tag() != Symbol::sym_array) {
	g->emit("&");
    }
    Boolean b = g->array_decl(false);
    g->emit("%E;\n", nil, value);
    g->array_decl(b);
}

void Operation::generate_receive_asg(Generator* g, Expr* type) {
    Symbol* s = g->actual_type(type);
    generate_arg(g, 0, ".u_");
    switch (s->tag()) {
    case Symbol::sym_string:
	g->emit("string = ", s->typename()->str());
	break;
    case Symbol::sym_typedef:
	g->emit("%I = ", s->typename()->str());
	break;
    case Symbol::sym_enum:
	g->emit("long = ");
	break;
    case Symbol::sym_interface:
	g->emit("objref = ");
	break;
    default:
	g->emit("addr = &");
	break;
    }
}