Logo Search packages:      
Sourcecode: gambas version File versions  Download package

gbx_exec.c

/***************************************************************************

  exec.c

  Subroutines for the interpreter : executing methods, native methods,
  the NEW operator, the casting operator, etc.

  (c) 2000-2004 Benoît Minisini <gambas@users.sourceforge.net>

  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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.

***************************************************************************/


#define __GBX_EXEC_C

#include "gb_common.h"
#include "gb_error.h"
#include "gbx_type.h"

#include <unistd.h>
#include <sys/time.h>

#include "gb_limit.h"
#include "gbx_subr.h"
#include "gbx_stack.h"
#include "gbx_trace.h"

#include "gbx_string.h"
#include "gbx_date.h"
#include "gbx_array.h"

#include "gbx_c_collection.h"

#include "gbx_api.h"
#include "gbx_exec.h"

PUBLIC STACK_CONTEXT EXEC_current = { 0 }; /* Contexte à sauvegarder */
PUBLIC PCODE EXEC_code; /* Opcode de l'instruction en cours */
PUBLIC VALUE *SP = NULL; /* Pointeur de pile */
PUBLIC VALUE TEMP; /* Stockage temporaire */
PUBLIC VALUE RET; /* Valeur de retour de la fonction */
PUBLIC bool EXEC_debug = FALSE; /* Mode débogage */
PUBLIC boolean EXEC_enum_stop = FALSE; /* Indique la fin d'une énumération */
PUBLIC void *EXEC_enum_data; /* Etat de l'énumération en cours */
PUBLIC bool EXEC_arch = FALSE; /* Exécution d'une archive */
PUBLIC bool EXEC_fifo = FALSE; /* Débogage par fifo */
PUBLIC EXEC_HOOK EXEC_Hook = { NULL };
PUBLIC bool EXEC_big_endian;
PUBLIC EXEC_FUNCTION EXEC;


PUBLIC void EXEC_init(void)
{
  char test[4];

  PC = NULL;
  BP = NULL;
  OP = NULL;
  CP = NULL;
  RP->type = T_VOID;

  test[0] = 0xAA;
  test[1] = 0xBB;
  test[2] = 0xCC;
  test[3] = 0xDD;

  EXEC_big_endian = *((ulong *)test) == 0xAABBCCDDL;
  /*printf("%s endian\n", EXEC_big_endian ? "big" : "little");*/

  DATE_init();
}


PUBLIC void BORROW(VALUE *value)
{
  static void *jump[16] = {
    &&__NONE, &&__NONE, &&__NONE, &&__NONE, &&__NONE, &&__NONE, &&__NONE, &&__NONE,
    &&__STRING, &&__NONE, &&__VARIANT, &&__NONE, &&__NONE, &&__FUNCTION, &&__NONE, &&__NONE
    };

  TYPE type = value->type;

  if (TYPE_is_object(type))
    goto __OBJECT;
  else
    goto *jump[type];

__STRING:

  STRING_ref(value->_string.addr);
  return;

__OBJECT:
  OBJECT_REF(value->_object.object, "BORROW");
  return;

__VARIANT:
  if (value->_variant.vtype == T_STRING)
    STRING_ref((*(char **)value->_variant.value));
  else if (TYPE_is_object(value->_variant.vtype))
    OBJECT_REF(*((void **)value->_variant.value), "BORROW");
  return;

__FUNCTION:
  OBJECT_REF(value->_function.object, "BORROW");
  return;

__NONE:
  return;
}


