/* $Id: object.h,v 1.5 2008/11/06 20:54:36 kiesling Exp $ */

/*
  This file is part of ctalk.
  Copyright © 2005-2008 Robert Kiesling, ctalk@ctalklang.org.
  Permission is granted to copy this software provided that this copyright
  notice is included in all source code modules.

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software Foundation, 
  Inc., 51 Franklin St., Fifth Floor, Boston, MA 02110-1301 USA.
*/

#ifndef _OBJECT_H
#define _OBJECT_H

#ifndef _CTALK_LIB

#ifndef MAXLABEL
#define MAXLABEL 255
#endif

#ifndef MAXARGS
#define MAXARGS 512
#endif

/*
 *  Object scope constants.
 */
#define GLOBAL_VAR                  (1 << 0)
#define LOCAL_VAR                   (1 << 1)
#define ARG_VAR                     (1 << 2)
#define RECEIVER_VAR                (1 << 3)
#define PROTOTYPE_VAR               (1 << 4)
#define BLOCK_VAR                   (1 << 5)
#define CREATED_PARAM               (1 << 6)
#define CVAR_VAR_ALIAS_COPY         (1 << 7)
#define SUBEXPR_CREATED_RESULT      (1 << 8)

#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE !(FALSE)
#endif

#ifndef __BOOLEAN
#define __BOOLEAN
/*
 *  Compatible with X11/Intrinsic.h.  Make sure this matches the
 *  typedef in ctalklib and ctldjpp.
 */
#ifdef CRAY
typedef long Boolean;
#else
typedef char Boolean;
#endif /* #ifdef CRAY */
#define True 1
#define False 0
#endif /* #ifndef __BOOLEAN */

/* If changing these, also change in ctalklib. */
#define METHOD_RETURN "OBJECT * "
#define METHOD_C_PARAM "(void)"

#define INSTANCE_SELECTOR "_instance_"
#define CLASS_SELECTOR    "_class_"

/*
 *  Attributes for run-time method calls.
 */
#define METHOD_SUPER_ATTR  (1 << 0)

#define METHOD_ERR_FMT "%s (Class %s)"

typedef enum {
  null_context,
  lvalue_context,
  receiver_context,
  argument_context,     /* Argument to a method. */
  c_argument_context,   /* Argument to a C operator. */
  c_context
} OBJECT_CONTEXT;

typedef enum {
  arg_null,
  arg_const_tok,
  arg_const_expr,
  arg_obj_tok,
  arg_method_param_tok,
  arg_c_var_tok,
  arg_obj_expr,
  arg_c_fn_expr,
  arg_c_var_expr,
  arg_c_fn_const_expr,
  arg_c_global_arg
} ARG_CLASS;

typedef enum {
  rt_expr_null,
  rt_expr_fn,
  rt_expr_user_fn,
  rt_c_fn
} RT_EXPR_CLASS;

typedef struct _method METHOD;

typedef struct _object OBJECT;

typedef struct _varentry VARENTRY;

#define PARAM_C_PARAM (1 << 0)
#define PARAM_VARARGS_PARAM (1 << 1)

typedef struct _param PARAM;

struct _param {
  char sig[5];
  char class[MAXLABEL];
  char name[MAXLABEL];
  int attrs;
  int is_ptr,
    is_ptrptr,
    n_derefs;
};

#ifndef _CVAR_H
#include "cvar.h"
#endif

struct _method {
  char sig[6];
  char name[MAXLABEL];
  char selector[MAXLABEL];
  char returnclass[MAXLABEL];
  OBJECT *rcvr_class_obj;
  OBJECT *(*cfunc)();      /* Method prototype.            */
  char *src;
  PARAM *params[MAXARGS];
  int n_params;
  int varargs;
  int no_init;
  int n_args;
  int error_line;
  int error_column;
  int arg_frame_top;
  int rcvr_frame_top;
  Boolean imported;
  Boolean queued;
  OBJECT *args[MAXARGS];
  union {
    VARENTRY *vars;
    OBJECT *objs; 
  } local_objects;
  CVAR *local_cvars;
  struct _method *next;
  struct _method *prev;
};

/*
 *  When changing this, also change in ctalklib, ctldjgpp and message.h. 
 */
#define GNUC_PACKED_STRUCT (defined(__linux__) && defined(__i386__) && \
			    defined(__GNUC__) && (__GNUC__ >= 3))
struct _object {
  char sig[16];
  char __o_name[MAXLABEL];
  char __o_classname[MAXLABEL];
  OBJECT *__o_class;
  char __o_superclassname[MAXLABEL];
  OBJECT *__o_superclass;
  OBJECT *__o_p_obj;
  VARENTRY *__o_varentry;
  char *__o_value;
  METHOD *instance_methods,
    *class_methods;
  int scope;
  int nrefs;
  struct _object *classvars;
  struct _object *instancevars;    
  struct _object *next;
  struct _object *prev;
#if GNUC_PACKED_STRUCT
} __attribute__ ((packed));
#else
};
#endif

struct _varentry {
  PARAM *var_decl;
  OBJECT *var_object;
  struct _varentry *next, *prev;
};

/*
 *  Used in lib/rtobjref.c functions.
 */
typedef OBJECT** OBJREF_T;

/*
 *  Used to dereference arguments to the lib/objref.c function calls.
 */
#define OBJREF(__o) (&(__o))

typedef enum {
  m_null_context,
  m_obj_context,
  m_bool_context,
  m_int_context,
  m_long_context,
  m_double_context,
  m_char_context,
  m_char_ptr_context
} METHOD_C_CONTEXT;

#define OBJ_REF_STR(__s) ((__s[0] && (__s[0] == '0')) && \
                          (__s[1] && (__s[1] == 'x')) && \
                          (__s[2] && (__s[2] != '0')))

#define DELETE_OBJECT_LIST(__l) \
  { OBJECT *__o, *__o_prev; \
    for (__o = (__l); __o && IS_OBJECT(__o) && __o -> next; __o = __o -> next) \
      ; \
    if (__o == (__l)) { \
      if (__l) __ctalkDeleteObject (__l); \
      (__l) = NULL; \
    } else { \
      while (__o != (__l)) { \
        __o_prev = __o -> prev; \
        if (__o) __ctalkDeleteObject ( __o); \
        __o = __o_prev; \
        if (!__o) break; \
        __o -> next = NULL; \
      } \
      if (__l) { __ctalkDeleteObject (__l); (__l) = NULL; } \
    } \
  } \

#define DELETE_VAR_LIST(__l) \
  { VARENTRY *__v, *__v_prev; \
    for (__v = (__l); __v && __v -> var_object && IS_OBJECT(__v -> var_object) && __v -> next; __v = __v -> next) \
      ; \
    if (__v == (__l)) { \
      if (__l && __l -> var_object) __ctalkDeleteObject (__l -> var_object); \
      delete_varentry (__l); \
      (__l) = NULL; \
    } else { \
      while (__v != (__l)) { \
        __v_prev = __v -> prev; \
        if (__v && __v -> var_object) \
            __ctalkDeleteObject ( __v -> var_object); \
        delete_varentry (__v); \
        __v = __v_prev; \
        if (!__v) break; \
        __v -> next = NULL; \
      } \
      if (__l && __l -> var_object) \
       { __ctalkDeleteObject (__l -> var_object); \
         delete_varentry (__l); \
       } \
    } \
  } \

#endif   /* _CTALK_LIB */

#endif   /* _OBJECT_H */

