/*
 * Copyright (c) 1998, 1999 The University of Utah and
 * the Computer Systems Laboratory at the University of Utah (CSL).
 *
 * This file is part of Flick, the Flexible IDL Compiler Kit.
 *
 * Flick is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * Flick is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Flick; see the file COPYING.  If not, write to
 * the Free Software Foundation, 59 Temple Place #330, Boston, MA 02111, USA.
 */

#include <assert.h>
#include <string.h>

#include <mom/c/libcast.h>

#include <mom/c/pbe.hh>

/*
 * Determine the CAST expressions that name the function to be invoked by a
 * Flick-generated ``receive dispatch'' function.
 *
 * The returned `formal_func_cexpr' and `actual_func_cexpr' must be identical
 * except that wherever a formal argument appears in the `formal_func_cexpr',
 * there must be a null CAST expression at the corresponding point in the
 * `actual_func_cexpr'.  These ``holes'' in the actual expression will be
 * filled in as marshal/unmarshal code is generated.
 */
void mu_state::mu_receive_func_get_invocation_names(
	cast_def *cfunc,
	/* OUT */ cast_expr *formal_func_cexpr,
	/* OUT */ cast_expr *actual_func_cexpr)
{
	*formal_func_cexpr = cast_new_expr_scoped_name(cfunc->name);
	*actual_func_cexpr = cast_new_expr_scoped_name(cfunc->name);
}

/*
 * Determine the CAST expressions that invoke the message-handling function
 * from a Flick-generated ``receive dispatch'' function.  This method must set
 * the `formal_func_invocation_cexpr' and `actual_func_invocation_cexpr' slots
 * of the `mu_state' object.
 *
 * The `formal_func_invocation_cexpr' and `actual_func_invocation_cexpr' built
 * by this method must be identical except that wherever a formal argument
 * appears in the `formal_func_invocation_cexpr', there must be a null CAST
 * expression at the corresponding point in the `actual_func_invocation_cexpr'.
 * These ``holes'' in the actual expression will be filled in as m/u code is
 * generated.
 */
void mu_state::mu_receive_func_set_invocation_cexprs(cast_def *cfunc)
{
	cast_func_type	*cfunct = &(cfunc->u.cast_def_u_u.func_type);
	
	cast_expr	formal_func_cexpr;
	cast_expr	actual_func_cexpr;
	
	unsigned int	i;
	
	/*
	 * Set up the formal and actual versions of the expression that will be
	 * output to invoke the work function.
	 */
	assert((cfunct->return_type != 0) &&
	       (cfunct->return_type->kind == CAST_TYPE_VOID));
	
	mu_receive_func_get_invocation_names(cfunc,
					     &formal_func_cexpr,
					     &actual_func_cexpr);
	assert(formal_func_cexpr);
	assert(actual_func_cexpr);
	
	formal_func_invocation_cexpr
		= cast_new_expr_call(formal_func_cexpr, 0);
	actual_func_invocation_cexpr
		= cast_new_expr_call(actual_func_cexpr, 0);
	
	for (i = 0; i < cfunct->params.params_len; ++i) {
		cast_expr_array *formal_params
			= &(formal_func_invocation_cexpr->cast_expr_u_u.call.
			    params);
		cast_expr_array *actual_params
			= &(actual_func_invocation_cexpr->cast_expr_u_u.call.
			    params);
		
		if (!(cfunct->params.params_val[i].spec
		      & CAST_PARAM_IMPLICIT)) {
			cast_add_expr_array_value(
				formal_params,
				cast_new_expr_name(cfunct->
						   params.params_val[i].name)
				);
			cast_add_expr_array_value(
				actual_params,
				0 /* A placeholder; will be filled by m/u. */
				);
		}
	}
}

/*
 * Output the invocation of the message-handling function that is called from
 * within a Flick-generated ``receive dispatch'' function.
 */