PUBLIC void UNBORROW(VALUE *value)
{
  static void *jump[16] = {
    &&__NONE, &&__NONE, &&__NONE, &&__NONE, &&__NONE, &&__NONE, &&__NONE, &&__NONE,
    &&__STRING, &&__NONE, &&__VARIANT, &&__NONE, &&__NONE, &&__FUNCTION, &&__NONE, &&__NONE
    };

  TYPE type = value->type;

  if (TYPE_is_object(type))
    goto __OBJECT;
  else
    goto *jump[type];

__STRING:

  STRING_unref_keep(&value->_string.addr);
  return;

__OBJECT:
  OBJECT_UNREF_KEEP(&value->_object.object, "UNBORROW");
  return;

__VARIANT:
  if (value->_variant.vtype == T_STRING)
    STRING_unref_keep((char **)value->_variant.value);
  else if (TYPE_is_object(value->_variant.vtype))
    OBJECT_UNREF_KEEP((void **)value->_variant.value, "UNBORROW");
  return;

__FUNCTION:
  OBJECT_UNREF_KEEP(&value->_function.object, "UNBORROW");
  return;

__NONE:
  return;
}


PUBLIC void RELEASE(VALUE *value)
{
  static void *jump[16] = {
    &&__NONE, &&__NONE, &&__NONE, &&__NONE, &&__NONE, &&__NONE, &&__NONE, &&__NONE,
    &&__STRING, &&__NONE, &&__VARIANT, &&__ARRAY, &&__NONE, &&__FUNCTION, &&__NONE, &&__NONE
    };

  TYPE type = value->type;

  if (TYPE_is_object(type))
    goto __OBJECT;
  else
    goto *jump[type];

__STRING:
  STRING_unref(&value->_string.addr);
  return;

__OBJECT:
  OBJECT_UNREF(&value->_object.object, "RELEASE");
  return;

__VARIANT:
  if (value->_variant.vtype == T_STRING)
    STRING_unref((char **)value->_variant.value);
  else if (TYPE_is_object(value->_variant.vtype))
    OBJECT_UNREF(value->_variant.value, "RELEASE");
  return;

__FUNCTION:
  OBJECT_UNREF(&value->_function.object, "RELEASE");
  return;

__ARRAY:
  if (!value->_array.keep)
    ARRAY_free(&value->_array.addr, value->_array.desc);
  return;

__NONE:
  return;
}

#if 0
PUBLIC void DUMP(VALUE *value)
{
  static void *jump[16] = {
    &&__NONE, &&__NONE, &&__NONE, &&__NONE, &&__NONE, &&__NONE, &&__NONE, &&__NONE,
    &&__STRING, &&__NONE, &&__VARIANT, &&__ARRAY, &&__NONE, &&__FUNCTION, &&__NONE, &&__NONE
    };

  TYPE type = value->type;

  printf("type = %p / ", (void *)type);
  
  if (TYPE_is_object(type))
    goto __OBJECT;
  else
    goto *jump[type];

__STRING:
  printf("STRING %p\n", value->_string.addr);
  return;

__OBJECT:
  if (value->_object.object)
  {
    printf("OBJECT (%p)\n", value->_object.object);
    printf("-> %s\n", OBJECT_class(value->_object.object)->name);
  }
  else
    printf("OBJECT (NULL)\n");
  return;

__VARIANT:
  if (value->_variant.vtype == T_STRING)
    printf("STRING %p\n", *((char **)value->_variant.value));
  else if (TYPE_is_object(value->_variant.vtype))
    printf("OBJECT (%s %p)\n", OBJECT_class(*((void **)value->_variant.value))->name, *((void **)value->_variant.value));
  return;

__FUNCTION:
  printf("FUNCTION %s (%s %p)\n", value->_function.class->name, OBJECT_class(value->_function.object)->name, value->_function.object);
  return;

__ARRAY:
  printf("ARRAY\n");
  return;

__NONE:
  printf("\n");
  return;
}
#endif

PUBLIC void EXEC_release_return_value(void)
{
  RELEASE(RP);
  RP->type = T_VOID;
}


#define print_register() \
  printf("| SP = %d  BP = %d  FP = %p  PC = %p  EC = %p\n", SP - (VALUE *)STACK_base, BP - (VALUE *)STACK_base, FP, PC, EC)


