
/*
 * Las siguientes partes son derechos adquiridos de sus autores individuales.
 * www - http://www.harbour-project.org
 *
 * Copyright 2001 Ryszard Glab <rglab@imid.med.pl>
 *   Documentacin en Ingls de codeblock.txt
 *
 * Copyright 2001 Alejandro de Grate <alex_degarate@hotmail.com>
 *   Traduccin al Espaol de codeblock.txt
 *
 * Vea doc/license.txt por los trminos de la licencia.
 *
 */

Implementacin de Harbour de codeblocks (bloques de cdigo)
===========================================================

Compilacin de un codeblock
  Durante el tiempo de Compilacin, el codeblock es almacenado en la 
  siguiente forma:
  - la cabecera
  - la ristra de bytes de pcodes

La cabecera almacena informacin acerca de variables locales 
referenciadas.
+0: el byte pcode para _PUSHBLOCK
+1: el nmero de bytes que definen a un codeblock
+3: el nmero de parmetros codeblock (declarados entre || en el codeblock)
+5: nmero de variables locales usadas declaradas en el procedimiento /
    funcin donde el codeblock es creado.
+7: La lista de las posiciones de variables locales de los procedimientos /
    funciones, en la pila eval del procedimiento / funcin. Cada variable
    local usada en un codeblock usa 2 bytes en esta lista. Cuando son 
    usados codeblocks anidados, entonces esta lista es creada solamente 
    en el codeblock ms externo.
+x: La ristra de bytes pcode, siguiendo a la cabecera.
+y: El byte pcode para _ENDBLOCK


Creacin de un codeblock
========================
 Cuando el opcode HB_P_PUSHBLOCK es ejecutado entonces la estructura 
HB_ITEM es creada y puesta en la pila de evaluacin. El tipo de item 
es IT_BLOCK.
El valor de este item es un puntero a la estructura HB_CODEBLOCK. 
Adicionalmente este item almacena la base de las variables estticas 
definidas para el procedimiento/funcin actual. - esto es usado durante 
la evaluacin de un codeblock cuando la evaluacin es llamada desde 
cdigo desde otro mdulo PRG. Tambin el nmero de parmetros esperados 
es almacenado.

 La estructura HB_CODEBLOCK almacena un puntero a la ristra (stream) 
de pcodes que es ejecutada durante la evaluacin de un codeblock. 
Este almacena tambin el puntero a la tabla con referencia a variables 
locales. Valores de todas las variables locales definidas en un 
procedimiento y usadas en un codeblock son reemplazadas con una 
referencia a un valor almacenado en un pool de variables de memoria 
global. Esto permite el correcto acceso a variables locales aisladas 
en un codeblock devuelto desde sta funcin (sea directamente en una
sentencia RETURN  indirectamente por asignarlo ste a una variable 
esttica  MEMVAR). 
Este reemplazo automtico e incondicional es requerido porque no hay 
un mtodo seguro de encontrar si un codeblock ser accedido desde 
fuera de una funcin dnde ste es creado.

Cuando son usados codeblocks anidados, solamente el codeblock ms 
externo crea la tabla - todo codeblock interno usa esta tabla. 
Esto permite compartir la tabla entre codeblocks anidados - , la 
tabla es borrada si no hay ms referencias a ella. 
Esto es causado por el hecho que un codeblock interno puede ser 
creado durante la evaluacin del codeblock exterior cuando las 
variables locales no existen como en este ejemplo:

PROCEDURE MAIN()
PRIVATE foo, bar

  Test()
  EVAL( foo )
  EVAL( bar )

RETURN

PROCEDURE Test()
LOCAL a:='FOO', b:='BAR'

  foo ={ || a + ( bar:=EVAL( {|| b} ) ) }

RETURN


Evaluacin de un codeblock
==========================
Los parmetros pasados a un codeblock son puestos en la pila de 
evaluacin antes de la evaluacin del codeblock. Ellos son accedidos 
exactamente igual que cualquier parmetro de funcin. Cuando un 
parmetro de codeblock es referenciado, entonces su posicin en 
la pila de evaluacin es usada.
Cuando una variable local de un procedimiento es referenciada 
entonces el ndice dentro de la tabla de posiciones de variables 
locales (copiada de la cabecera) es usada. El valor negativo es 
usado como un ndice para distinguirlo de la referencia a un 
parmetro del codeblock.


Incompatibilidad con Clipper
============================

1) Variables locales aisladas pasadas por referencia
   -------------------------------------------------
Hay una pequea diferencia entre el manejo de las variables pasadas 
por referencia en un codeblock.
El siguiente cdigo lo explica (gracias a David G. Holm)

Function Main()
Local nTest
Local bBlock1 := MakeBlock()
Local bBlock2 := {|| DoThing( @nTest ), qout("From Main: ", nTest ) }

   eval( bBlock1 )
   eval( bBlock2 )

Return( NIL )

Function MakeBlock()
Local nTest
Return( {|| DoThing( @nTest ), qout("From MakeBlock: ", nTest ) } )


Function DoThing( n )
   n := 42
Return( NIL )


   En Clipper esto produce:
Desde MakeBlock = NIL
Desde Main      = 42 

En Harbour esta produce: (esta es la salida correcta, en mi opinin ) 
Desde MakeBlock = 42
Desde Main      = 42 


2) Alcance de variables sin declarar
   ---------------------------------
Considere el siguiente cdigo:

PROCEDURE MAIN()
LOCAL cb
  cb :=Detach()
  ? EVAL( cb, 10 )

RETURN

FUNCTION Detach()
LOCAL b:={|x| x+a}
LOCAL a:=0
RETURN b

En Clipper la variable 'a' en un codeblock tiene alcance *local* ,
sin embargo en Harbour la variable 'a' tiene un alcance *privado*. 
Como resultado de ello, en Clipper este cdigo imprimir 10 y en 
Harbour este producir "error de argumento" en la operacin '+'.
Esto ser cierto cuando la variable 'a' sea declarada como PRIVATE.

PROCEDURE MAIN()
LOCAL cb
PRIVATE a
  cb := Detach()
  ? EVAL( cb, 10 )
RETURN

El cdigo de arriba tambin produce 10 en Clipper (an si es 
compilado con el switch -a  -v).