void mu_state::mu_receive_func_call(cast_expr func_call_cexpr)
{
	add_stmt(change_stub_state(FLICK_STATE_FUNCTION_CALL));
	add_stmt(cast_new_stmt_expr(func_call_cexpr));
	add_stmt(change_stub_state(FLICK_STATE_FUNCTION_RETURN));
}

/*****************************************************************************/

/* This routine generates the code to call a single server work function.
   It is generally called (indirectly) from within mu_decode_switch(),
   once the possible choices have been narrowed down to a single server work
   function.
   
   The parameter `inl' describes the "remaining" part of the itype and ctype of
   the incoming message, after mu_decode_switch has "eaten" the part it needed
   to select a work function.
   
   This routine will generate code to package the message and call the
   C work function for processing.  No code is produced to handle replies.
   (Receive functions issue their own reply if one is in order).
*/
void mu_state::mu_receive_func(pres_c_inline inl, mint_ref /*itype*/,
			       pres_c_receive_func *rfunc,
			       pres_c_skel */*skel*/)
{
	cast_def *cfunc = &pres->stubs_cast.cast_scope_val[rfunc->c_func];
	
	/*
	 * Create a new scope containing the variables passed to this server
	 * function.
	 */
	cast_stmt old_c_block = c_block;
	c_block = cast_new_block(0, 0);
	
	/*
	 * Set up the arglist: be ready to catch the various special function
	 * parameters.
	 *
	 * XXX --- We don't *use* any of these arguments here, at least not
	 * yet.  Nevertheless, we must be prepared to capture the information
	 * about any special arguments that the PG may have marked.
	 */
	mu_state_arglist *oldlist = arglist;
	arglist = new mu_state_arglist("params", oldlist);
	arglist->add("params", "object");
	arglist->add("params", "environment");
	arglist->add("params", "return");
	arglist->add("params", "invocation_id");
	arglist->add("params", "client");
	arglist->add("params", "message");
	/*
	 * XXX --- Don't handle these for now.  Would we ever need to?
	 * must.arglist->add("params", "continue_func");
	 * must.arglist->add("params", "continue_data");
	 */
	
	/*
	 * Set up the formal and actual versions of the invocation of the work
	 * function.
	 */
	mu_receive_func_set_invocation_cexprs(cfunc);
	
	/*
	 * Build the code to locate the target object.
	 */
	mu_receive_func_target(rfunc);
	/*
	 * ... and the client object.
	 */
	mu_receive_func_client(rfunc);
	
	/* Build the code to package and identify the message. */
	mu_func_params(rfunc->c_func, rfunc->simple_msg_itype, inl);
	mu_end();
	
	/*
	 * Signal that we are finished with the decode phase.  The matching
	 * `flick_*_server_start_encode' is output by `w_server_skel', which is
	 * defined individually by each back end.
	 */
	add_stmt(
		cast_new_stmt_expr(
			cast_new_expr_call(
				cast_new_expr_name(
					flick_asprintf(
						"flick_%s_server_end_decode",
						get_be_name())),
				0)));
	
	/*
	 * Build the function call to the server work function.
	 *
	 * The `actual_func_invocation_cexpr' should have been completely
	 * filled out as part of unmarshaling the message.
	 */
	cast_check_expr(actual_func_invocation_cexpr);
	mu_receive_func_call(actual_func_invocation_cexpr);
	actual_func_invocation_cexpr = 0;
	
	/*
	 * For receive functions, any necessary reply is handled by the
	 * work function.  Flick is not responsible for generating a reply
	 * when the function returns.
	 */
	add_stmt(
		cast_new_return(
			cast_new_expr_name(
				"FLICK_OPERATION_SUCCESS_NOREPLY"
				)));
	
	/* End the new scope we created. */
	cast_stmt new_c_block = c_block;
	c_block = old_c_block;
	add_stmt(new_c_block);
	
	delete arglist;
	arglist = oldlist;
}

/* End of file. */



syntax highlighted by Code2HTML, v. 0.9.1