PUBLIC void EXEC_enter(void)
{
  int i;
  FUNCTION *func; // = EXEC.func;
  int nparam = EXEC.nparam;
  void *object = EXEC.object;
  CLASS *class = EXEC.class;

  #if DEBUG_STACK
  printf("\n| >> EXEC_enter(%s, %ld, %d)\n", EXEC.class->name, EXEC.index, nparam);
  print_register();
  #endif

  /*
  func_id = value->index;

  if (value->kind & FUNCTION_PUBLIC)
    func_id = (int)(class->table[func_id].desc.method->exec;

  */

  func = &class->load->func[EXEC.index];
  #if DEBUG_STACK
  if (func->debug)
    printf(" | >> %s\n", func->debug->name);
  #endif

  /* vérification des paramètres */

  if (nparam < func->npmin)
    THROW(E_NEPARAM);
  else if (nparam > func->n_param)
    THROW(E_TMPARAM);

  /* paramètres obligatoires et réservation */

  for (i = 0; i < func->npmin; i++)
  {
    VALUE_conv(SP - nparam + i, func->param[i].type);
    /*BORROW(SP - nparam + i);*/
  }

  if (func->npmin < func->n_param)
  {
    /* paramètres facultatifs, mais passés à la fonction */

    for (i = func->npmin; i < nparam; i++)
    {
      if (SP[- nparam + i].type == T_VOID)
        SP[- nparam + i]._void.ptype = func->param[i].type;
      else
      {
        VALUE_conv(SP - nparam + i, func->param[i].type);
        /*BORROW(SP - nparam + i);*/
      }
    }

    /* paramètres facultatifs non passés à la fonction */

    if (nparam < func->n_param)
    {
      STACK_check(func->n_param - nparam);

      for (i = nparam; i < func->n_param; i++)
      {
        SP->type = T_VOID;
        SP->_void.ptype = func->param[i].type;
        SP++;
      }
    }
  }

  /* sauvegarde du contexte */

  STACK_push_frame(&EXEC_current);

  /* Vérification de la pile */

  STACK_check(func->stack_usage);

  /* entrée de fonction */

  BP = SP;
  FP = func;
  PC = func->code;
  OP = object;
  CP = class;
  EP = NULL;

  if (func->error)
  {
    #if DEBUG_ERROR
      printf("EXEC_enter: EC = PC + %d\n", func->error);
    #endif
    EC = PC + func->error;
  }
  else
    EC = NULL;

  /* On référence l'objet pour qu'il ne soit pas détruit pendant l'exécution de la méthode */
  OBJECT_REF(OP, "EXEC_enter");

  /*printf("PC = %p  nparam = %d\n", PC, FP->n_param);*/

  /* Initialisation des variables locales */

  if (func->n_local)
  {
    for (i = 0; i < func->n_local; i++)
    {
      VALUE_class_default(class, SP, func->local[i].type);
      SP++;
    }
  }

  /* Initialisation des variables de controles */

  if (func->n_ctrl)
  {
    for (i = 0; i < func->n_ctrl; i++)
    {
      SP->type = T_VOID;
      SP++;
    }
  }

  /*printf("EXEC_enter: nparam = %d  nlocal = %d  nctrl = %d\n", func->n_param, func->n_local, func->n_ctrl);*/
  
  RP->type = T_VOID;

  #if DEBUG_STACK
  printf("| << EXEC_enter()\n");
  print_register();
  #endif
}



