/* 
 * Motif
 *
 * Copyright (c) 1987-2012, The Open Group. All rights reserved.
 *
 * These libraries and programs are free software; you can
 * redistribute them and/or modify them under the terms of the GNU
 * Lesser General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * These libraries and programs are distributed in the hope that
 * they will be useful, but WITHOUT ANY WARRANTY; without even the
 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 * PURPOSE. See the GNU Lesser General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with these librararies and programs; if not, write
 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
 * Floor, Boston, MA 02110-1301 USA
*/ 
#ifdef REV_INFO
#ifndef lint
static char rcsid[] = "$XConsortium: UilSarProc.c /main/12 1995/07/14 09:37:43 drk $"
#endif
#endif

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

/*
**++
**  FACILITY:
**
**      User Interface Language Compiler (UIL)
**
**  ABSTRACT:
**
**      This module contain the routines for processing procedures.
**
**--
**/


/*
**
**  INCLUDE FILES
**
**/

#include "UilDefI.h"


/*
**
**  DEFINE and MACRO DEFINITIONS
**
**/



/*
**
**  EXTERNAL VARIABLE DECLARATIONS
**
**/


/*
**
**  GLOBAL VARIABLE DECLARATIONS
**
**/


/*
**
**  OWN VARIABLE DECLARATIONS
**
**/


/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      This function create the procedure definition entry symbol 
**	node a procedure declaration.
**
**  FORMAL PARAMETERS:
**
**	id_frame	ptr to token frame for the procedure name
**	param_frame	ptr to token frame or null frame holding the
**			type of the argument
**	class_frame	ptr to frame whose b_flags holds private, etc. info
**
**  IMPLICIT INPUTS:
**
**	sym_az_current_section_entry	the "current" section list
**
**  IMPLICIT OUTPUTS:
**
**      none
**
**  FUNCTION VALUE:
**
**      void
**
**  SIDE EFFECTS:
**
**      errors may be issued for previously defined name
**
**--
**/

void
sar_create_procedure(XmConst yystype *id_frame, 
                     XmConst yystype *param_frame, 
                     XmConst yystype *class_frame, 
                     XmConst yystype *semi_frame)
{
    sym_name_entry_type	    *name_entry;
    sym_proc_def_entry_type *proc_def_entry;
    sym_section_entry_type  *section_entry;
    sym_obj_entry_type	    *obj_entry;

    /*
    **  Call standard routine to check name entry for id_frame.
    **	This routine handles font name, color names, etc used as ids
    */

    name_entry = (sym_name_entry_type *) sem_dcl_name( id_frame );

    if (name_entry == NULL)
	return;

    /*
    **	Allocate the procedure definition entry and fill it in
    */

    proc_def_entry = (sym_proc_def_entry_type *)
	sem_allocate_node (sym_k_proc_def_entry, sym_k_proc_def_entry_size);

    proc_def_entry->b_widget_type = uil_max_object + 1;
    proc_def_entry->obj_header.az_name = (sym_name_entry_type *) name_entry;
    name_entry->az_object = (sym_entry_type *) proc_def_entry;

    /* 
    **	Parameter frame has 4 cases:
    **	    1) no argument checking desired
    **	       syntax: PROCEDURE id
    **	    2) argument checking desired - no argument
    **	       syntax: PROCEDURE id( )
    **	    3) argument checking desired - single argument
    **	       syntax: PROCEDURE id( type )
    **	    4) argument checking desired - single typed widget argument
    **	       syntax: PROCEDURE id( CLASS_NAME )
    **  These cases are distinguished as follows:
    **	    1) tag = null  type = 0
    **	    2) tag = null  type = sar_k_no_value
    **	    3) tag = token type = argument type
    **	    4) tag = object type = widget type
    */

    proc_def_entry->v_arg_checking = TRUE;

    switch (param_frame->b_tag)
    {
    case sar_k_null_frame:
	if (param_frame->b_type == sym_k_no_value )
	{
	    proc_def_entry->b_arg_count = 0;
	    proc_def_entry->b_arg_type = sym_k_no_value;
	}
	else
	    proc_def_entry->v_arg_checking = FALSE;
	    
	break;

    case sar_k_token_frame:
	proc_def_entry->b_arg_type = param_frame->b_type;
	proc_def_entry->b_arg_count = 1;
	break;

    case sar_k_object_frame:
	_assert((param_frame->b_type == sym_k_widget_entry),
		"object frame not widget entry");
	
	obj_entry = 
	  (sym_obj_entry_type *)param_frame->value.az_symbol_entry;

	proc_def_entry->b_arg_type = sym_k_widget_ref_value;
	proc_def_entry->b_arg_count = 1;
	proc_def_entry->b_widget_type = obj_entry->header.b_type;
	break;
	
    default:
	_assert( FALSE, "param frame in error" );

    }

    /*
    **	Process the class clause
    */

    switch (class_frame->b_flags)
    {
    case sym_m_exported:
	sym_make_external_def( name_entry );

    case sym_m_private:
    case sym_m_imported:
	break;

    default:
	_assert( FALSE, "class frame in error" );

    }

    proc_def_entry->obj_header.b_flags = class_frame->b_flags;

    /*
    ** save the source file info for this procedure entry
    */
    _sar_save_source_info (&proc_def_entry->header, id_frame, semi_frame );
    sar_assoc_comment((sym_obj_entry_type *)proc_def_entry);       /* preserve comments */

    /*
    ** allocate a section entry to link the proc_def entry into the structure
    */
    section_entry = (sym_section_entry_type *) sem_allocate_node
			(sym_k_section_entry, sym_k_section_entry_size);

    /*
    ** Link this entry off of the current section list
    */
    section_entry->next = (sym_entry_type *) sym_az_current_section_entry->entries;
    sym_az_current_section_entry->entries = (sym_entry_type *) section_entry;

    section_entry->entries = (sym_entry_type *) proc_def_entry;

}

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      This function processes a reference to a procedure.
**
**  FORMAL PARAMETERS:
**
**	id_frame	ptr to token frame for the procedure name
**	value_frame	ptr to token frame or null frame holding the
**			value of the argument to the procedure
**	context		value indicating how the procedure is being used
**
**  IMPLICIT INPUTS:
**
**      none
**
**  IMPLICIT OUTPUTS:
**
**      none
**
**  FUNCTION VALUE:
**
**      a procedure reference entry / NULL in case of an illegal reference
**
**  SIDE EFFECTS:
**
**      errors may be issued 
**
**--
**/

