/****************************************************************
 *								*
 * Copyright (c) 2001-2015 Fidelity National Information 	*
 * Services, Inc. and/or its subsidiaries. All rights reserved.	*
 *								*
 *	This source code contains the intellectual property	*
 *	of its copyright holder(s), and is made available	*
 *	under a license.  If you do not know the terms of	*
 *	the license, please stop and do not read further.	*
 *								*
 ****************************************************************/

#include "mdef.h"
#include "compiler.h"
#include "opcode.h"
#include "toktyp.h"
#include "mdq.h"
#include "fullbool.h"
#include "advancewindow.h"
#include "show_source_line.h"

GBLREF	boolean_t	run_time;

error_def(ERR_COMMAORRPAREXP);
error_def(ERR_MAXACTARG);
error_def(ERR_NAMEEXPECTED);
error_def(ERR_SIDEEFFECTEVAL);

	int actuallist (oprtype *opr)
{
	boolean_t	se_warn;
	int		i, j, mask, parmcount;
	oprtype		ot;
	triple		*counttrip, *masktrip, *ref0, *ref1, *ref2;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	assert(TK_LPAREN == TREF(window_token));
	advancewindow();
	masktrip = newtriple(OC_PARAMETER);
	mask = 0;
	counttrip = newtriple(OC_PARAMETER);
	masktrip->operand[1] = put_tref(counttrip);
	ref0 = counttrip;
	if (TK_RPAREN == TREF(window_token))
		parmcount = 0;
	else
	{
		for (parmcount = 1; ; parmcount++)
		{
			if (MAX_ACTUALS < parmcount)
			{
				stx_error (ERR_MAXACTARG);
				return FALSE;
			}
			if (TK_PERIOD == TREF(window_token))
			{
				advancewindow ();
				if (TK_IDENT == TREF(window_token))
				{
					ot = put_mvar(&(TREF(window_ident)));
					mask |= (1 << parmcount - 1);
					advancewindow();
				} else if (TK_ATSIGN == TREF(window_token))
				{
					if (!indirection(&ot))
						return FALSE;
					ref2 = newtriple(OC_INDLVNAMADR);
					ref2->operand[0] = ot;
					ot = put_tref(ref2);
					mask |= (1 << parmcount - 1);
				} else
				{
					stx_error(ERR_NAMEEXPECTED);
					return FALSE;
				}
			} else if (TK_COMMA == TREF(window_token))
			{
				ref2 = newtriple(OC_NULLEXP);
				ot = put_tref(ref2);
			} else if (EXPR_FAIL == expr(&ot, MUMPS_EXPR))
				return FALSE;
			ref1 = newtriple(OC_PARAMETER);
			ref0->operand[1] = put_tref(ref1);
			ref1->operand[0] = ot;
			if (TK_COMMA == TREF(window_token))
			{	advancewindow ();
				if (TK_RPAREN == TREF(window_token))
				{	ref0 = ref1;
					ref2 = newtriple(OC_NULLEXP);
					ot = put_tref(ref2);
					ref1 = newtriple(OC_PARAMETER);
					ref0->operand[1] = put_tref(ref1);
					ref1->operand[0] = ot;
					parmcount++;
					break;
				}
			} else if (TREF(window_token) == TK_RPAREN)
				break;
			else
			{
				stx_error (ERR_COMMAORRPAREXP);
				return FALSE;
			}
			ref0 = ref1;
		}
		if ((1 < parmcount) && (TREF(side_effect_base))[TREF(expr_depth)])
		{	/* at least two arguments and at least one side effect - look for lvns needing protection */
			assert(OLD_SE != TREF(side_effect_handling));
			se_warn = SE_WARN_ON;
			for (i = 0, j = parmcount, ref0 = counttrip->operand[1].oprval.tref; --j;
				ref0 = ref0->operand[1].oprval.tref)
			{	/* no need to do the last argument - can't have a side effect after it */
				assert(OC_PARAMETER == ref0->opcode);
				assert((TRIP_REF == ref0->operand[0].oprclass) && (TRIP_REF == ref0->operand[1].oprclass));
				if (!((1 << i++) & mask) && (OC_VAR == ref0->operand[0].oprval.tref->opcode))
				{	/* can only protect pass-by-value (not pass-by-reference) */
					ref1 = maketriple(OC_STOTEMP);
					ref1->operand[0] = put_tref(ref0->operand[0].oprval.tref);
					ref0->operand[0].oprval.tref = ref1;
					dqins(ref0, exorder, ref1); 	/* NOTE:this violates information hiding */
					if (se_warn)
						ISSUE_SIDEEFFECTEVAL_WARNING(ref0->src.column);
				}
			}
			/* the following asserts check we're getting only TRIP_REF or empty operands */
			assert((NO_REF == ref0->operand[0].oprclass) || (TRIP_REF == ref0->operand[0].oprclass));
			assert(((NO_REF == ref0->operand[0].oprclass) ? TRIP_REF : NO_REF) == ref0->operand[1].oprclass);
		}
	}
	advancewindow();
	masktrip->operand[0] = put_ilit(mask);
	counttrip->operand[0] = put_ilit(parmcount);
	parmcount += 2;
	*opr = put_tref(masktrip);
	return parmcount;
}