PUBLIC void EXEC_leave(bool keep_ret_value)
{
  int i, n;
  boolean drop;
  VALUE ret;

#if DEBUG_STACK
  printf("| >> EXEC_leave\n");
  print_register();
#endif

  /* Je garde cette bourde en commentaires.
     La honte...

  for (i = 0; i < (SP - BP); i++)
  {
    SP--;
    #if 1
    printf("Release local %p (0x%08lX)\n", SP, (ulong)SP->type);
    #endif
    RELEASE(SP);
  }

  */

  /* Sauvegarde de la valeur de retour.

     Car elle peut être écrasée par un _free() généré par un
     OBJECT_UNREF
  */

  ret = *RP;

  /* Libération des variables locales et de controle */

  n = FP->n_param + (SP - BP);

  for (i = 0; i < n; i++)
    POP();

  /* On libère l'objet reservé dans EXEC_enter() */
  OBJECT_UNREF(&OP, "EXEC_leave");

  /* restitution du contexte */

  STACK_pop_frame(&EXEC_current);

  /*printf("PC = %p  nparam = %d\n", PC, nparam);*/

  if (PC)
  {
    drop = PCODE_is_void(*PC);
    if (SP[-1].type != T_FUNCTION)
    {
      printf("EXEC_leave: type != T_FUNCTION\n");
      POP(); /* description de la fonction ? */
    }
    else
    {
      SP--;
      OBJECT_UNREF(&SP->_function.object, "EXEC_leave");
    }
    /*output = PCODE_is_output(*PC);*/
  }
  else
  {
    drop = TRUE;
    keep_ret_value = TRUE;
  }

  /* libération de la pile utilisée */

  /*
    Attention ! le RELEASE(RP) conjugué au UNBORROW(RP)
    peut faire descendre le compteur de référence d'un objet à -1 !
  */

  /*
    NOTE: les paramètres input-output ont le même problème que la
    valeur de retour. Ils peuvent contenir des références désallouées !
    A CORRIGER ! En attendant, ils sont désactivés.
  */

#if DEBUG_REF
  printf("EXEC_leave: return\n");
#endif

  if (!drop)
  {
    *SP = ret;
    RP->type = T_VOID;
    if (PCODE_is_variant(*PC))
      VALUE_conv(SP, T_VARIANT);
    SP++;
  }
  else if (!keep_ret_value)
    EXEC_release_return_value();

/* output = TRUE

      }
      else
      {
        if (!drop)
        {
          UNBORROW(RP);
          SP[-(nparam + 1)] = *RP;
          RP->type = T_VOID;
        }
        else
          RELEASE(RP);
      }
    }
  }
*/

#if DEBUG_STACK
  printf("| << EXEC_leave()\n");
  print_register();
  printf("\n");
#endif
}


PUBLIC void EXEC_function_real(bool keep_ret_value)
{
  /*PCODE *save = PC;*/
  boolean retry;

  /* nécessaire, car *PC est examiné par EXEC_leave pour savoir si on attend une valeur de retour */
  STACK_push_frame(&EXEC_current);

  PC = NULL;

  EXEC_enter();

  if (PC != NULL)
  {
    do
    {
      TRY
      {
        EXEC_loop();
        retry = FALSE;
      }
      CATCH
      {
        if (ERROR_info.code == E_UNKNOWN)
        {
          while (PC != NULL)
            EXEC_leave(FALSE);
            
          PROPAGATE();
        }
        else if (EP != NULL)
        {
          #if DEBUG_ERROR
          printf("#1 EP = %d  SP = %d\n", EP - STACK_base, SP - STACK_base);
          #endif

          while (SP > EP)
            POP();

          PC = EC;
          retry = TRUE;
          /* On va directement sur le END TRY */
        }
        else if (EC != NULL)
        {
          #if DEBUG_ERROR
          printf("#2 EC = %p\n", EC);
          #endif

          PC = EC;
          EC = NULL;
          retry = TRUE;
        }
        else
        {
          #if DEBUG_ERROR
          printf("#3\n");
          #endif

          if (EXEC_debug && !STACK_has_error_handler())
          {
            while (SP > TRACE.ep)
              POP();

            PC = TRACE.ec;

            TRACE_main(TRUE);
            retry = TRUE;
          }
          else
          {
            while (PC != NULL && EC == NULL)
              EXEC_leave(FALSE);

            if (PC == NULL)
            {
              /*printf("try to propagate\n");*/
              STACK_pop_frame(&EXEC_current);
              PROPAGATE();
              
              /*ERROR_print();
              exit(1);*/
              /*retry = FALSE;*/
            }

            PC = EC;
            EC = NULL;
            retry = TRUE;
          }
        }
      }
      END_TRY

      #if DEBUG_ERROR
      if (retry)
        printf("retry %p\n", PC);
      #endif
    }
    while (retry);
  }

  if (!keep_ret_value)
    EXEC_release_return_value();

  STACK_pop_frame(&EXEC_current);
  /*PC = save;*/
}