sym_proc_ref_entry_type
*sem_reference_procedure( yystype         *id_frame, 
                          XmConst yystype *value_frame, 
                          XmConst int     context )
{
    sym_value_entry_type    *value_entry = NULL;
    sym_proc_def_entry_type *proc_def_entry;
    sym_proc_ref_entry_type *proc_ref_entry;

    /*
    **  Call standard routine to check name entry for id_frame.
    **	This routine handles font name, color names, etc used as ids
    */

    proc_def_entry =
	(sym_proc_def_entry_type *)
	    sem_ref_name( id_frame, sym_k_proc_def_entry );

    switch (value_frame->b_tag)
    {
    case sar_k_null_frame:
	value_entry = NULL;
	break;

    case sar_k_value_frame:
	if ((value_frame->b_flags & sym_m_forward_ref) != 0)
	    value_entry = NULL;
	else
	    value_entry = (sym_value_entry_type *) 
			  value_frame->value.az_symbol_entry;
	break;

    case sar_k_object_frame:
	value_entry =
		(sym_value_entry_type *) value_frame->value.az_symbol_entry;
	break;

    default:
	_assert( FALSE, "actual arg in error" );
    }

    /*
    **	Allocate the procedure reference entry and fill it in
    */

    proc_ref_entry = (sym_proc_ref_entry_type *)
	sem_allocate_node (sym_k_proc_ref_entry, sym_k_proc_ref_entry_size);

    if ((id_frame->b_flags & sym_m_forward_ref) != 0)
        sym_make_value_forward_ref (id_frame, 
	(char*)&(proc_ref_entry->az_proc_def), sym_k_patch_list_add);
    else 
	proc_ref_entry->az_proc_def = proc_def_entry;

    if ((value_frame->b_flags & sym_m_forward_ref) != 0)
        sym_make_value_forward_ref (value_frame, 
	(char*)&(proc_ref_entry->az_arg_value), sym_k_patch_add);
    else
	proc_ref_entry->az_arg_value = value_entry;

    /*
    **	Apply context constraints
    **
    **	If this is a procedure being used as a user object,
    **	it should not have any arguments.  The arguments to such
    **	a procedure are always a parent widget id and an argument list.
    **	This constraint is currently inforced by the grammar.
    **
    **	At this time the compiler permits all types of values for callback
    **  arguments.  This may be limited shortly when we see if it is
    **  reasonable to pass fonts, colors, reasons, etc.
    */

    return proc_ref_entry;

}


/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      This function checks to see if a object is defined with the name
**	corresponding to the id given in the first parameter.
**
**  FORMAL PARAMETERS:
**
**      id_frame	ptr to a token frame on the parse stack holding the name
**	tag		the type of construct needed
**
**  IMPLICIT INPUTS:
**
**      none
**
**  IMPLICIT OUTPUTS:
**
**      none
**
**  FUNCTION VALUE:
**
**      ptr to a symbol entry for construct or NULL
**
**  SIDE EFFECTS:
**
**	error message if the name is undefined or for a different construct
**	forward_ref bit may be turned on in id_frame
**--
**/

sym_entry_type
*sem_ref_name(yystype     *id_frame, 
              XmConst int tag)
{
    sym_name_entry_type	    *name_entry;
    sym_entry_type	    *symbol_entry;

    _assert( id_frame->b_tag == sar_k_token_frame, "arg1 not id frame" );

    /* 
    ** The id frame may hold a name or the keyword for a font name, color
    ** name, reason name etc.  If it is one of these special name, then
    ** we must see if the symbol table holds a name for the special type.
    */

    if (id_frame->b_type != NAME)
    {
	name_entry = 
	    sym_find_name
		( id_frame->value.az_keyword_entry->b_length,
		  id_frame->value.az_keyword_entry->at_name );

	if (name_entry == NULL)
	{
	    diag_issue_diagnostic
		( d_undefined,
		  _sar_source_position( id_frame ),
		  diag_tag_text( sym_k_proc_def_entry ),
		  id_frame->value.az_keyword_entry->at_name );

	    return NULL;
	}

    }
    else
	name_entry =
		(sym_name_entry_type *) id_frame->value.az_symbol_entry;

    /*
    ** If the name entry already has no object linked from it, we are
    ** referencing an undefined object.
    */

    symbol_entry = name_entry->az_object;

    if (symbol_entry == NULL )
	{
	id_frame->b_flags |= sym_m_forward_ref;
	return NULL;
	}
    /*
    ** If the name entry has the wrong type of object, this is also
    ** an error.
    */

    if (symbol_entry->header.b_tag != tag )
    {
	diag_issue_diagnostic
	    ( d_ctx_req,
	      _sar_source_position( id_frame ),
	      diag_tag_text( tag ),
	      diag_tag_text( symbol_entry->header.b_tag ) );

	return NULL;
    }

    return symbol_entry;

}
