/****************************************************************
 *								*
 * Copyright (c) 2001-2020 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 "gtm_string.h"
#include "compiler.h"
#include "opcode.h"
#include "indir_enum.h"
#include "toktyp.h"
#include "mmemory.h"
#include "mdq.h"
#include "advancewindow.h"
#include "fullbool.h"
#include "glvn_pool.h"
#include "show_source_line.h"

GBLREF	boolean_t	run_time;
GBLREF	int		source_column;

error_def(ERR_SIDEEFFECTEVAL);
error_def(ERR_VAREXPECTED);

int f_get(oprtype *a, opctype op)
{
	boolean_t	ok, used_glvn_slot;
	oprtype		control_slot, def_opr, *def_oprptr, indir;
	short int	column;
	triple		*oldchain, *opptr, *r, *triptr;
	save_se		save_state;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	oldchain = NULL;
	used_glvn_slot = FALSE;
	r = maketriple(OC_NOOP);		/* We'll fill in the opcode later, when we figure out what it is */
	switch (TREF(window_token))
	{
	case TK_IDENT:
		r->opcode = OC_FNGET;
		ok = lvn(&r->operand[0], OC_SRCHINDX, 0);
		break;
	case TK_CIRCUMFLEX:
		r->opcode = OC_FNGVGET;
		ok = gvn();
		break;
	case TK_ATSIGN:
		r->opcode = OC_INDGET2;
		if (SHIFT_SIDE_EFFECTS)
			START_GVBIND_CHAIN(&save_state, oldchain);
		if (ok = indirection(&indir))	/* NOTE: assignment */
		{
			used_glvn_slot = TRUE;
			INSERT_INDSAVGLVN(control_slot, indir, ANY_SLOT, 1);
			r->operand[0] = control_slot;
		}
		break;
	default:
		ok = FALSE;
		break;
	}
	if (!ok)
	{
		if (NULL != oldchain)
			setcurtchain(oldchain);
		stx_error(ERR_VAREXPECTED);
		return FALSE;
	}
	opptr = r;
	ins_triple(r);
	if (used_glvn_slot)
	{	/* house cleaning for the indirection */
		triptr = newtriple(OC_GLVNPOP);
		triptr->operand[0] = control_slot;
	}
	if (TK_COMMA == TREF(window_token))
	{	/* two argument form with a specified default value */
		advancewindow();
		column = source_column;
		def_oprptr = (oprtype *)mcalloc(SIZEOF(oprtype));
		def_opr = put_indr(def_oprptr);
		DISABLE_SIDE_EFFECT_AT_DEPTH;		/* doing this here let's us know specifically if direction had SE threat */
		if (EXPR_FAIL == expr(def_oprptr, MUMPS_EXPR))
		{
			if (NULL != oldchain)
				setcurtchain(oldchain);
			return FALSE;
		}
		if (SE_WARN_ON && (TREF(side_effect_base))[TREF(expr_depth)])
			ISSUE_SIDEEFFECTEVAL_WARNING(column - 1);
		if (OC_FNGET == r->opcode)
			r->opcode = OC_FNGET1;
		else if (OC_FNGVGET == r->opcode)
			r->opcode = OC_FNGVGET1;
		else
			assert(OC_INDGET2 == r->opcode);
		r = newtriple(OC_FNGET2);
		r->operand[0] = put_tref(opptr);
		r->operand[1] = def_opr;
	} else if (OC_INDGET2 == r->opcode)
	{	/* indirect always acts like a two argument form so force that along with an empty string default */
		r = newtriple(OC_FNGET2);
		r->operand[0] = put_tref(opptr);
		r->operand[1] = put_str(0, 0);
	}
	if (NULL != oldchain)
		PLACE_GVBIND_CHAIN(&save_state, oldchain); 	/* shift chain back to "expr_start" */
	*a = put_tref(r);
	return TRUE;
}