PUBLIC bool EXEC_call_native(void (*exec)(), void *object, TYPE type, VALUE *param)
{
  TYPE save = GAMBAS_ReturnType;
  GAMBAS_Error = FALSE;

  GAMBAS_ReturnType = type;
  TEMP.type = T_NULL;

  /*OBJECT_REF(object, "EXEC_call_native"); N'est plus nécessaire ! */
  (*exec)(object, (void *)param);
  /*OBJECT_UNREF(&object, "EXEC_call_native");*/

  GAMBAS_ReturnType = save;
  return GAMBAS_Error;
}


PUBLIC void EXEC_native(void)
{
  CLASS_DESC_METHOD *desc = EXEC.desc;
  bool drop = EXEC.drop;
  int nparam = EXEC.nparam;
  bool use_stack = EXEC.use_stack;
  void *object = EXEC.object;

  int i; /* ,j */
  VALUE *value;
  TYPE *sign;
  bool error;
  void *free;
  int n;
  VALUE ret;

  /* vérification des paramètres */

  #if DEBUG_STACK
  printf("| >> EXEC_native: %s.%s (%p)\n", EXEC.class->name, desc->name, &desc);
  #endif

  if (nparam < desc->npmin)
    THROW(E_NEPARAM);
  
  if (!desc->npvar)
  {
    if (nparam > desc->npmax)
      THROW(E_TMPARAM);
  
    value = &SP[-nparam];
    sign = desc->signature;
  
    for (i = 0; i < desc->npmin; i++, value++, sign++)
      VALUE_conv(value, *sign);
  
    if (desc->npmin < desc->npmax)
    {
      for (; i < nparam; i++, value++, sign++)
      {
        if (value->type != T_VOID)
          VALUE_conv(value, *sign);
      }
      
      n = desc->npmax - nparam;

      STACK_check(n);
      SP += n;
      nparam = desc->npmax;

      for (; i < nparam; i++, value++)
        value->type = T_VOID;  
    }
  }
  else
  {
    value = &SP[-nparam];
    sign = desc->signature;
  
    for (i = 0; i < desc->npmin; i++, value++, sign++)
      VALUE_conv(value, *sign);
  
    if (desc->npmin < desc->npmax)
    {
      if (nparam < desc->npmax)
      {
        for (; i < nparam; i++, value++, sign++)
        {
          if (value->type != T_VOID)
            VALUE_conv(value, *sign);
        }
  
        n = desc->npmax - nparam;
  
        STACK_check(n);
        SP += n;
        nparam = desc->npmax;
  
        for (; i < nparam; i++, value++)
          value->type = T_VOID;  
      }
      else
      {
        for (; i < desc->npmax; i++, value++, sign++)
        {
          if (value->type != T_VOID)
            VALUE_conv(value, *sign);
        }
      }
    }
  
    if (desc->npmax < nparam)
      EXEC.nparvar = nparam - desc->npmax;
    else
      EXEC.nparvar = 0;
  
    for (; i < nparam; i++, value++)
      VARIANT_undo(value);
  }

  error = EXEC_call_native(desc->exec, object, desc->type, &SP[-nparam]);
  ret = TEMP;

  /* Libération des arguments */

  while (nparam > 0)
  {
    nparam--;
    POP();
  }

  /* Si la description de la fonction se trouve sur la pile */

  if (use_stack)
  {
    SP--;
    free = SP->_function.object;
    SP->type = T_NULL;
  }

  /*
  #if DEBUG_STACK
  else
    printf("** SP != func SP = %p func = %p **\n>", SP, func);
  #endif
  */

  if (!error)
  {
    if (desc->type == T_VOID)
    {
      if (!drop)
      {
        SP->type = T_VOID;
        SP->_void.ptype = T_NULL;
        SP++;
      }
    }
    else
    {
      BORROW(&ret);

      if (drop)
        RELEASE(&ret);
      else
      {
        VALUE_conv(&ret, desc->type);
        *SP = ret;
        SP++;
      }
    }
  }

  if (use_stack)
    OBJECT_UNREF(&free, "EXEC_native (FUNCTION)");

  if (error)
    PROPAGATE();

  #if DEBUG_STACK
  printf("| << EXEC_native: %s (%p)\n", desc->name, &desc);
  #endif
}


