// check.h - Useful argument checking macros. Used in pseudo-instructions.
//
// ##Copyright##
// 
// Copyright 2000-2016 Peter Robinson  (pjr@itee.uq.edu.au)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.00 
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// ##Copyright##
//
// $Id: check.h,v 1.5 2005/03/08 00:35:00 qp Exp $

#ifndef	CHECK_H
#define	CHECK_H

// #include "atom_table.h"


#define DECODE_STREAM_ARG(heap, iom, cell, arg_num, stream, dir)	\
  do {									\
    const ErrorValue ev_input =						\
      (heap).decode_stream_input(iom, cell, &stream);			\
    if (ev_input == EV_NO_ERROR)					\
      {									\
	dir = QP_INPUT;							\
      }									\
    else if (ev_input == EV_NOT_PERMITTED)				\
      {									\
	const ErrorValue ev_output =					\
          (heap).decode_stream_output(iom, cell, &stream);		\
	if (ev_output == EV_NO_ERROR)					\
	  {								\
	    dir = QP_OUTPUT;						\
	  }								\
	else								\
	  {								\
	    PSI_ERROR_RETURN(ev_output, arg_num);			\
	  }								\
      }									\
    else								\
      {									\
	PSI_ERROR_RETURN(ev_input, arg_num);				\
      }									\
  } while (0)

#define DECODE_STREAM_OUTPUT_ARG(heap, iom, cell, arg_num, stream)	   \
  do {									   \
    const ErrorValue ev = (heap).decode_stream_output(iom, cell, &stream); \
    if (ev != EV_NO_ERROR)						   \
      {									   \
	PSI_ERROR_RETURN(ev, arg_num);					   \
      }									   \
  } while (0)

#define DECODE_STREAM_INPUT_ARG(heap, iom, cell, arg_num, stream)	  \
  do {									  \
    const ErrorValue ev = (heap).decode_stream_input(iom, cell, &stream); \
    if (ev != EV_NO_ERROR)						  \
      {									  \
	PSI_ERROR_RETURN(ev, arg_num);					  \
      }									  \
  } while (0)

#define CHECK_NUMBER_ARG(cell, arg_num)		\
  do {						\
    if ((cell)->isVariable())			\
      {						\
	PSI_ERROR_RETURN(EV_INST,		\
			 arg_num);		\
      }						\
    if (!(cell)->isNumber())			\
      {						\
	PSI_ERROR_RETURN(EV_TYPE,		\
			 arg_num);		\
      }						\
  } while (0)

#define CHECK_ATOM_ARG(cell, arg_num)		\
  do {						\
    if ((cell)->isVariable())			\
      {						\
	PSI_ERROR_RETURN(EV_INST, arg_num);	\
      }						\
    else if (!(cell)->isAtom())			\
      {						\
	PSI_ERROR_RETURN(EV_TYPE, arg_num);	\
      }						\
  } while (0)

#define CHECK_ATOMIC_ARG(cell, arg_num)			\
  do {							\
    if ((cell)->isVariable())				\
      {							\
	PSI_ERROR_RETURN(EV_INST, arg_num);		\
      }							\
    else if (!(cell)->isAtom() && !(cell)->isNumber())	\
      {							\
	PSI_ERROR_RETURN(EV_TYPE, arg_num);		\
      }							\
  } while (0)

#define CHECK_VARIABLE_ARG(heap, prolog_value, arg_num, var)	\
do {								\
  PrologValue prolog_value(var);				\
  (heap).prologValueDereference(prolog_value);				\
  if (!(prolog_value).getTerm()->isVariable())			\
    {								\
      PSI_ERROR_RETURN(EV_INST, arg_num);			\
    }								\
} while (0)

#define DECODE_SEND_OPTIONS_ARG(heap, cell, arg_num,		\
				remember_names, encode)		\
  do {								\
    const bool result =					\
      (heap).decode_send_options(cell,				\
				 remember_names, encode);	\
    if (!result)					\
      {								\
        PSI_ERROR_RETURN(EV_TYPE, arg_num);			\
      }								\
  } while (0)

#define DECODE_RECV_OPTIONS_ARG(heap, cell, arg_num,			\
			       remember_names, peek, encode)		\
  do {									\
    const ErrorValue result =						\
      (heap).decode_recv_options(cell, remember_names, peek, encode);	\
    if (result != EV_NO_ERROR)						\
      {									\
        PSI_ERROR_RETURN(result, arg_num);				\
      }									\
  } while (0)

#define CHECK_ATOM_LIST_ARG(heap, cell, arg_num)	\
  do {							\
    size_t length = 0;					\
    if ((cell)->isVariable())				\
      {							\
	PSI_ERROR_RETURN(EV_INST, arg_num);		\
      }							\
    else if (! (heap).check_atom_list(cell, length))	\
      {							\
	PSI_ERROR_RETURN(EV_TYPE, arg_num);		\
      }							\
  } while (0)

#define DECODE_BOOLEAN_ARG(atoms, cell, arg_num, b)	\
  do {							\
    if ((cell)->isVariable())				\
      {							\
	PSI_ERROR_RETURN(EV_INST, arg_num);		\
      }							\
    else if (! (cell)->isAtom())				\
      {							\
	PSI_ERROR_RETURN(EV_TYPE, arg_num);		\
      }							\
    b = (atoms).atomToBool(cell);			\
  } while (0)

public:
ErrorValue decode_stream(IOManager&, Object*, QPStream **,
			 const IODirection);

bool check_functor(Object*, Atom*, const word32);

ErrorValue decode_stream_output(IOManager&, Object*, QPStream **);
ErrorValue decode_stream_input(IOManager&, Object*, QPStream **);

ErrorValue decode_nonneg_int(Object*, int&);

//
// Check the options associated with outgoing 
// TCP and IPC communication.
//
bool decode_send_options(Object*, bool&, bool&);

//
// Decode the options associated with incoming
// TCP and IPC/ICM communication.
//
bool decode_recv_options(Object*, Object*&, Object*&, Object*&);

//
// Decode the options associated with incoming
// TCP and IPC/ICM communications.
//
ErrorValue decode_recv_options(Object*, bool&, bool&, bool&);


bool check_atom_list(Object*, size_t&);

#endif	// CHECK_H
