#ifndef PROCESS_H
#define PROCESS_H
#pragma interface

#include "value.h"
#include "Structures.h"
#include "storage.h"
#include "tokentable.h"
#include "Scheduler.h"


/*******************************************************************
 pictorally, this structure looks like this:
     |
   Process --> Frame --> Frame --> Frame
     |
 A Process has a bunch of stored frames from each of the objects that
 have been called and not exited from yet.
 Each frame represents process control moving to a different object.
*********************************************************************/

const Value* anon_nm = new Value (new String ("an anonymous method"));

class lvarstack : public SymVal_List {
 public:
  Value* assign (String* s, Value* v);
};

class Frame {
  friend class Process;
  friend class Value;
  friend class Scheduler;
 public:
  Frame(int obj_on , Value* mthd_nm , Val_List* actuals ,
	Process* process_ptr , Frame* prev = NULL , Value* method_val = NULL);
  ~Frame();
  int do_operation ();       /** returns the number of ticks it took        **/
  int try_operation ();
  int expression_depth ()    {return expression_stack.depth;}

 protected:
  Value_Stack data_stack;         /** for storing evaluated values          **/
  Value_Stack expression_stack;   /** holds the expressions being evaluated **/
  SymVal_List local_vars;         /** a list of all local variables.        **/
  Value_Stack method_names;

  intlist ignore_list;       /** stores error codes to ignore          **/
  intlist method_on;
  int this_obj;              /** the object number this frame is running on **/
  Frame* previous;           /** pointer to frame waiting for this one      **/
  Process* proc;             /** points to root level process structure     **/
  int exprpop();
  void push_method (Value* mthd_nm = anon_nm);
  void pop_method ();
  void returned_val (Value*);
  void dump_state ();         /** for debugging **/
  int check_error_raise (Value* errnum, String* msg = NULL);
  int transfer_to_data();     /** transfers a value from expr --> data **/
  Value* lookup (Value*);     /** looks up that variable name **/
  int handle_reserved ();
  void dump_local_vars();
  int assert_type (Value*, Value_Type);
  int is_handling_error (int err_code, Value* err_string);
  /******* prototypes for operators: *********/
  op_EQ();
  op_LT();
  op_GT();
  op_MOD();
  op_DIV();
  op_SUB();
  op_ADD();
  op_MUL();
  op_SET();
  op_NOT();
  op_OR();
  op_AND();
  op_INDEX();
  op_RANGE();
  op_TONUM();
  op_TOREAL();
  op_TOSTR();
  op_TOOBJ();
  op_TIME();
  op_RANDOM();
  op_LENGTH();
  op_INSERT();
  op_CRYPT();
  op_IF();
  op_DOTIMES();
  op_FOREACH();
  op_WHILE();
  op_PASS();
  op_PASS_TO();
  op_SLEEP();
  op_FORK();
  op_KILL();
  op_ECHO_CMD();
  op_SETPARENTS();
  op_VAR();
  op_RMVAR();
  op_ADDCMD();
  op_RMCMD();
  op_MATCHCMD();
  op_CALL();
  op_METHOD();
  op_COMMANDS();
  op_VARS();
  op_CLONE();
  op_DISCONNECT();
  op_RECONNECT();
  op_SHUTDOWN();
  op_RETURN();
  op_BEGIN_CMD();
  op_TOERROR();
  op_TOLIST();
  op_IGNORE();
  op_COMPILE();
  op_SEARCH();
  op_PARENTS();
  op_EXPLODE();
  op_PURGECMDS();
  op_CAR();
  op_CDR();
  op_CONS();
  op_TOSYM();
  op_AFTER();
  op_BEFORE();
  op_QUOTE();
  op_EVAL();
  op_TYPEOF();
  op_FILETEXT();
  op_RUNSCRIPT();
  op_CLASS();
  op_SQRT();
  op_REGSPLIT();
  op_CONNOUT();
  op_HANDLE();
  op_SEMAPHORE();
  op_ADDRESS();
  op_GTE();
  op_LTE();
  op_FORMAT();
  op_IMPLODE();
  op_SETS();
  op_NUM2CHAR();
  op_CHAR2NUM();
  op_COLLECT();
  op_MATCHONE();
  op_LOG();
};

#define MAX_DEPTH 2500  // the greatest expression depth allowed ... to
                        // prevent runaway recursion.

class Process {
  friend class Frame;
  friend class Scheduler;
 protected:
  int process_id;
  int sleeping_til;
  int ticks_left;
  int player_obj;
  Frame* active_frame;
  String last_error_msg;
  Value* last_error;
  void add_sleeping (int);
 public:
  Process (int obj_on , int pid , Value* mthd_nm , int ticks , Val_List* actuals);
  ~Process ();
  int give_ticks (int tick_slice);
};

#endif /* PROCESS_H */