PUBLIC void EXEC_object(VALUE *val, CLASS **class, OBJECT **object, boolean *defined)
{
  if (val->type == T_FUNCTION && val->_function.kind == FUNCTION_UNKNOWN)
  {
    EXEC.class = val->_function.class;
    EXEC.object = val->_function.object;
    EXEC.drop = FALSE;
    EXEC.nparam = 0;
    EXEC.native = TRUE;
    EXEC.desc = &EXEC.class->special[SPEC_UNKNOWN]->method;
    EXEC.use_stack = FALSE;
    EXEC.index = val->_function.index;
    EXEC.property = TRUE;

    /*SP--; on ne décremente pas SP, car on ne sait pas sur quoi pointe val */
    /* => il faut qu'il y ait une place vide dans la pile, sinon crash !*/
    *object = EXEC.object;

    EXEC_native();

    OBJECT_UNREF(object, "EXEC_object (FUNCTION)");

    SP--;
    *val = *SP;
  }

  if (val->type == T_CLASS)
  {
    *class = val->_class.class;
    *object = NULL;
    *defined = TRUE;

    CLASS_load(*class);

    #if 0
    if ((*class)->auto_create)
    {
      *object = CLASS_auto_create(*class); /* object is checked by CLASS_auto_create */
      OBJECT_REF(*object, "EXEC_object");
    }
    #endif
  }
  else
  {
    if (val->type == T_OBJECT)
    {
      *object = val->_object.object;
      *class = OBJECT_class(*object);
      *defined = FALSE;
    }
    else if (TYPE_is_object(val->type))
    {
      *object = val->_object.object;
      *class = val->_object.class;
      *defined = TRUE;
    }
    else if (val->type == T_VARIANT)
    {
      if (val->_variant.vtype == T_OBJECT)
      {
        *object = *((void **)val->_variant.value);
        *class = OBJECT_class(*object);
        *defined = FALSE;
      }
      else if (TYPE_is_object(val->_variant.vtype))
      {
        *object = *((void **)val->_variant.value);
        *class = (CLASS *)val->_variant.vtype;
        *defined = FALSE;
      }
      else
        THROW(E_NOBJECT);
    }
    else
      THROW(E_NOBJECT);

    if (*object == NULL)
      THROW(E_NULL);

    CLASS_load(*class);

    if ((*class)->check(*object))
      THROW(E_IOBJECT);
  }
}


