2013-12-10 16:14:06 +00:00
with H2.Pool ;
with System.Address_To_Access_Conversions ;
2013-12-19 14:36:14 +00:00
with Ada.Unchecked_Deallocation ; -- for h2scm c interface. TOOD: move it to a separate file
with Interfaces.C ;
2013-12-10 16:14:06 +00:00
package body H2.Scheme is
----------------------------------------------------------------------------------
-- EXCEPTIONS
----------------------------------------------------------------------------------
Allocation_Error : exception ;
Size_Error : exception ;
2013-12-19 13:54:47 +00:00
Syntax_Error : exception ;
2013-12-18 14:58:46 +00:00
Evaluation_Error : exception ;
2013-12-10 16:14:06 +00:00
Internal_Error : exception ;
----------------------------------------------------------------------------------
-- INTERNALLY-USED TYPES
----------------------------------------------------------------------------------
type Memory_Element_Pointer is access all Memory_Element ;
for Memory_Element_Pointer ' Size use Object_Pointer_Bits ; -- ensure that it can be overlayed by an ObjectPointer
type Thin_Memory_Element_Array is array ( 1 . . Memory_Size ' Last ) of Memory_Element ;
type Thin_Memory_Element_Array_Pointer is access all Thin_Memory_Element_Array ;
for Thin_Memory_Element_Array_Pointer ' Size use Object_Pointer_Bits ;
2013-12-19 13:54:47 +00:00
subtype Opcode_Type is Object_Integer range 0 . . 5 ;
2013-12-17 16:04:55 +00:00
Opcode_Exit : constant Opcode_Type := Opcode_Type ' ( 0 ) ;
Opcode_Evaluate_Object : constant Opcode_Type := Opcode_Type ' ( 1 ) ;
2013-12-19 13:54:47 +00:00
Opcode_Evaluate_Group : constant Opcode_Type := Opcode_Type ' ( 2 ) ;
Opcode_Evaluate_Syntax : constant Opcode_Type := Opcode_Type ' ( 3 ) ;
Opcode_Evaluate_Procedure : constant Opcode_Type := Opcode_Type ' ( 4 ) ;
Opcode_Apply : constant Opcode_Type := Opcode_Type ' ( 5 ) ;
2013-12-17 16:04:55 +00:00
2013-12-10 16:14:06 +00:00
----------------------------------------------------------------------------------
-- COMMON OBJECTS
----------------------------------------------------------------------------------
Cons_Object_Size : constant Pointer_Object_Size := 2 ;
Cons_Car_Index : constant Pointer_Object_Size := 1 ;
Cons_Cdr_Index : constant Pointer_Object_Size := 2 ;
2013-12-17 16:04:55 +00:00
Frame_Object_Size : constant Pointer_Object_Size := 5 ;
2013-12-10 16:14:06 +00:00
Frame_Stack_Index : constant Pointer_Object_Size := 1 ;
Frame_Opcode_Index : constant Pointer_Object_Size := 2 ;
Frame_Operand_Index : constant Pointer_Object_Size := 3 ;
2013-12-17 16:04:55 +00:00
Frame_Environment_Index : constant Pointer_Object_Size := 4 ;
Frame_Return_Index : constant Pointer_Object_Size := 5 ;
2013-12-18 14:58:46 +00:00
Mark_Object_Size : constant Pointer_Object_Size := 1 ;
Mark_Context_Index : constant Pointer_Object_Size := 1 ;
2013-12-17 16:04:55 +00:00
Procedure _Object_Size : constant Pointer_Object_Size := 1 ;
Procedure _Opcode_Index : constant Pointer_Object_Size := 1 ;
Closure_Object_Size : constant Pointer_Object_Size := 2 ;
Closure_Code_Index : constant Pointer_Object_Size := 1 ;
Closure_Environment_Index : constant Pointer_Object_Size := 2 ;
2013-12-10 16:14:06 +00:00
2013-12-19 13:54:47 +00:00
Pair_Object_Size : constant Pointer_Object_Size := 3 ;
Pair_Key_Size : constant Pointer_Object_Size := 1 ;
Pair_Value_Size : constant Pointer_Object_Size := 2 ;
Pair_Link_Size : constant Pointer_Object_Size := 3 ;
2013-12-10 16:14:06 +00:00
procedure Set_New_Location ( Object : in Object_Pointer ; Ptr : in Memory_Element_Pointer ) ;
procedure Set_New_Location ( Object : in Object_Pointer ; Ptr : in Object_Pointer ) ;
pragma Inline ( Set_New_Location ) ;
function Get_New_Location ( Object : in Object_Pointer ) return Object_Pointer ;
pragma Inline ( Get_New_Location ) ;
----------------------------------------------------------------------------------
-- POINTER AND DATA CONVERSION
----------------------------------------------------------------------------------
function Get_Pointer_Type ( Pointer : in Object_Pointer ) return Object_Pointer_Type is
pragma Inline ( Get_Pointer_Type ) ;
Word : Object_Word ;
for Word ' Address use Pointer ' Address ;
begin
return Object_Pointer_Type ( Word and Object_Word ( Object_Pointer_Type_Mask ) ) ;
end Get_Pointer_Type ;
function Is_Pointer ( Pointer : in Object_Pointer ) return Standard . Boolean is
begin
return Get_Pointer_Type ( Pointer ) = Object_Pointer_Type_Pointer ;
end Is_Pointer ;
function Is_Special_Pointer ( Pointer : in Object_Pointer ) return Standard . Boolean is
begin
-- though sepcial, these 3 pointers gets true for Is_Pointer.
return Pointer = Nil_Pointer or else
Pointer = True_Pointer or else
Pointer = False_Pointer ;
end Is_Special_Pointer ;
function Is_Normal_Pointer ( Pointer : in Object_Pointer ) return Standard . Boolean is
begin
return Is_Pointer ( Pointer ) and then
not Is_Special_Pointer ( Pointer ) ;
end Is_Normal_Pointer ;
function Is_Integer ( Pointer : in Object_Pointer ) return Standard . Boolean is
begin
return Get_Pointer_Type ( Pointer ) = Object_Pointer_Type_Integer ;
end Is_Integer ;
function Is_Character ( Pointer : in Object_Pointer ) return Standard . Boolean is
begin
return Get_Pointer_Type ( Pointer ) = Object_Pointer_Type_Character ;
end Is_Character ;
function Is_Byte ( Pointer : in Object_Pointer ) return Standard . Boolean is
begin
return Get_Pointer_Type ( Pointer ) = Object_Pointer_Type_Byte ;
end Is_Byte ;
function Integer_To_Pointer ( Int : in Object_Integer ) return Object_Pointer is
Pointer : Object_Pointer ;
Word : Object_Word ;
for Word ' Address use Pointer ' Address ;
begin
if Int < 0 then
-- change the sign of a negative number.
-- '-Int' may violate the range of Object_Integer
-- if it is Object_Integer'First. So I add 1 to 'Int'
-- first to make it fall between Object_Integer'First + 1
-- .. 0 and typecast it with an extra increment.
--Word := Object_Word (-(Int + 1)) + 1;
-- Let me use Object_Signed_Word instead of the trick shown above
Word := Object_Word ( - Object_Signed_Word ( Int ) ) ;
-- shift the number to the left by 2 and
-- set the highest bit on by force.
Word := ( Word * ( 2 * * Object_Pointer_Type_Bits ) ) or Object_Word ( Object_Pointer_Type_Integer ) or ( 2 * * ( Word ' Size - 1 ) ) ;
else
Word := Object_Word ( Int ) ;
-- Shift 'Word' to the left by 2 and set the integer mark.
Word := ( Word * ( 2 * * Object_Pointer_Type_Bits ) ) or Object_Word ( Object_Pointer_Type_Integer ) ;
end if ;
--return Object_Word_To_Object_Pointer (Word);
return Pointer ;
end Integer_To_Pointer ;
function Character_To_Pointer ( Char : in Object_Character ) return Object_Pointer is
Pointer : Object_Pointer ;
Word : Object_Word ;
for Word ' Address use Pointer ' Address ;
begin
-- Note: Object_Character may get defined to Wide_Wide_Character.
-- and Wide_Wide_Character'Last is #16#7FFFFFFF#. Such a large value
-- may get lost when it's shifted left by 2 if Object_Word is 32 bits long
-- or short. In reality, the last Unicode code point assigned is far
-- less than #16#7FFFFFFF# as of this writing. So I should not be
-- worried about it for the time being.
Word := Object_Character ' Pos ( Char ) ;
Word := ( Word * ( 2 * * Object_Pointer_Type_Bits ) ) or Object_Word ( Object_Pointer_Type_Character ) ;
--return Object_Word_To_Object_Pointer (Word);
return Pointer ;
end Character_To_Pointer ;
function Byte_To_Pointer ( Byte : in Object_Byte ) return Object_Pointer is
Pointer : Object_Pointer ;
Word : Object_Word ;
for Word ' Address use Pointer ' Address ;
begin
Word := Object_Word ( Byte ) ;
Word := ( Word * ( 2 * * Object_Pointer_Type_Bits ) ) or Object_Word ( Object_Pointer_Type_Byte ) ;
return Pointer ;
end Byte_To_Pointer ;
function Pointer_To_Word is new Ada . Unchecked_Conversion ( Object_Pointer , Object_Word ) ;
--function Pointer_To_Word (Pointer: in Object_Pointer) return Object_Word is
-- Word: Object_Word;
-- for Word'Address use Pointer'Address;
--begin
-- return Word;
--end Pointer_To_Word;
pragma Inline ( Pointer_To_Word ) ;
function Pointer_To_Integer ( Pointer : in Object_Pointer ) return Object_Integer is
Word : Object_Word := Pointer_To_Word ( Pointer ) ;
begin
if ( Word and ( 2 * * ( Word ' Size - 1 ) ) ) / = 0 then
-- if the highest bit is set, it's a negative number
-- originally. strip it off and shift 'Word' to the right by 2.
return Object_Integer ( - Object_Signed_Word ( Word and not ( 2 * * ( Word ' Size - 1 ) ) ) / ( 2 * * Object_Pointer_Type_Bits ) ) ;
else
-- shift Word to the right by Object_Pointer_Type_Bits.
return Object_Integer ( Word / ( 2 * * Object_Pointer_Type_Bits ) ) ;
end if ;
end Pointer_To_Integer ;
function Pointer_To_Character ( Pointer : in Object_Pointer ) return Object_Character is
Word : Object_Word := Pointer_To_Word ( Pointer ) ;
begin
return Object_Character ' Val ( Word / ( 2 * * Object_Pointer_Type_Bits ) ) ;
end Pointer_To_Character ;
function Pointer_To_Byte ( Pointer : in Object_Pointer ) return Object_Byte is
Word : Object_Word := Pointer_To_Word ( Pointer ) ;
begin
return Object_Byte ( Word / ( 2 * * Object_Pointer_Type_Bits ) ) ;
end Pointer_To_Byte ;
-- Check if a character object contains a given string in the payload.
function Match ( Object : in Object_Pointer ;
Data : in Object_String ) return Standard . Boolean is
Slot : Object_Character_Array renames Object . Character_Slot ;
begin
return Slot ( Slot ' First . . Slot ' Last - 1 ) = Object_Character_Array ( Data ) ;
end ;
procedure Copy_String ( Source : in Object_String ;
Target : out Object_Character_Array ) is
begin
-- This procedure is not generic. The size of the Source
-- and Target must be in the expected length.
pragma Assert ( Source ' Length + 1 = Target ' Length ) ;
-- Method 1. Naive. It doesn't look Adaish.
-- ---------------------------------------------------------------------
--declare
-- x: Storage_Count;
--begin
-- x := Target'First;
-- for index in Source'Range loop
-- Target(x) := Source(index);
-- x := x + 1;
-- end loop;
-- Target(x) := Object_Character'First; -- Object_Character'Val(0);
--end;
-- Method 2.
2013-12-11 15:40:57 +00:00
-- ObjectAda complains that the member of Object_String is not
-- aliased because Object_Character_Array is an array of aliased
-- Object_Character.It points to LRM 4.6(12); The component subtypes
-- shall statically match.
2013-12-10 16:14:06 +00:00
-- ---------------------------------------------------------------------
--Target(Target'First .. Target'Last - 1) := Object_Character_Array (Source(Source'First .. Source'Last));
--Target(Target'Last) := Object_Character'First; -- Object_Character'Val(0);
-- Method 3. Use unchecked conversion
declare
subtype Character_Array is Object_Character_Array ( Target ' First . . Target ' Last - 1 ) ;
function To_Character_Array is new Ada . Unchecked_Conversion ( Object_String , Character_Array ) ;
begin
Target ( Target ' First . . Target ' Last - 1 ) := To_Character_Array ( Source ) ;
Target ( Target ' Last ) := Object_Character ' First ; -- Object_Character'Val(0);
end ;
end Copy_String ;
procedure Copy_String ( Source : in Object_Character_Array ;
Target : out Object_String ) is
begin
pragma Assert ( Source ' Length = Target ' Length + 1 ) ;
declare
subtype Character_Array is Object_Character_Array ( Source ' First . . Source ' Last - 1 ) ;
subtype String_Array is Object_String ( Target ' Range ) ;
function To_Character_Array is new Ada . Unchecked_Conversion ( Character_Array , String_Array ) ;
begin
Target := To_Character_Array ( Source ( Source ' First . . Source ' Last - 1 ) ) ;
end ;
end Copy_String ;
function To_String ( Source : in Object_Character_Array ) return Object_String is
begin
2013-12-11 15:40:57 +00:00
-- ObjectAda complains that the member of Object_String is not
-- aliased because Object_Character_Array is an array of aliased
-- Object_Character. It points to LRM 4.6(12); The component subtypes
-- shall statically match. So let me turn to unchecked conversion.
2013-12-10 16:14:06 +00:00
declare
subtype Character_Array is Object_Character_Array ( Source ' First . . Source ' Last - 1 ) ;
subtype String_Array is Object_String ( 1 . . Source ' Length - 1 ) ;
function To_Character_Array is new Ada . Unchecked_Conversion ( Character_Array , String_Array ) ;
begin
return To_Character_Array ( Source ( Source ' First . . Source ' Last - 1 ) ) ;
--return String_Array (Source (Source'First .. Source'Last - 1));
end ;
end To_String ;
type Thin_String is new Object_String ( Standard . Positive ' Range ) ;
type Thin_String_Pointer is access all Thin_String ;
for Thin_String_Pointer ' Size use Object_Pointer_Bits ;
-- TODO: move away these utilities routines
--function To_Thin_String_Pointer (Source: in Object_Pointer) return Thin_String_Pointer is
-- type Character_Pointer is access all Object_Character;
-- Ptr: Thin_String_Pointer;
-- X: Character_Pointer;
-- for X'Address use Ptr'Address;
-- pragma Import (Ada, X);
--begin
-- this method requires Object_Character_Array to have aliased Object_Character.
-- So i've commented out this function and turn to a different method below.
-- X := Source.Character_Slot(Source.Character_Slot'First)'Access;
-- return Ptr;
--end To_Thin_String_Pointer;
--function To_Thin_String_Pointer (Source: in Object_Pointer) return Thin_String_Pointer is
-- function To_Thin_Pointer is new Ada.Unchecked_Conversion (System.Address, Thin_String_Pointer);
--begin
-- return To_Thin_Pointer(Source.Character_Slot'Address);
--end To_Thin_String_Pointer;
function To_Thin_String_Pointer ( Source : in Object_Pointer ) return Thin_String_Pointer is
X : aliased Thin_String ;
for X ' Address use Source.Character_Slot ' Address ;
begin
return X ' Unchecked_Access ;
end To_Thin_String_Pointer ;
procedure Put_String ( TS : in Thin_String_Pointer ) ;
pragma Import ( C , Put_String , "puts" ) ;
-- TODO: delete this procedure
procedure Print_Object_Pointer ( Msg : in Object_String ; Source : in Object_Pointer ) is
W : Object_Word ;
for W ' Address use Source ' Address ;
2013-12-17 16:04:55 +00:00
Ptr_Type : Object_Pointer_Type ;
2013-12-10 16:14:06 +00:00
begin
2013-12-17 16:04:55 +00:00
Ptr_Type := Get_Pointer_Type ( Source ) ;
if Ptr_Type = Object_Pointer_Type_Character then
Text_IO . Put_Line ( Msg & Object_Character ' Image ( Pointer_To_Character ( Source ) ) ) ;
elsif Ptr_Type = Object_Pointer_Type_Integer then
Text_IO . Put_Line ( Msg & Object_Integer ' Image ( Pointer_To_Integer ( Source ) ) ) ;
elsif Is_Special_Pointer ( Source ) then
2013-12-10 16:14:06 +00:00
Text_IO . Put_Line ( Msg & " at " & Object_Word ' Image ( W ) ) ;
elsif Source . Kind = Character_Object then
Text_IO . Put ( Msg & " at " & Object_Word ' Image ( W ) & " at " & Object_Kind ' Image ( Source . Kind ) & " size " & Object_Size ' Image ( Source . Size ) & " - " ) ;
if Source . Kind = Moved_Object then
Text_IO . Put_Line ( To_String ( Get_New_Location ( Source ) . Character_Slot ) ) ;
else
Text_IO . Put_Line ( To_String ( Source . Character_Slot ) ) ;
end if ;
else
Text_IO . Put_Line ( Msg & " at " & Object_Word ' Image ( W ) & " at " & Object_Kind ' Image ( Source . Kind ) ) ;
end if ;
end Print_Object_Pointer ;
----------------------------------------------------------------------------------
-- MEMORY MANAGEMENT
----------------------------------------------------------------------------------
-- (define x ())
-- (define x #())
-- (define x $())
-- (define x #(
-- (#a . 10) ; a is a synbol
-- (b . 20) ; b is a variable. resolve b at the eval-time and use it.
-- ("c" . 30) ; "c" is a string
-- )
-- )
-- (clone x y) -- deep copy
-- (define y x) -- reference assignment
-- (set! x.a 20) -- syntaic sugar
-- (set! (get x #a) 20)
-- (define x (make-hash))
-- I wanted to reuse the Size field to store the pointer to
-- the new location. GCC-GNAT 3.2.3 suffered from various constraint
-- check errors. So i gave up on this procedure.
--------------------------------------------------------------------
--procedure Set_New_Location (Object: in Object_Pointer; Ptr: in Memory_Element_Pointer) is
--New_Addr: Memory_Element_Pointer;
--for New_Addr'Address use Object.Size'Address;
--pragma Import (Ada, New_Addr);
--begin
--New_Addr := Ptr;
--end Set_New_Location;
--function Get_New_Location (Object: in Object_Pointer) return Object_Pointer is
--New_Ptr: Object_Pointer;
--for New_Ptr'Address use Object.Size'Address;
--pragma Import (Ada, New_Ptr);
--begin
--return New_Ptr;
--end;
-- Instead, I created a new object kind that indicates a moved object.
-- The original object is replaced by this special object. this special
-- object takes up the smallest space that a valid object can take. So
-- it is safe to overlay it on any normal objects.
procedure Set_New_Location ( Object : in Object_Pointer ; Ptr : in Memory_Element_Pointer ) is
subtype Moved_Object_Record is Object_Record ( Moved_Object , 0 ) ;
Moved_Object : Moved_Object_Record ;
for Moved_Object ' Address use Object.all ' Address ;
-- pramga Import must not be specified here as I'm counting
-- on the default initialization of Moved_Object to overwrite
-- the Kind discriminant in particular.
--pragma Import (Ada, Moved_Object); -- this must not be used.
function To_Object_Pointer is new Ada . Unchecked_Conversion ( Memory_Element_Pointer , Object_Pointer ) ;
begin
Moved_Object . New_Pointer := To_Object_Pointer ( Ptr ) ;
end Set_New_Location ;
procedure Set_New_Location ( Object : in Object_Pointer ; Ptr : in Object_Pointer ) is
subtype Moved_Object_Record is Object_Record ( Moved_Object , 0 ) ;
Moved_Object : Moved_Object_Record ;
for Moved_Object ' Address use Object.all ' Address ;
--pragma Import (Ada, Moved_Object); -- this must not be used.
begin
Moved_Object . New_Pointer := Ptr ;
end Set_New_Location ;
function Get_New_Location ( Object : in Object_Pointer ) return Object_Pointer is
begin
return Object . New_Pointer ;
end Get_New_Location ;
2013-12-19 13:54:47 +00:00
function Allocate_Bytes_In_Heap ( Heap : access Heap_Record ;
Heap_Bytes : in Memory_Size ) return Memory_Element_Pointer is
2013-12-10 16:14:06 +00:00
Avail : Memory_Size ;
2013-12-19 13:54:47 +00:00
Result : Memory_Element_Pointer ;
2013-12-10 16:14:06 +00:00
begin
Avail := Heap . Size - Heap . Bound ;
if Heap_Bytes > Avail then
2013-12-19 13:54:47 +00:00
return null ;
2013-12-10 16:14:06 +00:00
end if ;
2013-12-19 13:54:47 +00:00
Result := Heap . Space ( Heap . Bound + 1 ) ' Unchecked_Access ;
Heap . Bound := Heap . Bound + Heap_Bytes ;
return Result ;
2013-12-10 16:14:06 +00:00
end Allocate_Bytes_In_Heap ;
procedure Copy_Object ( Source : in Object_Pointer ;
Target : in out Memory_Element_Pointer ) is
pragma Inline ( Copy_Object ) ;
subtype Target_Object_Record is Object_Record ( Source . Kind , Source . Size ) ;
type Target_Object_Pointer is access all Target_Object_Record ;
Target_Object : Target_Object_Pointer ;
for Target_Object ' Address use Target ' Address ;
pragma Import ( Ada , Target_Object ) ;
begin
-- This procedure should work. but gnat 4.3.2 on whiite(ppc32,wii)
-- produced erroneous code when it was called from Move_One_Object().
-- Target_Object_Record'Size, Target_Object.all'Size, and
-- Target_Object_Record'Max_Size_In_Stroage_Elements were not
-- always correct. For example, for a character object containing
-- the string "lambda", Target_Object.all'Size returned 72 while
-- it's supposed to be 96.
Target_Object . all := Source . all ;
pragma Assert ( Source . all ' Size = Target_Object . all ' Size ) ;
end Copy_Object ;
2013-12-11 16:30:56 +00:00
procedure Copy_Object_With_Size ( Source : in Object_Pointer ;
Target : in out Memory_Element_Pointer ;
Bytes : in Memory_Size ) is
pragma Inline ( Copy_Object_With_Size ) ;
2013-12-10 16:14:06 +00:00
-- This procedure uses a more crude type for copying objects.
-- It's the result of an effort to work around some compiler
-- issues mentioned above.
Tgt : Thin_Memory_Element_Array_Pointer ;
for Tgt ' Address use Target ' Address ;
pragma Import ( Ada , Tgt ) ;
Src : Thin_Memory_Element_Array_Pointer ;
for Src ' Address use Source ' Address ;
pragma Import ( Ada , Src ) ;
begin
Tgt ( 1. . Bytes ) := Src ( 1. . Bytes ) ;
2013-12-11 16:30:56 +00:00
end Copy_Object_With_Size ;
2013-12-10 16:14:06 +00:00
procedure Collect_Garbage ( Interp : in out Interpreter_Record ) is
Last_Pos : Memory_Size ;
New_Heap : Heap_Number ;
--function To_Object_Pointer is new Ada.Unchecked_Conversion (Memory_Element_Pointer, Object_Pointer);
function Move_One_Object ( Object : in Object_Pointer ) return Object_Pointer is
begin
if Is_Special_Pointer ( Object ) then
Print_Object_Pointer ( "Moving special ..." , Object ) ;
return Object ;
end if ;
if Object . Kind = Moved_Object then
Print_Object_Pointer ( "Moving NOT ..." , Object ) ;
-- the object has moved to the new heap.
-- the size field has been updated to the new object
-- in the 'else' block below. i can simply return it
-- without further migration.
return Get_New_Location ( Object ) ;
else
Print_Object_Pointer ( "Moving REALLY ..." , Object ) ;
declare
Bytes : Memory_Size ;
-- This variable holds the allocation result
Ptr : Memory_Element_Pointer ;
-- Create an overlay for type conversion
New_Object : Object_Pointer ;
for New_Object ' Address use Ptr ' Address ;
pragma Import ( Ada , New_Object ) ;
begin
-- Target_Object_Record'Max_Size_In_Storage_Elements gave
-- some erroneous values when compiled with GNAT 4.3.2 on
-- WII(ppc) Debian.
--Bytes := Target_Object_Record'Max_Size_In_Storage_Elements;
Bytes := Object . all ' Size / System . Storage_Unit ;
-- Allocate space in the new heap
2013-12-19 13:54:47 +00:00
Ptr := Allocate_Bytes_In_Heap (
2013-12-10 16:14:06 +00:00
Heap => Interp . Heap ( New_Heap ) ,
2013-12-19 13:54:47 +00:00
Heap_Bytes => Bytes
2013-12-10 16:14:06 +00:00
) ;
-- Allocation here must not fail because
-- I'm allocating the new space in a new heap for
-- moving an existing object in the current heap.
-- It must not fail, assuming the new heap is as large
-- as the old heap, and garbage collection doesn't
-- allocate more objects than in the old heap.
pragma Assert ( Ptr / = null ) ;
-- Copy the payload to the new object
--Copy_Object (Object, Ptr); -- not reliable with some compilers
2013-12-11 16:30:56 +00:00
Copy_Object_With_Size ( Object , Ptr , Bytes ) ; -- use this instead
2013-12-10 16:14:06 +00:00
pragma Assert ( Object . all ' Size = New_Object . all ' Size ) ;
pragma Assert ( Bytes = New_Object . all ' Size / System . Storage_Unit ) ;
-- Let the size field of the old object point to the
-- new object allocated in the new heap. It is returned
-- in the 'if' block at the beginning of this function
-- if the object is marked with FLAG_MOVED;
Set_New_Location ( Object , Ptr ) ;
Text_IO . Put_Line ( Object_Word ' Image ( Pointer_To_Word ( Object ) ) & Object_Word ' Image ( Pointer_To_Word ( New_Object ) ) ) ;
Text_IO . Put_Line ( " Flags....after " & Object_Kind ' Image ( Object . Kind ) & " New Size " & Object_Size ' Image ( Object . Size ) & " New Loc: " & Object_Word ' Image ( Pointer_To_Word ( Object . New_Pointer ) ) ) ;
-- Return the new object
return New_Object ;
end ;
end if ;
end Move_One_Object ;
function Scan_New_Heap ( Start_Position : in Memory_Size ) return Memory_Size is
Ptr : Memory_Element_Pointer ;
Position : Memory_Size ;
begin
Position := Start_Position ;
--Text_IO.Put_Line ("Start Scanning New Heap from " & Memory_Size'Image (Start_Position) & " Bound: " & Memory_Size'Image (Interp.Heap(New_Heap).Bound));
while Position < = Interp . Heap ( New_Heap ) . Bound loop
--Text_IO.Put_Line (">>> Scanning New Heap from " & Memory_Size'Image (Position) & " Bound: " & Memory_Size'Image (Interp.Heap(New_Heap).Bound));
Ptr := Interp . Heap ( New_Heap ) . Space ( Position ) ' Unchecked_Access ;
declare
Object : Object_Pointer ;
for Object ' Address use Ptr ' Address ;
pragma Import ( Ada , Object ) ; -- not really needed
--subtype Target_Object_Record is Object_Record (Object.Kind, Object.Size);
Bytes : Memory_Size ;
begin
--Bytes := Target_Object_Record'Max_Size_In_Storage_Elements;
Bytes := Object . all ' Size / System . Storage_Unit ;
--Text_IO.Put_Line (">>> Scanning Obj " & Object_Kind'Image (Object.Kind) & " size " & Object_Size'Image(Object.Size) & " at " & Object_Word'Image(Pointer_To_Word(Object)) & " Bytes " & Memory_Size'Image(Bytes));
if Object . Kind = Pointer_Object then
for i in Object . Pointer_Slot ' Range loop
if Is_Pointer ( Object . Pointer_Slot ( i ) ) then
Object . Pointer_Slot ( i ) := Move_One_Object ( Object . Pointer_Slot ( i ) ) ;
end if ;
end loop ;
end if ;
Position := Position + Bytes ;
end ;
end loop ;
return Position ;
end Scan_New_Heap ;
procedure Compact_Symbol_Table is
Pred : Object_Pointer ;
Cons : Object_Pointer ;
begin
-- TODO: Change code here if the symbol table structure is changed to a hash table.
Pred := Nil_Pointer ;
Cons := Interp . Symbol_Table ;
while Cons / = Nil_Pointer loop
pragma Assert ( Cons . Tag = Cons_Object ) ;
declare
Car : Object_Pointer renames Cons . Pointer_Slot ( Cons_Car_Index ) ;
Cdr : Object_Pointer renames Cons . Pointer_Slot ( Cons_Cdr_Index ) ;
begin
pragma Assert ( Car . Kind = Moved_Object or else Car . Tag = Symbol_Object ) ;
if Car . Kind / = Moved_Object and then
( Car . Flags and Syntax_Object ) = 0 then
-- A non-syntax symbol has not been moved.
-- Unlink the cons cell from the symbol table.
Text_IO . Put_Line ( "COMPACT_SYMBOL_TABLE Unlinking " & To_String ( Car . Character_Slot ) ) ;
if Pred = Nil_Pointer then
Interp . Symbol_Table := Cdr ;
else
Pred . Pointer_Slot ( Cons_Cdr_Index ) := Cdr ;
end if ;
end if ;
Cons := Cdr ;
end ;
end loop ;
end Compact_Symbol_Table ;
begin
-- As the Heap_Number type is a modular type that can
-- represent 0 and 1, incrementing it gives the next value.
New_Heap := Interp . Current_Heap + 1 ;
-- Migrate objects in the root table
Print_Object_Pointer ( "Root_Table ..." , Interp . Root_Table ) ;
Interp . Root_Table := Move_One_Object ( Interp . Root_Table ) ;
2013-12-18 14:58:46 +00:00
Interp . Mark := Move_One_Object ( Interp . Mark ) ;
2013-12-10 16:14:06 +00:00
-- Scane the heap
Last_Pos := Scan_New_Heap ( Interp . Heap ( New_Heap ) . Space ' First ) ;
-- Traverse the symbol table for unreferenced symbols.
-- If the symbol has not moved to the new heap, the symbol
-- is not referenced by any other objects than the symbol
-- table itself
Text_IO . Put_Line ( ">>> [COMPACTING SYMBOL TABLE]" ) ;
Compact_Symbol_Table ;
Print_Object_Pointer ( ">>> [MOVING SYMBOL TABLE]" , Interp . Symbol_Table ) ;
-- Migrate the symbol table itself
Interp . Symbol_Table := Move_One_Object ( Interp . Symbol_Table ) ;
Text_IO . Put_Line ( ">>> [SCANNING HEAP AGAIN AFTER SYMBOL TABLE MIGRATION]" ) ;
-- Scan the new heap again from the end position of
-- the previous scan to move referenced objects by
-- the symbol table.
Last_Pos := Scan_New_Heap ( Last_Pos ) ;
-- Swap the current heap and the new heap
Interp . Heap ( Interp . Current_Heap ) . Bound := 0 ;
Interp . Current_Heap := New_Heap ;
Text_IO . Put_Line ( ">>> [GC DONE]" ) ;
end Collect_Garbage ;
2013-12-19 13:54:47 +00:00
function Allocate_Bytes ( Interp : access Interpreter_Record ;
Bytes : in Memory_Size ) return Memory_Element_Pointer is
2013-12-10 16:14:06 +00:00
-- I use this temporary variable not to change Result
-- if Allocation_Error should be raised.
Tmp : Memory_Element_Pointer ;
begin
pragma Assert ( Bytes > 0 ) ;
2013-12-19 13:54:47 +00:00
Tmp := Allocate_Bytes_In_Heap ( Interp . Heap ( Interp . Current_Heap ) , Bytes ) ;
2013-12-10 16:14:06 +00:00
if Tmp = null and then ( Interp . Trait . Trait_Bits and No_Garbage_Collection ) = 0 then
2013-12-19 13:54:47 +00:00
Collect_Garbage ( Interp . all ) ;
Tmp := Allocate_Bytes_In_Heap ( Interp . Heap ( Interp . Current_Heap ) , Bytes ) ;
2013-12-10 16:14:06 +00:00
if Tmp = null then
raise Allocation_Error ;
end if ;
end if ;
2013-12-19 13:54:47 +00:00
return Tmp ;
2013-12-10 16:14:06 +00:00
end Allocate_Bytes ;
2013-12-19 13:54:47 +00:00
function Allocate_Pointer_Object ( Interp : access Interpreter_Record ;
Size : in Pointer_Object_Size ;
Initial : in Object_Pointer ) return Object_Pointer is
2013-12-10 16:14:06 +00:00
subtype Pointer_Object_Record is Object_Record ( Pointer_Object , Size ) ;
type Pointer_Object_Pointer is access all Pointer_Object_Record ;
Ptr : Memory_Element_Pointer ;
Obj_Ptr : Pointer_Object_Pointer ;
2013-12-19 13:54:47 +00:00
for Obj_Ptr ' Address use Ptr ' Address ;
2013-12-10 16:14:06 +00:00
pragma Import ( Ada , Obj_Ptr ) ;
2013-12-19 13:54:47 +00:00
Result : Object_Pointer ;
for Result ' Address use Ptr ' Address ;
pragma Import ( Ada , Result ) ;
2013-12-10 16:14:06 +00:00
begin
2013-12-19 13:54:47 +00:00
Ptr := Allocate_Bytes (
2013-12-10 16:14:06 +00:00
Interp ,
2013-12-19 13:54:47 +00:00
Memory_Size ' ( Pointer_Object_Record ' Max_Size_In_Storage_Elements )
2013-12-10 16:14:06 +00:00
) ;
Obj_Ptr . all := (
Kind => Pointer_Object ,
Size => Size ,
Flags => 0 ,
Scode => 0 ,
Tag => Unknown_Object ,
Pointer_Slot => ( others => Initial )
) ;
2013-12-19 13:54:47 +00:00
return Result ;
2013-12-10 16:14:06 +00:00
end Allocate_Pointer_Object ;
2013-12-19 13:54:47 +00:00
function Allocate_Character_Object ( Interp : access Interpreter_Record ;
Size : in Character_Object_Size ) return Object_Pointer is
2013-12-10 16:14:06 +00:00
subtype Character_Object_Record is Object_Record ( Character_Object , Size ) ;
type Character_Object_Pointer is access all Character_Object_Record ;
Ptr : Memory_Element_Pointer ;
Obj_Ptr : Character_Object_Pointer ;
2013-12-19 13:54:47 +00:00
for Obj_Ptr ' Address use Ptr ' Address ;
2013-12-10 16:14:06 +00:00
pragma Import ( Ada , Obj_Ptr ) ;
2013-12-19 13:54:47 +00:00
Result : Object_Pointer ;
for Result ' Address use Ptr ' Address ;
pragma Import ( Ada , Result ) ;
2013-12-10 16:14:06 +00:00
begin
2013-12-19 13:54:47 +00:00
Ptr := Allocate_Bytes (
Interp . Self ,
Memory_Size ' ( Character_Object_Record ' Max_Size_In_Storage_Elements )
2013-12-10 16:14:06 +00:00
) ;
Obj_Ptr . all := (
Kind => Character_Object ,
Size => Size ,
Flags => 0 ,
Scode => 0 ,
Tag => Unknown_Object ,
Character_Slot => ( others => Object_Character ' First )
) ;
2013-12-19 13:54:47 +00:00
return Result ;
2013-12-10 16:14:06 +00:00
end Allocate_Character_Object ;
2013-12-19 13:54:47 +00:00
function Allocate_Character_Object ( Interp : access Interpreter_Record ;
Source : in Object_String ) return Object_Pointer is
Result : Object_Pointer ;
2013-12-10 16:14:06 +00:00
begin
if Source ' Length > Character_Object_Size ' Last then
raise Size_Error ;
end if ;
2013-12-19 13:54:47 +00:00
Result := Allocate_Character_Object ( Interp , Character_Object_Size ' ( Source ' Length ) ) ;
2013-12-10 16:14:06 +00:00
Copy_String ( Source , Result . Character_Slot ) ;
2013-12-19 13:54:47 +00:00
return Result ;
2013-12-10 16:14:06 +00:00
end Allocate_Character_Object ;
2013-12-19 13:54:47 +00:00
function Allocate_Byte_Object ( Interp : access Interpreter_Record ;
Size : in Byte_Object_Size ) return Object_Pointer is
2013-12-10 16:14:06 +00:00
subtype Byte_Object_Record is Object_Record ( Byte_Object , Size ) ;
type Byte_Object_Pointer is access all Byte_Object_Record ;
Ptr : Memory_Element_Pointer ;
Obj_Ptr : Byte_Object_Pointer ;
2013-12-19 13:54:47 +00:00
for Obj_Ptr ' Address use Ptr ' Address ;
2013-12-10 16:14:06 +00:00
pragma Import ( Ada , Obj_Ptr ) ;
2013-12-19 13:54:47 +00:00
Result : Object_Pointer ;
for Result ' Address use Ptr ' Address ;
pragma Import ( Ada , Result ) ;
2013-12-10 16:14:06 +00:00
begin
2013-12-19 13:54:47 +00:00
Ptr := Allocate_Bytes ( Interp . Self , Memory_Size ' ( Byte_Object_Record ' Max_Size_In_Storage_Elements ) ) ;
2013-12-10 16:14:06 +00:00
Obj_Ptr . all := (
Kind => Byte_Object ,
Size => Size ,
Flags => 0 ,
Scode => 0 ,
Tag => Unknown_Object ,
Byte_Slot => ( others => 0 )
) ;
2013-12-19 13:54:47 +00:00
return Result ;
2013-12-10 16:14:06 +00:00
end Allocate_Byte_Object ;
2013-12-19 13:54:47 +00:00
function Verify_Pointer ( Source : in Object_Pointer ) return Object_Pointer is
pragma Inline ( Verify_Pointer ) ;
2013-12-18 14:58:46 +00:00
begin
2013-12-19 13:54:47 +00:00
if not Is_Normal_Pointer ( Source ) or else
Source . Kind / = Moved_Object then
return Source ;
end if ;
2013-12-18 14:58:46 +00:00
2013-12-19 13:54:47 +00:00
return Get_New_Location ( Source ) ;
end Verify_Pointer ;
----------------------------------------------------------------------------------
function Make_Cons ( Interp : access Interpreter_Record ;
Car : in Object_Pointer ;
Cdr : in Object_Pointer ) return Object_Pointer is
Cons : Object_Pointer ;
2013-12-18 14:58:46 +00:00
begin
2013-12-19 13:54:47 +00:00
Cons := Allocate_Pointer_Object ( Interp , Cons_Object_Size , Nil_Pointer ) ;
Cons . Pointer_Slot ( Cons_Car_Index ) := Verify_Pointer ( Car ) ; -- TODO: is this really a good idea? resise this...
Cons . Pointer_Slot ( Cons_Cdr_Index ) := Verify_Pointer ( Cdr ) ; -- If so, use Verify_pointer after Allocate_XXX
Cons . Tag := Cons_Object ;
return Cons ;
2013-12-18 14:58:46 +00:00
end Make_Cons ;
2013-12-10 16:14:06 +00:00
function Is_Cons ( Source : in Object_Pointer ) return Standard . Boolean is
pragma Inline ( Is_Cons ) ;
begin
2013-12-18 14:58:46 +00:00
return Is_Normal_Pointer ( Source ) and then
2013-12-10 16:14:06 +00:00
Source . Tag = Cons_Object ;
end Is_Cons ;
2013-12-17 16:04:55 +00:00
function Get_Car ( Source : in Object_Pointer ) return Object_Pointer is
pragma Inline ( Get_Car ) ;
2013-12-18 14:58:46 +00:00
pragma Assert ( Is_Cons ( Source ) ) ;
begin
2013-12-17 16:04:55 +00:00
return Source . Pointer_Slot ( Cons_Car_Index ) ;
end Get_Car ;
procedure Set_Car ( Source : in out Object_Pointer ;
Value : in Object_Pointer ) is
pragma Inline ( Set_Car ) ;
2013-12-18 14:58:46 +00:00
pragma Assert ( Is_Cons ( Source ) ) ;
begin
2013-12-17 16:04:55 +00:00
Source . Pointer_Slot ( Cons_Car_Index ) := Value ;
end Set_Car ;
function Get_Cdr ( Source : in Object_Pointer ) return Object_Pointer is
pragma Inline ( Get_Cdr ) ;
2013-12-18 14:58:46 +00:00
pragma Assert ( Is_Cons ( Source ) ) ;
begin
2013-12-17 16:04:55 +00:00
return Source . Pointer_Slot ( Cons_Cdr_Index ) ;
end Get_Cdr ;
procedure Set_Cdr ( Source : in out Object_Pointer ;
Value : in Object_Pointer ) is
pragma Inline ( Set_Cdr ) ;
2013-12-18 14:58:46 +00:00
pragma Assert ( Is_Cons ( Source ) ) ;
begin
2013-12-17 16:04:55 +00:00
Source . Pointer_Slot ( Cons_Cdr_Index ) := Value ;
end Set_Cdr ;
2013-12-10 16:14:06 +00:00
2013-12-18 14:58:46 +00:00
function Reverse_Cons ( Source : in Object_Pointer ) return Object_Pointer is
pragma Assert ( Is_Cons ( Source ) ) ;
-- Note: The non-nil cdr in the last cons cell gets lost.
-- e.g.) Reversing (1 2 3 . 4) results in (3 2 1)
Ptr : Object_Pointer ;
Next : Object_Pointer ;
Prev : Object_Pointer ;
2013-12-17 16:04:55 +00:00
begin
2013-12-18 14:58:46 +00:00
Prev := Nil_Pointer ;
Ptr := Source ;
loop
Next := Get_Cdr ( Ptr ) ;
Set_Cdr ( Ptr , Prev ) ;
Prev := Ptr ;
if Is_Cons ( Next ) then
Ptr := Next ;
else
exit ;
end if ;
end loop ;
2013-12-17 16:04:55 +00:00
2013-12-18 14:58:46 +00:00
return Ptr ;
end Reverse_Cons ;
2013-12-17 16:04:55 +00:00
----------------------------------------------------------------------------------
2013-12-19 13:54:47 +00:00
function Make_String ( Interp : access Interpreter_Record ;
Source : in Object_String ) return Object_Pointer is
Result : Object_Pointer ;
2013-12-10 16:14:06 +00:00
begin
2013-12-19 13:54:47 +00:00
Result := Allocate_Character_Object ( Interp , Source ) ;
2013-12-10 16:14:06 +00:00
Result . Tag := String_Object ;
Print_Object_Pointer ( "Make_String Result - " & Source , Result ) ;
2013-12-19 13:54:47 +00:00
return Result ;
2013-12-10 16:14:06 +00:00
end Make_String ;
2013-12-17 16:04:55 +00:00
function Is_Symbol ( Source : in Object_Pointer ) return Standard . Boolean is
pragma Inline ( Is_Symbol ) ;
begin
return Is_Normal_Pointer ( Source ) and then
Source . Tag = Symbol_Object ;
end Is_Symbol ;
2013-12-19 13:54:47 +00:00
function Make_Symbol ( Interp : access Interpreter_Record ;
Source : in Object_String ) return Object_Pointer is
Ptr : Object_Pointer ;
2013-12-10 16:14:06 +00:00
begin
-- TODO: the current linked list implementation isn't efficient.
-- change the symbol table to a hashable table.
-- Find an existing symbol in the symbol table.
2013-12-19 13:54:47 +00:00
Ptr := Interp . Symbol_Table ;
while Ptr / = Nil_Pointer loop
pragma Assert ( Is_Cons ( Ptr ) ) ;
2013-12-10 16:14:06 +00:00
declare
2013-12-19 13:54:47 +00:00
Car : Object_Pointer renames Ptr . Pointer_Slot ( Cons_Car_Index ) ;
Cdr : Object_Pointer renames Ptr . Pointer_Slot ( Cons_Cdr_Index ) ;
2013-12-10 16:14:06 +00:00
begin
--Text_IO.Put_Line (Car.Kind'Img & Car.Tag'Img & Object_Word'Image(Pointer_To_Word(Car)));
pragma Assert ( Car . Tag = Symbol_Object ) ;
2013-12-19 13:54:47 +00:00
if Match ( Car , Source ) then
return Car ;
--Print_Object_Pointer ("Make_Symbol Result (Existing) - " & Source, Car);
2013-12-10 16:14:06 +00:00
end if ;
2013-12-19 13:54:47 +00:00
Ptr := Cdr ;
2013-12-10 16:14:06 +00:00
end ;
end loop ;
2013-12-19 13:54:47 +00:00
--Text_IO.Put_Line ("Creating a symbol .. " & Source);
2013-12-10 16:14:06 +00:00
-- Create a symbol object
2013-12-19 13:54:47 +00:00
Ptr := Allocate_Character_Object ( Interp , Source ) ;
Ptr . Tag := Symbol_Object ;
2013-12-10 16:14:06 +00:00
-- TODO: ensure that Result is not reclaimed by GC.
2013-12-19 13:54:47 +00:00
-- Make it GC-aweare. Protect Ptr
2013-12-10 16:14:06 +00:00
-- Link the symbol to the symbol table.
2013-12-19 13:54:47 +00:00
Interp . Symbol_Table := Make_Cons ( Interp . Self , Ptr , Interp . Symbol_Table ) ;
--Print_Object_Pointer ("Make_Symbol Result - " & Source, Result);
return Ptr ;
2013-12-17 16:04:55 +00:00
end Make_Symbol ;
----------------------------------------------------------------------------------
2013-12-19 13:54:47 +00:00
function Make_Array ( Interp : access Interpreter_Record ;
Size : in Pointer_Object_Size ) return Object_Pointer is
Arr : Object_Pointer ;
2013-12-17 16:04:55 +00:00
begin
2013-12-19 13:54:47 +00:00
Arr := Allocate_Pointer_Object ( Interp , Size , Nil_Pointer ) ;
Arr . Tag := Array_Object ;
return Arr ;
end Make_Array ;
2013-12-17 16:04:55 +00:00
2013-12-19 13:54:47 +00:00
function Is_Array ( Source : in Object_Pointer ) return Standard . Boolean is
pragma Inline ( Is_Array ) ;
2013-12-17 16:04:55 +00:00
begin
2013-12-19 13:54:47 +00:00
return Is_Normal_Pointer ( Source ) and then
Source . Tag = Array_Object ;
end Is_Array ;
----------------------------------------------------------------------------------
--
-- Environment is a cons cell whose slots represents:
-- Car: Point to the first key/value pair.
-- Cdr: Point to Parent environment
--
-- A key/value pair is held in an array object consisting of 3 slots.
-- #1: Key
-- #2: Value
-- #3: Link to the next key/value array.
--
-- Interp.Environment Interp.Root_Environment
-- | |
-- | V
-- | +----+----+ +----+----+
-- +---> | | | ----> | | | Nil|
-- +-|--+----- +-|--+-----
-- | |
-- | +--> another list
-- V
-- +----+----+----+ +----+----+----+ +----+----+----+ +----+----+----+
-- list: | | | | | ----> | | | | | -----> | | | | | -----> | | | | | Nil|
-- +-|--+-|-------+ +-|--+-|-------+ +-|--+-|-------+ +-|--+-|-------+
-- | | | | | | | |
-- V V V V V V V V
-- Key Value Key Value Key Value Key Value
--
-- Upon initialization, Interp.Environment is equal to Interp.Root_Environment.
-- CDR(Interp.Root_Environment) is Nil_Pointer.
--
-- TODO: Change environment implementation to a hash table or something similar
function Make_Environment ( Interp : access Interpreter_Record ;
Parent : in Object_Pointer ) return Object_Pointer is
pragma Inline ( Make_Environment ) ;
begin
return Make_Cons ( Interp , Nil_Pointer , Parent ) ;
end Make_Environment ;
function Find_In_Environment_List ( Interp : access Interpreter_Record ;
List : in Object_Pointer ;
Key : in Object_Pointer ) return Object_Pointer is
Arr : Object_Pointer ;
begin
Arr := List ;
while Arr / = Nil_Pointer loop
pragma Assert ( Is_Array ( Arr ) ) ;
pragma Assert ( Arr . Size = 3 ) ;
2013-12-17 16:04:55 +00:00
2013-12-19 13:54:47 +00:00
if Arr . Pointer_Slot ( 1 ) = Key then
return Arr ;
2013-12-17 16:04:55 +00:00
end if ;
2013-12-19 13:54:47 +00:00
Arr := Arr . Pointer_Slot ( 3 ) ;
2013-12-17 16:04:55 +00:00
end loop ;
return null ; -- not found. note that it's not Nil_Pointer.
2013-12-19 13:54:47 +00:00
end Find_In_Environment_List ;
2013-12-17 16:04:55 +00:00
procedure Set_Environment ( Interp : in out Interpreter_Record ;
Key : in Object_Pointer ;
Value : in Object_Pointer ) is
2013-12-19 13:54:47 +00:00
Arr : Object_Pointer ;
2013-12-17 16:04:55 +00:00
begin
2013-12-19 13:54:47 +00:00
pragma Assert ( Is_Symbol ( Key ) ) ;
Arr := Find_In_Environment_List ( Interp . Self , Get_Car ( Interp . Environment ) , Key ) ;
if Arr = null then
-- Add a new key/value pair
-- TODO: make it GC-aware - protect Key and Value
Arr := Make_Array ( Interp . Self , 3 ) ;
Arr . Pointer_Slot ( 1 ) := Key ;
Arr . Pointer_Slot ( 2 ) := Value ;
-- Chain the pair to the head of the list
Arr . Pointer_Slot ( 3 ) := Get_Car ( Interp . Environment ) ;
Set_Car ( Interp . Environment , Arr ) ;
2013-12-17 16:04:55 +00:00
else
-- overwrite an existing pair
2013-12-19 13:54:47 +00:00
Arr . Pointer_Slot ( 2 ) := Value ;
2013-12-17 16:04:55 +00:00
end if ;
end Set_Environment ;
2013-12-19 13:54:47 +00:00
function Get_Environment ( Interp : access Interpreter_Record ;
Key : in Object_Pointer ) return Object_Pointer is
Envir : Object_Pointer ;
Arr : Object_Pointer ;
begin
Envir := Interp . Environment ;
while Envir / = Nil_Pointer loop
pragma Assert ( Is_Cons ( Envir ) ) ;
Arr := Find_In_Environment_List ( Interp , Get_Car ( Envir ) , Key ) ;
if Arr / = Nil_Pointer then
return Arr . Pointer_Slot ( 2 ) ;
end if ;
2013-12-17 16:04:55 +00:00
2013-12-19 13:54:47 +00:00
-- Move on to the parent environment
Envir := Get_Cdr ( Envir ) ;
end loop ;
return null ; -- not found
end Get_Environment ;
2013-12-10 16:14:06 +00:00
2013-12-19 13:54:47 +00:00
procedure Push_Environment ( Interp : in out Interpreter_Record ) is
pragma Inline ( Push_Environment ) ;
pragma Assert ( Is_Cons ( Interp . Environment ) ) ;
2013-12-10 16:14:06 +00:00
begin
2013-12-19 13:54:47 +00:00
Interp . Environment := Make_Environment ( Interp . Self , Interp . Environment ) ;
end Push_Environment ;
procedure Pop_Environment ( Interp : in out Interpreter_Record ) is
pragma Inline ( Pop_Environment ) ;
pragma Assert ( Is_Cons ( Interp . Environment ) ) ;
begin
Interp . Environment := Get_Cdr ( Interp . Environment ) ;
end Pop_Environment ;
----------------------------------------------------------------------------------
function Make_Syntax ( Interp : access Interpreter_Record ;
Opcode : in Syntax_Code ;
Name : in Object_String ) return Object_Pointer is
Result : Object_Pointer ;
begin
Result := Make_Symbol ( Interp , Name ) ;
2013-12-10 16:14:06 +00:00
Result . Flags := Result . Flags or Syntax_Object ;
2013-12-17 16:04:55 +00:00
Result . Scode := Opcode ;
2013-12-10 16:14:06 +00:00
Text_IO . Put ( "Creating Syntax Symbol " ) ;
Put_String ( To_Thin_String_Pointer ( Result ) ) ;
2013-12-19 13:54:47 +00:00
return Result ;
2013-12-10 16:14:06 +00:00
end Make_Syntax ;
2013-12-18 14:58:46 +00:00
function Is_Syntax ( Source : in Object_Pointer ) return Standard . Boolean is
pragma Inline ( Is_Syntax ) ;
begin
return Is_Symbol ( Source ) and then ( Source . Flags and Syntax_Object ) / = 0 ;
end Is_Syntax ;
2013-12-19 13:54:47 +00:00
function Make_Procedure ( Interp : access Interpreter_Record ;
Opcode : in Procedure _Code ;
Name : in Object_String ) return Object_Pointer is
2013-12-17 16:04:55 +00:00
-- this procedure is for internal use only
Symbol : Object_Pointer ;
Proc : Object_Pointer ;
2013-12-10 16:14:06 +00:00
begin
2013-12-17 16:04:55 +00:00
-- TODO: make temporaries GC-aware
-- Make a symbol for the procedure
2013-12-19 13:54:47 +00:00
Symbol := Make_Symbol ( Interp , Name ) ;
2013-12-17 16:04:55 +00:00
-- Make the actual procedure object
2013-12-19 13:54:47 +00:00
Proc := Allocate_Pointer_Object ( Interp , Procedure _Object_Size , Nil_Pointer ) ;
2013-12-17 16:04:55 +00:00
Proc . Tag := Procedure _Object ;
Proc . Pointer_Slot ( Procedure _Opcode_Index ) := Integer_To_Pointer ( Opcode ) ;
-- Link it to the top environement
2013-12-19 13:54:47 +00:00
pragma Assert ( Interp . Environment = Interp . Root_Environment ) ;
pragma Assert ( Get_Environment ( Interp . Self , Symbol ) = null ) ;
Set_Environment ( Interp . all , Symbol , Proc ) ;
2013-12-17 16:04:55 +00:00
2013-12-19 13:54:47 +00:00
return Proc ;
2013-12-10 16:14:06 +00:00
end Make_Procedure ;
2013-12-18 14:58:46 +00:00
function Is_Procedure ( Source : in Object_Pointer ) return Standard . Boolean is
pragma Inline ( Is_Procedure ) ;
begin
return Is_Normal_Pointer ( Source ) and then
Source . Tag = Procedure _Object ;
end Is_Procedure ;
function Get_Procedure_Opcode ( Proc : in Object_Pointer ) return Procedure _Code is
pragma Inline ( Get_Procedure_Opcode ) ;
pragma Assert ( Is_Procedure ( Proc ) ) ;
pragma Assert ( Proc . Size = Procedure _Object_Size ) ;
begin
return Pointer_To_Integer ( Proc . Pointer_Slot ( Procedure _Opcode_Index ) ) ;
end Get_Procedure_Opcode ;
2013-12-17 16:04:55 +00:00
----------------------------------------------------------------------------------
2013-12-19 13:54:47 +00:00
function Make_Frame ( Interp : access Interpreter_Record ;
Stack : in Object_Pointer ; -- current stack pointer
2013-12-10 16:14:06 +00:00
Opcode : in Object_Pointer ;
2013-12-17 16:04:55 +00:00
Operand : in Object_Pointer ;
Envir : in Object_Pointer ) return Object_Pointer is
Frame : Object_Pointer ;
2013-12-10 16:14:06 +00:00
begin
2013-12-19 13:54:47 +00:00
-- TODO: create a Frame in a special memory rather than in Heap Memory.
-- Since it's used for stack, it can be made special.
Frame := Allocate_Pointer_Object ( Interp , Frame_Object_Size , Nil_Pointer ) ;
Frame . Tag := Frame_Object ;
Frame . Pointer_Slot ( Frame_Stack_Index ) := Stack ;
Frame . Pointer_Slot ( Frame_Opcode_Index ) := Opcode ;
Frame . Pointer_Slot ( Frame_Operand_Index ) := Operand ;
Frame . Pointer_Slot ( Frame_Environment_Index ) := Envir ;
--Print_Object_Pointer ("Make_Frame Result - ", Result);
2013-12-17 16:04:55 +00:00
return Frame ;
2013-12-10 16:14:06 +00:00
end Make_Frame ;
2013-12-18 14:58:46 +00:00
function Is_Frame ( Source : in Object_Pointer ) return Standard . Boolean is
pragma Inline ( Is_Frame ) ;
begin
return Is_Normal_Pointer ( Source ) and then
Source . Tag = Frame_Object ;
end Is_Frame ;
2013-12-17 16:04:55 +00:00
function Get_Frame_Return ( Frame : in Object_Pointer ) return Object_Pointer is
pragma Inline ( Get_Frame_Return ) ;
pragma Assert ( Is_Frame ( Frame ) ) ;
2013-12-18 14:58:46 +00:00
begin
2013-12-17 16:04:55 +00:00
return Frame . Pointer_Slot ( Frame_Return_Index ) ;
end Get_Frame_Return ;
procedure Set_Frame_Return ( Frame : in out Object_Pointer ;
Value : in Object_Pointer ) is
pragma Inline ( Set_Frame_Return ) ;
pragma Assert ( Is_Frame ( Frame ) ) ;
2013-12-18 14:58:46 +00:00
begin
2013-12-17 16:04:55 +00:00
Frame . Pointer_Slot ( Frame_Return_Index ) := Value ;
end Set_Frame_Return ;
2013-12-18 14:58:46 +00:00
procedure Chain_Frame_Return ( Interp : in out Interpreter_Record ;
Frame : in out Object_Pointer ;
Value : in Object_Pointer ) is
pragma Inline ( Chain_Frame_Return ) ;
pragma Assert ( Is_Frame ( Frame ) ) ;
Cons : Object_Pointer renames Frame . Pointer_Slot ( Frame_Return_Index ) ;
begin
-- TODO: make it GC-aware
-- Add a new cons cell to the front
Cons := Make_Cons ( Interp . Self , Value , Cons ) ;
end Chain_Frame_Return ;
procedure Clear_Frame_Return ( Frame : in out Object_Pointer ) is
begin
Frame . Pointer_Slot ( Frame_Return_Index ) := Nil_Pointer ;
end Clear_Frame_Return ;
2013-12-17 16:04:55 +00:00
function Get_Frame_Environment ( Frame : in Object_Pointer ) return Object_Pointer is
pragma Inline ( Get_Frame_Environment ) ;
pragma Assert ( Is_Frame ( Frame ) ) ;
2013-12-18 14:58:46 +00:00
begin
2013-12-17 16:04:55 +00:00
return Frame . Pointer_Slot ( Frame_Environment_Index ) ;
end Get_Frame_Environment ;
function Get_Frame_Opcode ( Frame : in Object_Pointer ) return Opcode_Type is
pragma Inline ( Get_Frame_Opcode ) ;
pragma Assert ( Is_Frame ( Frame ) ) ;
2013-12-18 14:58:46 +00:00
begin
2013-12-17 16:04:55 +00:00
return Pointer_To_Integer ( Frame . Pointer_Slot ( Frame_Opcode_Index ) ) ;
end Get_Frame_Opcode ;
procedure Set_Frame_Opcode ( Frame : in Object_Pointer ;
OpcodE : in Opcode_Type ) is
pragma Inline ( Set_Frame_Opcode ) ;
pragma Assert ( Is_Frame ( Frame ) ) ;
2013-12-18 14:58:46 +00:00
begin
2013-12-17 16:04:55 +00:00
Frame . Pointer_Slot ( Frame_Opcode_Index ) := Integer_To_Pointer ( Opcode ) ;
end Set_Frame_Opcode ;
function Get_Frame_Operand ( Frame : in Object_Pointer ) return Object_Pointer is
pragma Inline ( Get_Frame_Operand ) ;
pragma Assert ( Is_Frame ( Frame ) ) ;
2013-12-18 14:58:46 +00:00
begin
2013-12-17 16:04:55 +00:00
return Frame . Pointer_Slot ( Frame_Operand_Index ) ;
end Get_Frame_Operand ;
procedure Set_Frame_Operand ( Frame : in out Object_Pointer ;
2013-12-18 14:58:46 +00:00
Value : in Object_Pointer ) is
2013-12-17 16:04:55 +00:00
pragma Inline ( Set_Frame_Operand ) ;
pragma Assert ( Is_Frame ( Frame ) ) ;
2013-12-18 14:58:46 +00:00
begin
2013-12-17 16:04:55 +00:00
Frame . Pointer_Slot ( Frame_Operand_Index ) := Value ;
end Set_Frame_Operand ;
----------------------------------------------------------------------------------
2013-12-18 14:58:46 +00:00
function Make_Mark ( Interp : access Interpreter_Record ;
Context : in Object_Integer ) return Object_Pointer is
Mark : Object_Pointer ;
begin
2013-12-19 13:54:47 +00:00
Mark := Allocate_Pointer_Object ( Interp , Mark_Object_Size , Nil_Pointer ) ;
Mark . Pointer_Slot ( Mark_Context_Index ) := Integer_To_Pointer ( Context ) ;
Mark . Tag := Mark_Object ;
2013-12-18 14:58:46 +00:00
return Mark ;
end Make_Mark ;
----------------------------------------------------------------------------------
2013-12-19 13:54:47 +00:00
function Make_Closure ( Interp : access Interpreter_Record ;
Code : in Object_Pointer ;
Envir : in Object_Pointer ) return Object_Pointer is
2013-12-17 16:04:55 +00:00
Closure : Object_Pointer ;
begin
2013-12-19 13:54:47 +00:00
Closure := Allocate_Pointer_Object ( Interp , Closure_Object_Size , Nil_Pointer ) ;
Closure . Tag := Closure_Object ;
Closure . Pointer_Slot ( Closure_Code_Index ) := Code ;
Closure . Pointer_Slot ( Closure_Environment_Index ) := Envir ;
2013-12-17 16:04:55 +00:00
return Closure ;
end Make_Closure ;
2013-12-19 13:54:47 +00:00
2013-12-18 14:58:46 +00:00
function Is_Closure ( Source : in Object_Pointer ) return Standard . Boolean is
pragma Inline ( Is_Closure ) ;
begin
return Is_Normal_Pointer ( Source ) and then
Source . Tag = Closure_Object ;
end Is_Closure ;
function Get_Closure_Code ( Closure : in Object_Pointer ) return Object_Pointer is
pragma Inline ( Get_Closure_Code ) ;
pragma Assert ( Is_Closure ( Closure ) ) ;
begin
return Closure . Pointer_Slot ( Closure_Code_Index ) ;
end Get_Closure_Code ;
function Get_Closure_Environment ( Closure : in Object_Pointer ) return Object_Pointer is
pragma Inline ( Get_Closure_Environment ) ;
pragma Assert ( Is_Closure ( Closure ) ) ;
begin
return Closure . Pointer_Slot ( Closure_Environment_Index ) ;
end Get_Closure_Environment ;
2013-12-10 16:14:06 +00:00
----------------------------------------------------------------------------------
procedure Deinitialize_Heap ( Interp : in out Interpreter_Record ) is
begin
for I in Interp . Heap ' Range loop
if Interp . Heap ( I ) / = null then
declare
subtype Target_Heap_Record is Heap_Record ( Interp . Heap ( I ) . Size ) ;
type Target_Heap_Pointer is access all Target_Heap_Record ;
package Pool is new H2.Pool ( Target_Heap_Record, Target_Heap_Pointer, Interp.Storage_Pool) ;
Heap : Target_Heap_Pointer ;
for Heap ' Address use Interp.Heap ( I ) ' Address ;
pragma Import ( Ada , Heap ) ;
begin
Pool . Deallocate ( Heap ) ;
end ;
end if ;
end loop ;
end Deinitialize_Heap ;
procedure Open ( Interp : in out Interpreter_Record ;
Initial_Heap_Size : in Memory_Size ;
Storage_Pool : in Storage_Pool_Pointer := null ) is
procedure Initialize_Heap ( Size : Memory_Size ) is
subtype Target_Heap_Record is Heap_Record ( Size ) ;
type Target_Heap_Pointer is access all Target_Heap_Record ;
package Pool is new H2.Pool ( Target_Heap_Record, Target_Heap_Pointer, Interp.Storage_Pool) ;
begin
for I in Interp . Heap ' Range loop
Interp . Heap ( I ) := null ; -- just in case
end loop ;
for I in Interp . Heap ' Range loop
declare
Heap : Target_Heap_Pointer ;
for Heap ' Address use Interp.Heap ( I ) ' Address ;
pragma Import ( Ada , Heap ) ;
begin
Heap := Pool . Allocate ;
end ;
end loop ;
exception
when others =>
Deinitialize_Heap ( Interp ) ;
raise ;
end Initialize_Heap ;
procedure Make_Syntax_Objects is
Dummy : Object_Pointer ;
begin
2013-12-19 13:54:47 +00:00
Dummy := Make_Syntax ( Interp . Self , And_Syntax , "and" ) ;
Dummy := Make_Syntax ( Interp . Self , Begin_Syntax , "begin" ) ;
Dummy := Make_Syntax ( Interp . Self , Case_Syntax , "case" ) ;
Dummy := Make_Syntax ( Interp . Self , Cond_Syntax , "cond" ) ;
Dummy := Make_Syntax ( Interp . Self , Define_Syntax , "define" ) ;
Dummy := Make_Syntax ( Interp . Self , If_Syntax , "if" ) ;
Dummy := Make_Syntax ( Interp . Self , Lambda_Syntax , "lambda" ) ;
Dummy := Make_Syntax ( Interp . Self , Let_Syntax , "let" ) ;
Dummy := Make_Syntax ( Interp . Self , Letast_Syntax , "let*" ) ;
Dummy := Make_Syntax ( Interp . Self , Letrec_Syntax , "letrec" ) ;
Dummy := Make_Syntax ( Interp . Self , Or_Syntax , "or" ) ;
Dummy := Make_Syntax ( Interp . Self , Quote_Syntax , "quote" ) ;
Dummy := Make_Syntax ( Interp . Self , Set_Syntax , "set!" ) ;
2013-12-10 16:14:06 +00:00
end Make_Syntax_Objects ;
2013-12-17 16:04:55 +00:00
procedure Make_Procedure_Objects is
Dummy : Object_Pointer ;
begin
2013-12-19 13:54:47 +00:00
Dummy := Make_Procedure ( Interp . Self , Car_Procedure , "car" ) ;
Dummy := Make_Procedure ( Interp . Self , Cdr_Procedure , "cdr" ) ;
Dummy := Make_Procedure ( Interp . Self , Setcar_Procedure , "setcar" ) ;
Dummy := Make_Procedure ( Interp . Self , Setcdr_Procedure , "setcdr" ) ;
Dummy := Make_Procedure ( Interp . Self , Add_Procedure , "+" ) ;
Dummy := Make_Procedure ( Interp . Self , Subtract_Procedure , "-" ) ;
Dummy := Make_Procedure ( Interp . Self , Multiply_Procedure , "*" ) ;
Dummy := Make_Procedure ( Interp . Self , Divide_Procedure , "/" ) ;
2013-12-17 16:04:55 +00:00
end Make_Procedure_Objects ;
2013-12-10 16:14:06 +00:00
begin
2013-12-11 15:40:57 +00:00
declare
Aliased_Interp : aliased Interpreter_Record ;
for Aliased_Interp ' Address use Interp ' Address ;
pragma Import ( Ada , Aliased_Interp ) ;
begin
-- Store a pointer to the interpreter record itself.
-- I use this pointer to call functions that accept the "access"
-- type to work around the ada95 limitation of no "in out" as
-- a function parameter. Accoring to Ada95 RM (6.2), both a
-- non-private limited record type and a private type whose
-- full type is a by-reference type are by-rereference types.
-- So i assume that it's safe to create this aliased overlay
-- to deceive the compiler. If Interpreter_Record is a tagged
-- limited record type, this overlay is not needed since the
-- type is considered aliased. Having this overlay, however,
-- should be safe for both "tagged" and "non-tagged".
-- Note: Making it a tagged limit record caused gnat 3.4.6 to
-- crash with an internal bug report.
--Interp.Self := Interp'Unchecked_Access; -- if tagged limited
Interp . Self := Aliased_Interp ' Unchecked_Access ;
end ;
2013-12-10 16:14:06 +00:00
Interp . Storage_Pool := Storage_Pool ;
Interp . Root_Table := Nil_Pointer ;
Interp . Symbol_Table := Nil_Pointer ;
2013-12-17 16:04:55 +00:00
Interp . Line_Pos := Interp . Line ' First - 1 ;
Interp . Line_Last := Interp . Line ' First - 1 ;
2013-12-10 16:14:06 +00:00
-- TODO: disallow garbage collecion during initialization.
Initialize_Heap ( Initial_Heap_Size ) ;
2013-12-18 14:58:46 +00:00
Interp . Mark := Make_Mark ( Interp . Self , 0 ) ; -- to indicate the end of cons evluation
2013-12-19 13:54:47 +00:00
Interp . Root_Environment := Make_Environment ( Interp . Self , Nil_Pointer ) ;
Interp . Environment := Interp . Root_Environment ;
2013-12-10 16:14:06 +00:00
Make_Syntax_Objects ;
2013-12-17 16:04:55 +00:00
Make_Procedure_Objects ;
2013-12-18 14:58:46 +00:00
2013-12-10 16:14:06 +00:00
exception
when others =>
Deinitialize_Heap ( Interp ) ;
end Open ;
procedure Close ( Interp : in out Interpreter_Record ) is
begin
Deinitialize_Heap ( Interp ) ;
end Close ;
procedure Set_Option ( Interp : in out Interpreter_Record ;
Option : in Option_Record ) is
begin
case Option . Kind is
2013-12-17 16:04:55 +00:00
when Trait_Option =>
2013-12-10 16:14:06 +00:00
Interp . Trait := Option ;
end case ;
end Set_Option ;
procedure Get_Option ( Interp : in out Interpreter_Record ;
Option : in out Option_Record ) is
begin
case Option . Kind is
2013-12-17 16:04:55 +00:00
when Trait_Option =>
2013-12-10 16:14:06 +00:00
Option := Interp . Trait ;
end case ;
end Get_Option ;
2013-12-17 16:04:55 +00:00
procedure Read ( Interp : in out Interpreter_Record ;
Result : out Object_Pointer ) is
EOF_Error : exception ;
function Get_Character return Object_Character is
begin
if Interp . Line_Pos > = Interp . Line_Last then
if Text_IO . End_Of_File then
raise EOF_Error ;
end if ;
Text_IO . Get_Line ( Interp . Line , Interp . Line_Last ) ;
Interp . Line_Pos := Interp . Line ' First - 1 ;
end if ;
Interp . Line_Pos := Interp . Line_Pos + 1 ;
return Interp . Line ( Interp . Line_Pos ) ;
end Get_Character ;
procedure Skip_Space is
begin
null ;
end Skip_Space ;
--function Get_Token is
--begin
-- null;
--end Get_Token;
procedure Read_Atom ( Atom : out Object_Pointer ) is
begin
null ;
end Read_Atom ;
Stack : Object_Pointer ;
Opcode : Object_Integer ;
Operand : Object_Pointer ;
begin
--Opcode := 1;
--loop
-- case Opcode is
-- when 1 =>
--end loop;
null ;
end Read ;
2013-12-10 16:14:06 +00:00
procedure Print ( Interp : in out Interpreter_Record ;
Source : in Object_Pointer ) is
procedure Print_Atom ( Atom : in Object_Pointer ) is
Ptr_Type : Object_Pointer_Type ;
procedure Print_Pointee is
W : Object_Word ;
for W ' Address use Atom ' Address ;
begin
case W is
2013-12-17 16:04:55 +00:00
when Nil_Word =>
Text_IO . Put ( "()" ) ;
2013-12-10 16:14:06 +00:00
2013-12-17 16:04:55 +00:00
when True_Word =>
Text_IO . Put ( "#t" ) ;
2013-12-10 16:14:06 +00:00
2013-12-17 16:04:55 +00:00
when False_Word =>
Text_IO . Put ( "#f" ) ;
2013-12-10 16:14:06 +00:00
2013-12-17 16:04:55 +00:00
when others =>
case Atom . Tag is
when Cons_Object =>
-- Cons_Object must not reach here.
raise Internal_Error ;
2013-12-10 16:14:06 +00:00
2013-12-17 16:04:55 +00:00
when Symbol_Object =>
Text_IO . Put ( To_String ( Atom . Character_Slot ) ) ;
2013-12-10 16:14:06 +00:00
2013-12-17 16:04:55 +00:00
when String_Object =>
Text_IO . Put ( "" "" ) ;
Text_IO . Put ( To_String ( Atom . Character_Slot ) ) ;
Text_IO . Put ( "" "" ) ;
2013-12-10 16:14:06 +00:00
2013-12-17 16:04:55 +00:00
when Continuation_Object =>
Text_IO . Put ( "#Continuation" ) ;
when Procedure _Object =>
Text_IO . Put ( "#Procedure" ) ;
2013-12-19 13:54:47 +00:00
when Array_Object =>
Text_IO . Put ( "#Array" ) ;
2013-12-17 16:04:55 +00:00
when Others =>
if Atom . Kind = Character_Object then
Text_IO . Put ( To_String ( Atom . Character_Slot ) ) ;
else
Text_IO . Put ( "#NOIMPL#" ) ;
end if ;
end case ;
2013-12-10 16:14:06 +00:00
end case ;
end Print_Pointee ;
procedure Print_Integer is
X : constant Object_Integer := Pointer_To_Integer ( Atom ) ;
begin
Text_IO . Put ( Object_Integer ' Image ( X ) ) ;
end Print_Integer ;
procedure Print_Character is
X : constant Object_Character := Pointer_To_Character ( Atom ) ;
begin
Text_IO . Put ( Object_Character ' Image ( X ) ) ;
end Print_Character ;
procedure Print_Byte is
X : constant Object_Byte := Pointer_To_Byte ( Atom ) ;
begin
Text_IO . Put ( Object_Byte ' Image ( X ) ) ;
end Print_Byte ;
begin
2013-12-17 16:04:55 +00:00
Ptr_Type := Get_Pointer_Type ( Atom ) ;
2013-12-10 16:14:06 +00:00
case Ptr_Type is
2013-12-17 16:04:55 +00:00
when Object_Pointer_Type_Pointer =>
Print_Pointee ;
2013-12-10 16:14:06 +00:00
2013-12-17 16:04:55 +00:00
when Object_Pointer_Type_Integer =>
Print_Integer ;
2013-12-10 16:14:06 +00:00
2013-12-17 16:04:55 +00:00
when Object_Pointer_Type_Character =>
Print_Character ;
2013-12-10 16:14:06 +00:00
2013-12-17 16:04:55 +00:00
when Object_Pointer_Type_Byte =>
Print_Byte ;
2013-12-10 16:14:06 +00:00
end case ;
end Print_Atom ;
procedure Print_Object ( Obj : in Object_Pointer ) is
Cons : Object_Pointer ;
Car : Object_Pointer ;
Cdr : Object_Pointer ;
begin
if Is_Cons ( Obj ) then
Cons := Obj ;
Text_IO . Put ( "(" ) ;
loop
2013-12-17 16:04:55 +00:00
Car := Get_Car ( Cons ) ;
2013-12-10 16:14:06 +00:00
if Is_Cons ( Car ) then
Print_Object ( Car ) ;
else
Print_Atom ( Car ) ;
end if ;
2013-12-17 16:04:55 +00:00
Cdr := Get_Cdr ( Cons ) ;
2013-12-10 16:14:06 +00:00
if Is_Cons ( Cdr ) then
Text_IO . Put ( " " ) ;
Cons := Cdr ;
exit when Cons = Nil_Pointer ;
else
if Cdr / = Nil_Pointer then
Text_IO . Put ( " . " ) ;
Print_Atom ( Cdr ) ;
end if ;
exit ;
end if ;
end loop ;
Text_IO . Put ( ")" ) ;
else
Print_Atom ( Obj ) ;
end if ;
end Print_Object ;
2013-12-17 16:04:55 +00:00
Stack : Object_Pointer ; -- TODO: make it into the interpreter_Record so that GC can workd
2013-12-10 16:14:06 +00:00
Opcode : Object_Integer ;
Operand : Object_Pointer ;
begin
-- TODO: Let Make_Frame use a dedicated stack space that's apart from the heap.
-- This way, the stack frame doesn't have to be managed by GC.
2013-12-19 13:54:47 +00:00
-- TODO: use a interp.Stack.
-- TODO: use Push_Frame
Stack := Make_Frame ( Interp . Self , Nil_Pointer , Integer_To_Pointer ( 0 ) , Nil_Pointer , Nil_Pointer ) ; -- just for get_frame_environment...
2013-12-17 16:04:55 +00:00
2013-12-10 16:14:06 +00:00
Opcode := 1 ;
Operand := Source ;
loop
case Opcode is
2013-12-17 16:04:55 +00:00
when 1 =>
if Is_Cons ( Operand ) then
-- push cdr
2013-12-19 13:54:47 +00:00
Stack := Make_Frame ( Interp . Self , Stack , Integer_To_Pointer ( 2 ) , Get_Cdr ( Operand ) , Nil_Pointer ) ; -- push cdr
2013-12-17 16:04:55 +00:00
Text_IO . Put ( "(" ) ;
Operand := Get_Car ( Operand ) ;
Opcode := 1 ;
else
Print_Atom ( Operand ) ;
if Stack = Nil_Pointer then
Opcode := 0 ; -- stack empty. arrange to exit
Operand := True_Pointer ; -- return value
2013-12-10 16:14:06 +00:00
else
2013-12-17 16:04:55 +00:00
Opcode := Pointer_To_Integer ( Stack . Pointer_Slot ( Frame_Opcode_Index ) ) ;
Operand := Stack . Pointer_Slot ( Frame_Operand_Index ) ;
Stack := Stack . Pointer_Slot ( Frame_Stack_Index ) ; -- pop
2013-12-10 16:14:06 +00:00
end if ;
2013-12-17 16:04:55 +00:00
end if ;
2013-12-10 16:14:06 +00:00
2013-12-17 16:04:55 +00:00
when 2 =>
if Is_Cons ( Operand ) then
-- push cdr
2013-12-19 13:54:47 +00:00
Stack := Make_Frame ( Interp . Self , Stack , Integer_To_Pointer ( 2 ) , Get_Cdr ( Operand ) , Nil_Pointer ) ; -- push
2013-12-17 16:04:55 +00:00
Text_IO . Put ( " " ) ;
Operand := Get_Car ( Operand ) ; -- car
Opcode := 1 ;
else
if Operand / = Nil_Pointer then
-- cdr of the last cons cell is not null.
Text_IO . Put ( " . " ) ;
Print_Atom ( Operand ) ;
end if ;
Text_IO . Put ( ")" ) ;
2013-12-10 16:14:06 +00:00
2013-12-17 16:04:55 +00:00
if Stack = Nil_Pointer then
Opcode := 0 ; -- stack empty. arrange to exit
2013-12-10 16:14:06 +00:00
else
2013-12-17 16:04:55 +00:00
Opcode := Pointer_To_Integer ( Stack . Pointer_Slot ( Frame_Opcode_Index ) ) ;
Operand := Stack . Pointer_Slot ( Frame_Operand_Index ) ;
Stack := Stack . Pointer_Slot ( Frame_Stack_Index ) ; -- pop
2013-12-10 16:14:06 +00:00
end if ;
2013-12-17 16:04:55 +00:00
end if ;
2013-12-10 16:14:06 +00:00
2013-12-17 16:04:55 +00:00
when others =>
exit ;
2013-12-10 16:14:06 +00:00
end case ;
end loop ;
--Print_Object (Source);
Text_IO . New_Line ;
end Print ;
2013-12-17 16:04:55 +00:00
procedure Evaluatex ( Interp : in out Interpreter_Record ) is
2013-12-10 16:14:06 +00:00
X : Object_Pointer ;
begin
--Make_Cons (Interpreter, Nil_Pointer, Nil_Pointer, X);
--Make_Cons (Interpreter, Nil_Pointer, X, X);
--Make_Cons (Interpreter, Nil_Pointer, X, X);
--Make_Cons (Interpreter, Nil_Pointer, X, X);
2013-12-19 13:54:47 +00:00
Interp . Root_Table := Make_Symbol ( Interp . Self , "lambda" ) ;
2013-12-10 16:14:06 +00:00
--Print_Object_Pointer (">>> Root_Table ...", Interp.Root_Table);
Collect_Garbage ( Interp ) ;
2013-12-11 15:40:57 +00:00
-- (define x 10)
2013-12-10 16:14:06 +00:00
2013-12-11 15:40:57 +00:00
X := Make_Cons (
Interp . Self ,
Make_Symbol ( Interp . Self , "define" ) ,
Make_Cons (
Interp . Self ,
Make_Symbol ( Interp . Self , "x" ) ,
2013-12-10 16:14:06 +00:00
Make_Cons (
2013-12-11 15:40:57 +00:00
Interp . Self ,
Integer_To_Pointer ( 10 ) ,
--Nil_Pointer
Integer_To_Pointer ( 10 )
2013-12-10 16:14:06 +00:00
)
2013-12-11 15:40:57 +00:00
)
) ;
X := Make_Cons ( Interp . Self , X , Make_Cons ( Interp . Self , X , Integer_To_Pointer ( 10 ) ) ) ;
--X := Make_Cons (Interp.Self, Nil_Pointer, Make_Cons (Interp.Self, Nil_Pointer, Integer_To_Pointer(TEN)));
--X := Make_Cons (Interp.Self, Nil_Pointer, Nil_Pointer);
2013-12-17 16:04:55 +00:00
Read ( Interp , X ) ;
2013-12-11 15:40:57 +00:00
Print ( Interp , X ) ;
2013-12-10 16:14:06 +00:00
2013-12-17 16:04:55 +00:00
end Evaluatex ;
procedure Make_Test_Object ( Interp : in out Interpreter_Record ; Result : out Object_Pointer ) is
2013-12-18 14:58:46 +00:00
Y : Object_Pointer ;
Z : Object_Pointer ;
2013-12-17 16:04:55 +00:00
begin
--(define x 10)
--Result := Make_Cons (
-- Interp.Self,
-- Make_Symbol (Interp.Self, "define"),
-- Make_Cons (
-- Interp.Self,
-- Make_Symbol (Interp.Self, "x"),
-- Make_Cons (
-- Interp.Self,
-- Integer_To_Pointer (10),
-- --Nil_Pointer
-- Integer_To_Pointer (10)
-- )
-- )
--);
2013-12-18 14:58:46 +00:00
Z := Make_Cons (
Interp . Self ,
Make_Symbol ( Interp . Self , "+" ) ,
Make_Cons (
Interp . Self ,
Integer_To_Pointer ( 3 ) ,
Make_Cons (
Interp . Self ,
Integer_To_Pointer ( 9 ) ,
Nil_Pointer
)
)
) ;
Y := Make_Cons (
Interp . Self ,
Make_Symbol ( Interp . Self , "+" ) ,
Make_Cons (
Interp . Self ,
Integer_To_Pointer ( 100 ) ,
Make_Cons (
Interp . Self ,
Z ,
Nil_Pointer
)
)
) ;
2013-12-17 16:04:55 +00:00
Result := Make_Cons (
Interp . Self ,
Make_Symbol ( Interp . Self , "+" ) ,
Make_Cons (
Interp . Self ,
2013-12-18 14:58:46 +00:00
--Integer_To_Pointer (10),
Y ,
2013-12-17 16:04:55 +00:00
Make_Cons (
Interp . Self ,
2013-12-18 14:58:46 +00:00
Integer_To_Pointer ( - 5 ) ,
Make_Cons (
Interp . Self ,
Y ,
Integer_To_Pointer ( 20 )
)
2013-12-17 16:04:55 +00:00
)
)
) ;
2013-12-19 13:54:47 +00:00
2013-12-19 14:36:14 +00:00
Z := Make_Cons (
Interp . Self ,
Make_Symbol ( Interp . Self , "begin" ) ,
Y
) ;
2013-12-19 13:54:47 +00:00
2013-12-19 14:36:14 +00:00
Result := Make_Cons (
Interp . Self ,
Make_Symbol ( Interp . Self , "begin" ) ,
Make_Cons ( Interp . Self , Z , Nil_Pointer )
) ;
2013-12-19 13:54:47 +00:00
Text_IO . PUt ( "TEST OBJECT: " ) ;
Print ( Interp , Result ) ;
2013-12-17 16:04:55 +00:00
end Make_Test_Object ;
function Pointer_To_Opcode ( Pointer : in Object_Pointer ) return Opcode_Type is
pragma Inline ( Pointer_To_Opcode ) ;
begin
return Pointer_To_Integer ( Pointer ) ;
end Pointer_To_Opcode ;
function Opcode_To_Pointer ( Opcode : in Opcode_Type ) return Object_Pointer is
pragma Inline ( Opcode_To_Pointer ) ;
begin
return Integer_To_Pointer ( Opcode ) ;
end Opcode_To_Pointer ;
procedure Evaluate ( Interp : in out Interpreter_Record ;
Source : in Object_Pointer ;
Result : out Object_Pointer ) is
2013-12-19 13:54:47 +00:00
procedure Push_Frame ( Opcode : in Opcode_Type ;
Operand : in Object_Pointer ) is
2013-12-17 16:04:55 +00:00
pragma Inline ( Push_Frame ) ;
begin
2013-12-19 13:54:47 +00:00
Interp . Stack := Make_Frame ( Interp . Self , Interp . Stack , Opcode_To_Pointer ( Opcode ) , Operand , Interp . Environment ) ;
2013-12-17 16:04:55 +00:00
end Push_Frame ;
2013-12-19 13:54:47 +00:00
--procedure Pop_Frame (Interp.Stack: out Object_Pointer;
2013-12-17 16:04:55 +00:00
-- Opcode: out Opcode_Type;
-- Operand: out Object_Pointer) is
-- pragma Inline (Pop_Frame);
--begin
2013-12-19 13:54:47 +00:00
-- pragma Assert (Interp.Stack /= Nil_Pointer);
-- Opcode := Pointer_To_Opcode(Interp.Stack.Pointer_Slot(Frame_Opcode_Index));
-- Operand := Interp.Stack.Pointer_Slot(Frame_Operand_Index);
-- Interp.Stack := Interp.Stack.Pointer_Slot(Frame_Stack_Index); -- pop
2013-12-17 16:04:55 +00:00
--end Pop_Frame;
2013-12-19 13:54:47 +00:00
procedure Pop_Frame is
2013-12-17 16:04:55 +00:00
pragma Inline ( Pop_Frame ) ;
begin
2013-12-19 13:54:47 +00:00
pragma Assert ( Interp . Stack / = Nil_Pointer ) ;
Interp . Environment := Interp . Stack . Pointer_Slot ( Frame_Environment_Index ) ; -- restore environment
Interp . Stack := Interp . Stack . Pointer_Slot ( Frame_Stack_Index ) ; -- pop
2013-12-17 16:04:55 +00:00
end Pop_Frame ;
2013-12-19 13:54:47 +00:00
procedure Evaluate_Group is
pragma Inline ( Evaluate_Group ) ;
2013-12-17 16:04:55 +00:00
Operand : Object_Pointer ;
2013-12-19 13:54:47 +00:00
Car : Object_Pointer ;
Cdr : Object_Pointer ;
begin
Operand := Get_Frame_Operand ( Interp . Stack ) ;
pragma Assert ( Is_Normal_Pointer ( Operand ) ) ;
case Operand . Tag is
when Cons_Object =>
Car := Get_Car ( Operand ) ;
Cdr := Get_Cdr ( Operand ) ;
if Is_Cons ( Cdr ) then
-- Let the current frame remember the next expression list
Set_Frame_Operand ( Interp . Stack , Cdr ) ;
else
if Cdr / = Nil_Pointer then
-- The last CDR is not Nil.
Text_IO . Put_Line ( "$$$$..................FUCKING CDR. FOR GROUP....................$$$$" ) ;
-- raise Syntax_Error;
end if ;
Set_Frame_Operand ( Interp . Stack , Interp . Mark ) ;
end if ;
-- Clear the return value from the previous expression.
Clear_Frame_Return ( Interp . Stack ) ;
-- Arrange to evaluate the current expression
Push_Frame ( Opcode_Evaluate_Object , Car ) ;
when Mark_Object =>
Operand := Get_Frame_Return ( Interp . Stack ) ;
Pop_Frame ; -- Done;
Set_Frame_Return ( Interp . Stack , Operand ) ;
when others =>
raise Internal_Error ;
end case ;
end Evaluate_Group ;
procedure Evaluate_Object is
pragma Inline ( Evaluate_Object ) ;
2013-12-17 16:04:55 +00:00
2013-12-19 13:54:47 +00:00
Operand : Object_Pointer ;
Car : Object_Pointer ;
Cdr : Object_Pointer ;
2013-12-17 16:04:55 +00:00
begin
2013-12-18 14:58:46 +00:00
<<Start_Over>>
2013-12-19 13:54:47 +00:00
Operand := Get_Frame_Operand ( Interp . Stack ) ;
2013-12-17 16:04:55 +00:00
2013-12-19 13:54:47 +00:00
if not Is_Normal_Pointer ( Operand ) then
-- integer, character, specal pointers
-- TODO: some normal pointers may point to literal objects. e.g.) bignum
2013-12-17 16:04:55 +00:00
goto Literal ;
end if ;
2013-12-19 13:54:47 +00:00
case Operand . Tag is
when Symbol_Object => -- Is_Symbol(Operand)
-- TODO: find it in the Environment hierarchy.. not in the current environemnt.
Car := Get_Environment ( Interp . Self , Operand ) ;
if Car = null then
-- unbound
Text_IO . Put_Line ( "Unbound symbol...." ) ;
raise Evaluation_Error ;
else
-- symbol found in the environment
Operand := Car ;
goto Literal ; -- In fact, this is not a literal, but can be handled in the same way
end if ;
2013-12-17 16:04:55 +00:00
2013-12-19 13:54:47 +00:00
when Cons_Object => -- Is_Cons(Operand)
Car := Get_Car ( Operand ) ;
Cdr := Get_Cdr ( Operand ) ;
if Is_Syntax ( Car ) then
-- special syntax symbol. normal evaluate rule doesn't
-- apply for special syntax objects.
case Car . Scode is
when Begin_Syntax =>
2013-12-19 14:36:14 +00:00
Operand := Cdr ; -- Skip begin
2013-12-19 13:54:47 +00:00
if Operand = Nil_Pointer then
-- 'begin' is followed by nothing. i.e. (begin)
Text_IO . Put_LINE ( "NO EXPRESSIONS FOR BEGIN" ) ;
-- TODO: should i raise Syntax_Error? if so, i can combile this with the next elsif block
Pop_Frame ; -- Done
elsif not Is_Cons ( Operand ) then
-- 'begin' is in the last cons cell and the cdr field
-- is not nil.
-- e.g) (begin . 10)
Text_IO . Put_LINE ( "FUCKNING CDR FOR BEGIN" ) ;
-- TODO: raise Syntax_Error
Pop_Frame ; -- Done
else
Set_Frame_Opcode ( Interp . Stack , Opcode_Evaluate_Group ) ;
Set_Frame_Operand ( Interp . Stack , Operand ) ;
2013-12-19 14:42:14 +00:00
if ( Interp . Trait . Trait_Bits and No_Optimization ) = 0 then
-- I call Evaluate_Group for optimization here.
Evaluate_Group ; -- for optimization only. not really needed.
-- I can jump to Start_Over because Evaluate_Group called
-- above pushes an Opcode_Evaluate_Object frame.
pragma Assert ( Get_Frame_Opcode ( Interp . Stack ) = Opcode_Evaluate_Object ) ;
goto Start_Over ; -- for optimization only. not really needed.
end if ;
2013-12-19 13:54:47 +00:00
end if ;
when Define_Syntax =>
Text_IO . Put_Line ( "define syntax" ) ;
Set_Frame_Opcode ( Interp . Stack , Opcode_Evaluate_Syntax ) ; -- switch to syntax evaluation
when others =>
Text_IO . Put_Line ( "Unknown syntax" ) ;
Set_Frame_Opcode ( Interp . Stack , Opcode_Evaluate_Syntax ) ; -- switch to syntax evaluation
end case ;
else
2013-12-19 14:42:14 +00:00
if ( Interp . Trait . Trait_Bits and No_Optimization ) = 0 then
while not Is_Normal_Pointer ( Car ) loop
-- This while block is for optimization only. It's not really needed.
-- If I know that the next object to evaluate is a literal object,
-- I can simply reverse-chain it to the return field of the current
-- frame without pushing another frame dedicated for it.
-- TODO: some normal pointers may point to a literal object. e.g.) bignum
Chain_Frame_Return ( Interp , Interp . Stack , Car ) ;
if Is_Cons ( Cdr ) then
Operand := Cdr ;
Car := Get_Car ( Operand ) ;
Cdr := Get_Cdr ( Operand ) ;
else
-- last cons
Operand := Reverse_Cons ( Get_Frame_Return ( Interp . Stack ) ) ;
Clear_Frame_Return ( Interp . Stack ) ;
Set_Frame_Opcode ( Interp . Stack , Opcode_Apply ) ;
Set_Frame_Operand ( Interp . Stack , Operand ) ;
return ;
end if ;
end loop ;
end if ;
2013-12-10 16:14:06 +00:00
2013-12-19 13:54:47 +00:00
if Is_Cons ( Cdr ) then
-- Not the last cons cell yet
Set_Frame_Operand ( Interp . Stack , Cdr ) ; -- change the operand for the next call
else
-- Reached the last cons cell
if Cdr / = Nil_Pointer then
-- The last CDR is not Nil.
Text_IO . Put_Line ( "$$$$..................FUCKING CDR.....................$$$$" ) ;
-- raise Syntax_Error;
2013-12-17 16:04:55 +00:00
end if ;
2013-12-19 13:54:47 +00:00
-- Change the operand to a mark object so that the call to this
-- procedure after the evaluation of the last car goes to the
-- Mark_Object case.
Set_Frame_Operand ( Interp . Stack , Interp . Mark ) ;
end if ;
2013-12-18 14:58:46 +00:00
2013-12-19 13:54:47 +00:00
-- Arrange to evaluate the car object
2013-12-19 14:42:14 +00:00
if ( Interp . Trait . Trait_Bits and No_Optimization ) = 0 then
Push_Frame ( Opcode_Evaluate_Object , Car ) ;
goto Start_Over ; -- for optimization only. not really needed.
end if ;
2013-12-19 13:54:47 +00:00
end if ;
2013-12-18 14:58:46 +00:00
2013-12-19 13:54:47 +00:00
when Mark_Object =>
-- TODO: you can use the mark context to differentiate context
2013-12-18 14:58:46 +00:00
2013-12-19 13:54:47 +00:00
-- Get the evaluation result stored in the current stack frame by
-- various sub-Opcode_Evaluate_Object frames. the return value
-- chain must be reversed Chain_Frame_Return reverse-chains values.
Operand := Reverse_Cons ( Get_Frame_Return ( Interp . Stack ) ) ;
-- Refresh the current stack frame to Opcode_Apply.
-- This should be faster than Popping the current frame and pushing
-- a new frame.
-- Envir := Get_Frame_Environment(Interp.Stack);
-- Pop_Frame (Interp.Stack); -- done
-- Push_Frame (Interp.Stack, Opcode_Apply, Operand, Envir);
Clear_Frame_Return ( Interp . Stack ) ;
Set_Frame_Opcode ( Interp . Stack , Opcode_Apply ) ;
Set_Frame_Operand ( Interp . Stack , Operand ) ;
2013-12-17 16:04:55 +00:00
2013-12-19 13:54:47 +00:00
when others =>
-- normal literal object
goto Literal ;
end case ;
2013-12-17 16:04:55 +00:00
return ;
<<Literal>>
2013-12-19 13:54:47 +00:00
Pop_Frame ; -- done
2013-12-18 14:58:46 +00:00
Text_IO . Put ( "Return => " ) ;
Print ( Interp , Operand ) ;
2013-12-19 13:54:47 +00:00
Chain_Frame_Return ( Interp , Interp . Stack , Operand ) ;
2013-12-17 16:04:55 +00:00
end Evaluate_Object ;
2013-12-19 13:54:47 +00:00
procedure Evaluate_Syntax is
pragma Inline ( Evaluate_Syntax ) ;
2013-12-17 16:04:55 +00:00
Scode : Syntax_Code ;
begin
2013-12-19 13:54:47 +00:00
Scode := Get_Car ( Get_Frame_Operand ( Interp . Stack ) ) . Scode ;
2013-12-17 16:04:55 +00:00
case Scode is
2013-12-19 13:54:47 +00:00
when Begin_Syntax =>
null ;
2013-12-17 16:04:55 +00:00
when Define_Syntax =>
Text_IO . Put_Line ( "define syntax" ) ;
when others =>
Text_IO . Put_Line ( "Unknown syntax" ) ;
end case ;
end Evaluate_Syntax ;
2013-12-19 13:54:47 +00:00
procedure Evaluate_Procedure is
pragma Inline ( Evaluate_Procedure ) ;
2013-12-17 16:04:55 +00:00
begin
null ;
end Evaluate_Procedure ;
2013-12-19 13:54:47 +00:00
procedure Apply is
pragma Inline ( Apply ) ;
2013-12-18 14:58:46 +00:00
Operand : Object_Pointer ;
Func : Object_Pointer ;
Args : Object_Pointer ;
procedure Apply_Car_Procedure is
begin
2013-12-19 13:54:47 +00:00
Pop_Frame ; -- Done with the current frame
Chain_Frame_Return ( Interp , Interp . Stack , Get_Car ( Args ) ) ;
2013-12-18 14:58:46 +00:00
end Apply_Car_Procedure ;
procedure Apply_Cdr_Procedure is
begin
2013-12-19 13:54:47 +00:00
Pop_Frame ; -- Done with the current frame
Chain_Frame_Return ( Interp , Interp . Stack , Get_Cdr ( Args ) ) ;
2013-12-18 14:58:46 +00:00
end Apply_Cdr_Procedure ;
procedure Apply_Add_Procedure is
Ptr : Object_Pointer := Args ;
Num : Object_Integer := 0 ; -- TODO: support BIGNUM
Car : Object_Pointer ;
begin
while Ptr / = Nil_Pointer loop
-- TODO: check if car is an integer or bignum or something else.
-- if something else, error
Car := Get_Car ( Ptr ) ;
if not Is_Integer ( Car ) then
raise Evaluation_Error ;
end if ;
Num := Num + Pointer_To_Integer ( Car ) ;
Ptr := Get_Cdr ( Ptr ) ;
end loop ;
2013-12-19 13:54:47 +00:00
Pop_Frame ; -- Done with the current frame
Chain_Frame_Return ( Interp , Interp . Stack , Integer_To_Pointer ( Num ) ) ;
2013-12-18 14:58:46 +00:00
end Apply_Add_Procedure ;
procedure Apply_Subtract_Procedure is
Ptr : Object_Pointer := Args ;
Num : Object_Integer := 0 ; -- TODO: support BIGNUM
Car : Object_Pointer ;
begin
if Ptr / = Nil_Pointer then
Car := Get_Car ( Ptr ) ;
if not Is_Integer ( Car ) then
raise Evaluation_Error ;
end if ;
Num := Pointer_To_Integer ( Car ) ;
while Ptr / = Nil_Pointer loop
-- TODO: check if car is an integer or bignum or something else.
-- if something else, error
Car := Get_Car ( Ptr ) ;
if not Is_Integer ( Car ) then
raise Evaluation_Error ;
end if ;
Num := Num - Pointer_To_Integer ( Car ) ;
Ptr := Get_Cdr ( Ptr ) ;
end loop ;
end if ;
2013-12-19 13:54:47 +00:00
Pop_Frame ; -- Done with the current frame
Chain_Frame_Return ( Interp , Interp . Stack , Integer_To_Pointer ( Num ) ) ;
2013-12-18 14:58:46 +00:00
end Apply_Subtract_Procedure ;
procedure Apply_Closure is
Envir : Object_Pointer ;
Param : Object_Pointer ;
Arg : Object_Pointer ;
begin
-- For a closure created of "(lambda (x y) (+ x y) (* x y))"
-- Get_Closure_Code(Func) returns "((x y) (+ x y) (* x y))"
Envir := Make_Cons ( Interp . Self , Nil_Pointer , Get_Closure_Environment ( Func ) ) ;
Param := Get_Car ( Get_Closure_Code ( Func ) ) ; -- parameter list
Arg := Get_Car ( Args ) ;
while Is_Cons ( Param ) loop
-- Insert the parameter name/value pair into the environment
--Set_Car (Envir, Make_Cons (Interp.Self,
Param := Get_Cdr ( Param ) ;
Arg := Get_Cdr ( Arg ) ;
end loop ;
--Push_Frame (....);
end Apply_Closure ;
2013-12-17 16:04:55 +00:00
begin
2013-12-19 13:54:47 +00:00
Operand := Get_Frame_Operand ( Interp . Stack ) ;
2013-12-18 14:58:46 +00:00
pragma Assert ( Is_Cons ( Operand ) ) ;
Print ( Interp , Operand ) ;
Func := Get_Car ( Operand ) ;
if not Is_Normal_Pointer ( Func ) then
Text_IO . Put_Line ( "INVALID FUNCTION TYPE" ) ;
raise Evaluation_Error ;
end if ;
Args := Get_Cdr ( Operand ) ;
-- No GC must be performed here.
-- Otherwise, Operand, Func, Args get invalidated
-- since GC doesn't update local variables.
case Func . Tag is
when Procedure _Object =>
case Get_Procedure_Opcode ( Func ) is
when Car_Procedure =>
Apply_Car_Procedure ;
when Cdr_Procedure =>
Apply_Cdr_Procedure ;
when Add_Procedure =>
Apply_Add_Procedure ;
when Subtract_Procedure =>
Apply_Subtract_Procedure ;
when others =>
raise Internal_Error ;
end case ;
when Closure_Object =>
Apply_Closure ;
when Continuation_Object =>
null ;
when others =>
Text_IO . Put_Line ( "INVALID FUNCTION TYPE" ) ;
raise Internal_Error ;
end case ;
2013-12-17 16:04:55 +00:00
end Apply ;
begin
2013-12-19 13:54:47 +00:00
-- Stack frames looks like this upon initialization
--
-- | Opcode | Operand | Return
-- -----------------------------------------------------------------
-- top | Opcode_Evaluate_Object | Source | Nil
-- bottom | Opcode_Exit | Nil | Nil
--
-- For a source (+ 1 2), it should look like this.
-- -----------------------------------------------------------------
-- top | Opcode_Evaluate_Object | Source | Nil
-- bottom | Opcode_Exit | Nil | Nil
--
-- The operand changes to the cdr of the source.
-- The symbol '+' is pushed to the stack with Opcode_Evaluate_Object.
-- -----------------------------------------------------------------
-- top | Opcode_Evaluate_Object | + | Nil
-- | Opcode_Evaluate_Object | (1 2) | Nil
-- bottom | Opcode_Exit | Nil | Nil
--
-- After the evaluation of the symbol, the pushed frame is removed
-- and the result is set to the return field.
-- -----------------------------------------------------------------
-- top | Opcode_Evaluate_Object | (1 2) | (#Proc+)
-- bottom | Opcode_Exit | Nil | Nil
--
-- The same action is taken to evaluate the literal 1.
-- -----------------------------------------------------------------
-- top | Opcode_Evaluate_Object | 1 | Nil
-- | Opcode_Evaluate_Object | (2) | (#Proc+)
-- bottom | Opcode_Exit | Nil | Nil
--
-- The result of the valuation is reverse-chained to the return field.
-- -----------------------------------------------------------------
-- top | Opcode_Evaluate_Object | (2) | (1 #Proc+)
-- bottom | Opcode_Exit | Nil | Nil
--
-- The same action is taken to evaluate the literal 2.
-- -----------------------------------------------------------------
-- top | Opcode_Evaluate_Object | 2 | Nil
-- | Opcode_Evaluate_Object | Mark | (1 #Proc+)
-- bottom | Opcode_Exit | Nil | Nil
--
-- The result of the valuation is reverse-chained to the return field.
-- -----------------------------------------------------------------
-- top | Opcode_Evaluate_Object | Mark | (2 1 #Proc+)
-- bottom | Opcode_Exit | Nil | Nil
--
-- Once evluation of each cons cell is complete, switch the top frame
-- to 'Apply' reversing the result field into the operand field and
-- nullifying the result field afterwards.
-- -----------------------------------------------------------------
-- top | Apply | (#Proc+ 1 2) | Nil
-- bottom | Opcode_Exit | Nil | Nil
--
-- The apply operation produces the final result and sets it to the
-- parent frame while removing the apply frame.
-- -----------------------------------------------------------------
-- top/bottom| Opcode_Exit | Nil | 3
Interp . Stack := Nil_Pointer ;
2013-12-17 16:04:55 +00:00
-- Push a pseudo-frame to terminate the evaluation loop
2013-12-19 13:54:47 +00:00
Push_Frame ( Opcode_Exit , Nil_Pointer ) ;
2013-12-17 16:04:55 +00:00
-- Push the actual frame for evaluation
2013-12-19 13:54:47 +00:00
Push_Frame ( Opcode_Evaluate_Object , Source ) ;
2013-12-17 16:04:55 +00:00
loop
2013-12-19 13:54:47 +00:00
case Get_Frame_Opcode ( Interp . Stack ) is
2013-12-17 16:04:55 +00:00
when Opcode_Evaluate_Object =>
2013-12-19 13:54:47 +00:00
Evaluate_Object ;
when Opcode_Evaluate_Group =>
Evaluate_Group ;
2013-12-17 16:04:55 +00:00
when Opcode_Evaluate_Syntax =>
2013-12-19 13:54:47 +00:00
Evaluate_Syntax ;
2013-12-17 16:04:55 +00:00
when Opcode_Evaluate_Procedure =>
2013-12-19 13:54:47 +00:00
Evaluate_Procedure ;
2013-12-17 16:04:55 +00:00
when Opcode_Apply =>
2013-12-19 13:54:47 +00:00
Apply ;
2013-12-17 16:04:55 +00:00
when Opcode_Exit =>
2013-12-19 13:54:47 +00:00
Result := Get_Frame_Return ( Interp . Stack ) ;
Pop_Frame ;
2013-12-17 16:04:55 +00:00
exit ;
end case ;
end loop ;
-- the stack must be empty when the loop is terminated
2013-12-19 13:54:47 +00:00
pragma Assert ( Interp . Stack = Nil_Pointer ) ;
2013-12-17 16:04:55 +00:00
end Evaluate ;
2013-12-10 16:14:06 +00:00
2013-12-19 14:36:14 +00:00
----------------------------------------------------------------------------------
function h2scm_open return Interpreter_Pointer ;
pragma Export ( C , h2scm_open , "h2scm_open" ) ;
procedure h2scm_close ( Interp : in out Interpreter_Pointer ) ;
pragma Export ( C , h2scm_close , "h2scm_close" ) ;
function h2scm_evaluate ( Interp : access Interpreter_Record ;
Source : in Object_Pointer ) return Interfaces . C . int ;
pragma Export ( C , h2scm_evaluate , "h2scm_evaluate" ) ;
procedure h2scm_dealloc is new
Ada . Unchecked_Deallocation ( Interpreter_Record , Interpreter_Pointer ) ;
function h2scm_open return Interpreter_Pointer is
Interp : Interpreter_Pointer ;
begin
begin
Interp := new Interpreter_Record ;
exception
when others =>
return null ;
end ;
begin
Open ( Interp . all , 1_000_000 , null ) ;
exception
when others =>
h2scm_dealloc ( Interp ) ;
return null ;
end ;
return Interp ;
end h2scm_open ;
procedure h2scm_close ( Interp : in out Interpreter_Pointer ) is
begin
Text_IO . Put_Line ( "h2scm_close" ) ;
Close ( Interp . all ) ;
h2scm_dealloc ( Interp ) ;
end h2scm_close ;
function h2scm_evaluate ( Interp : access Interpreter_Record ;
Source : in Object_Pointer ) return Interfaces . C . int is
begin
return Interfaces . C . int ( Interp . Heap ( Interp . Current_Heap ) . Size ) ;
end h2scm_evaluate ;
2013-12-10 16:14:06 +00:00
end H2.Scheme ;
2013-12-17 16:04:55 +00:00