PUBLIC void EXEC_public(CLASS *class, void *object, const char *name, int nparam)
{
  CLASS_DESC *desc;

  desc = CLASS_get_symbol_desc_kind(class, name, (object != NULL) ? CD_METHOD : CD_STATIC_METHOD, 0);

  if (desc == NULL)
    return;

  EXEC.class = desc->method.class;
  EXEC.object = object;
  EXEC.nparam = nparam;
  EXEC.drop = TRUE;

  if (FUNCTION_is_native(&desc->method))
  {
    EXEC.desc = &desc->method;
    EXEC.use_stack = FALSE;
    EXEC_native();
  }
  else
  {
    EXEC.index = (long)desc->method.exec;
    //EXEC.func = &class->load->func[(long)desc->method.exec]
    EXEC_function();
  }
}



PUBLIC boolean EXEC_spec(int special, CLASS *class, void *object, int nparam, boolean drop)
{
  CLASS_DESC *desc = class->special[special];

  if (desc == NULL)
    return TRUE;

  if (CLASS_DESC_get_type(desc) == CD_STATIC_METHOD)
  {
    if (object != NULL)
      return TRUE;
  }
  else
  {
    if (object == NULL)
    {
      if (class->auto_create)
      {
        object = EXEC_auto_create(class);
        OBJECT_UNREF(&object, "EXEC_spec");
      }

      if (object == NULL)
        THROW(E_NOBJECT);
    }
  }

  EXEC.class = desc->method.class;
  EXEC.object = object;
  EXEC.nparam = nparam;
  EXEC.drop = drop;

  if (FUNCTION_is_native(&desc->method))
  {
    EXEC.desc = &desc->method;
    EXEC.use_stack = FALSE;
    EXEC.native = TRUE;
    EXEC_native();
  }
  else
  {
    //EXEC.func = &class->load->func[(long)desc->method.exec]
    EXEC.index = (long)desc->method.exec;
    EXEC.native = FALSE;
    EXEC_function_real(!drop);
  }

  return FALSE;
}


/* PRIVATE void dump(int np) */
/* { */
/*   int i; */
/*  */
/*   for (i = 1; i <= np; i++) */
/*     printf("SP[%d] = %d  ", -i, SP[-i].type); */
/*  */
/*   printf("\n"); */
/* } */
/*  */

/*
  The highest parent method is called first, but get only the parameters
  not consumed by the child methods.
*/

PUBLIC void EXEC_special_inheritance(int special, CLASS *class, OBJECT *object, int nparam, boolean drop)
{
  CLASS *her[MAX_INHERITANCE];
  int npher[MAX_INHERITANCE];
  int nher;
  int i, np;
  CLASS_DESC *desc;

  /*if (class->parent != NULL)
    EXEC_special_inheritance(special, class->parent, object, 0, drop);*/

  nher = CLASS_get_inheritance(class, her);

  for(i = 0, np = 0; i < nher; i++)
  {
    class = her[i];
    npher[i] = np;

    desc = class->special[special];
    if (!desc)
      continue;

    np += desc->method.npmax;
  }

  for(;;)
  {
    nher--;
    if (nher < 0)
      break;
    class = her[nher];

    if (special == SPEC_NEW)
    {
      if (!CLASS_is_native(class))
      {
        EXEC.class = class;
        EXEC.object = object;
        EXEC.index = FUNC_INIT_DYNAMIC;
        //EXEC.func = &class->load->func[FUNC_INIT_DYNAMIC];
        EXEC.native = FALSE;
        EXEC.nparam = 0;

        EXEC_function();
      }
    }

    desc = class->special[special];
    if (!desc)
      continue;

    /*np = Min(nparam, desc->method.npmax);*/

    np = Max(0, nparam - npher[nher]);


    /*
    dup = ((np > 0) && nher > 0);

    if (dup)
    {
      STACK_check(nparam);

      for (i = 0; i < np; i++)
      {
        SP[i] = SP[i - np];
        BORROW(&SP[i]);
      }

      SP += np;

    }
    */

    EXEC_special(special, class, object, np, drop);
    nparam -= np;
  }
}


PUBLIC void EXEC_new(void)
{
  CLASS *class;
  int np;
  boolean event;
  void *object;
  char *name = NULL;
  char *cname = NULL;

  np = *PC & 0xFF;
  event = np & CODE_NEW_EVENT;
  np &= 0x3F;

  /* Instanciation */

  SP -= np;

  if (SP->type == T_CLASS)
  {
    class = SP->_class.class;
  }
  else if (TYPE_is_string(SP->type))
  {
    STRING_copy_from_value_temp(&cname, SP);
    class = CLASS_find(cname);
    RELEASE(SP);
    SP->type = T_NULL;
  }
  else
    THROW(E_TYPE, "String", TYPE_get_name(SP->type));

  SP += np;

  CLASS_load(class);

  if (class->new == NULL)
    THROW(E_CSTATIC, class->name);

  if (event)
  {
    SP--;

    if (!TYPE_is_string(SP->type))
      THROW(E_TYPE, "String", TYPE_get_name(SP->type));

    STRING_copy_from_value_temp(&name, SP);

    STRING_ref(name);
    (*class->new)(&object, class, name, ((OP == NULL) ? (OBJECT *)CP : (OBJECT *)OP));
    STRING_unref(&name);

    RELEASE(SP);

    np -= 2;
  }
  else
  {
    (*class->new)(&object, class, name, ((OP == NULL) ? (OBJECT *)CP : (OBJECT *)OP));
    np--;
  }

  /*OBJECT_REF(object, "EXEC_new");*/

  /* On retourne l'objet créé */

  TRY
  {  
    EXEC_special_inheritance(SPEC_NEW, class, object, np, TRUE);

    SP--; /* class */

    SP->_object.class = class;
    SP->_object.object = object;
    SP++;
  }
  CATCH
  {
    OBJECT_UNREF(&object, "EXEC_new");
    SP--; /* class */
    SP->type = T_NULL;
    SP++;
    PROPAGATE();
  }
  END_TRY

  /*  PUSH(); */

  /* L'objet a été crée avec un nombre de référence égal à 1.
     On remet ce nombre à 0 maintenant que l'objet est prêt.
     Mais on ne le détruit pas ! */

  /* OBJECT_UNREF(&object, "EXEC_new"); */
}


PUBLIC void EXEC_class(void)
{
  //fprintf(stderr, ">> EXEC_class: SP = %d  drop = %d\n", SP - (VALUE *)STACK_base, EXEC.drop);

  if (EXEC_special(SPEC_CALL, EXEC.class, EXEC.object, EXEC.nparam, EXEC.drop))
  {
    if (EXEC.nparam < 1)
      THROW(E_NEPARAM);
    else if (EXEC.nparam > 1)
      THROW(E_TMPARAM);

    VALUE_conv(SP - 1, (TYPE)EXEC.class);
  }
  else
  {
    if (RP->type != T_VOID) /* Ceci est fait pour un EXEC_native, mais pas pour un EXEC_function */
    {
      BORROW(RP);
      SP[-1] = *RP; /* On écrase la classe */
      EXEC_release_return_value();
    }
    else
      POP(); /* On enlève la classe */
  }
  
  //fprintf(stderr, "<< EXEC_class: SP = %d\n\n", SP - (VALUE *)STACK_base);
}


PUBLIC void EXEC_nop(void)
{
  printf("* NOP *\n");
}


PUBLIC void EXEC_ILLEGAL(void)
{
  THROW(E_ILLEGAL);
}


PUBLIC void EXEC_quit(void)
{
  GAMBAS_DoNotRaiseEvent = TRUE;

  HOOK(quit)();

  THROW(E_UNKNOWN);
}


PUBLIC void *EXEC_auto_create(CLASS *class)
{
  void *object;

  object = CLASS_auto_create(class, 0); /* object is checked by CLASS_auto_create */
  OBJECT_REF(object, "EXEC_auto_create");
  return object;
}


Generated by  Doxygen 1.6.0   Back to index