2014-01-09 15:32:36 +00:00
with H2.Ascii ;
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 ;
2014-01-01 14:07:03 +00:00
-- XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXx
with Ada.Characters.Handling ;
with Ada.Wide_Characters.Handling ;
-- TODO: delete these after debugging
with ada.text_io ;
with ada.wide_text_io ;
-- TODO: delete above after debugging
-- XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXx
2013-12-10 16:14:06 +00:00
package body H2.Scheme is
2014-01-09 15:32:36 +00:00
package body Token is separate ;
package Ch is new Ascii ( Object_Character) ;
-----------------------------------------------------------------------------
-- PRIMITIVE DEFINITIONS
-----------------------------------------------------------------------------
-- I define these constants to word around the limitation of not being
-- able to use a string literal when the string type is a generic parameter.
-- Why doesn't ada include a formal type support for different character
-- and string types? This limitation is caused because the generic
-- type I chosed to use to represent a character type is a discrete type.
Label_And : constant Object_String := ( Ch . LC_A , Ch . LC_N , Ch . LC_D ) ; -- "and"
Label_Begin : constant Object_String := ( Ch . LC_B , Ch . LC_E , Ch . LC_G , Ch . LC_I , Ch . LC_N ) ; -- "begin"
Label_Case : constant Object_String := ( Ch . LC_C , Ch . LC_A , Ch . LC_S , Ch . LC_E ) ; -- "case"
Label_Cond : constant Object_String := ( Ch . LC_C , Ch . LC_O , Ch . LC_N , Ch . LC_D ) ; -- "cond"
Label_Define : constant Object_String := ( Ch . LC_D , Ch . LC_E , Ch . LC_F , Ch . LC_I , Ch . LC_N , Ch . LC_E ) ; -- "define"
Label_If : constant Object_String := ( Ch . LC_I , Ch . LC_F ) ; -- "if"
Label_Lambda : constant Object_String := ( Ch . LC_L , Ch . LC_A , Ch . LC_M , Ch . LC_B , Ch . LC_D , Ch . LC_A ) ; -- "lambda"
Label_Let : constant Object_String := ( Ch . LC_L , Ch . LC_E , Ch . LC_T ) ; -- "let"
Label_Letast : constant Object_String := ( Ch . LC_L , Ch . LC_E , Ch . LC_T , Ch . Asterisk ) ; -- "let*"
Label_Letrec : constant Object_String := ( Ch . LC_L , Ch . LC_E , Ch . LC_T , Ch . LC_R , Ch . LC_E , Ch . LC_C ) ; -- "letrec"
Label_Or : constant Object_String := ( Ch . LC_O , Ch . LC_R ) ; -- "or"
Label_Quote : constant Object_String := ( Ch . LC_Q , Ch . LC_U , Ch . LC_O , Ch . LC_T , Ch . LC_E ) ; -- "quote"
Label_Set : constant Object_String := ( Ch . LC_S , Ch . LC_E , Ch . LC_T , Ch . Exclamation ) ; -- "set!"
Label_Car : constant Object_String := ( Ch . LC_C , Ch . LC_A , Ch . LC_R ) ; -- "car"
Label_Cdr : constant Object_String := ( Ch . LC_C , Ch . LC_D , Ch . LC_R ) ; -- "cdr"
Label_Setcar : constant Object_String := ( Ch . LC_S , Ch . LC_E , Ch . LC_T , Ch . LC_C , Ch . LC_A , Ch . LC_R ) ; -- "setcar"
Label_Setcdr : constant Object_String := ( Ch . LC_S , Ch . LC_E , Ch . LC_T , Ch . LC_C , Ch . LC_D , Ch . LC_R ) ; -- "setcar"
Label_Plus : constant Object_String := ( 1 => Ch . Plus_Sign ) ; -- "+"
Label_Minus : constant Object_String := ( 1 => Ch . Minus_Sign ) ; -- "-"
Label_Multiply : constant Object_String := ( 1 => Ch . Asterisk ) ; -- "*"
Label_Divide : constant Object_String := ( 1 => Ch . Slash ) ; -- "/"
2014-01-01 14:07:03 +00:00
2013-12-21 04:57:44 +00:00
-----------------------------------------------------------------------------
2013-12-10 16:14:06 +00:00
-- EXCEPTIONS
2013-12-21 04:57:44 +00:00
-----------------------------------------------------------------------------
2013-12-10 16:14:06 +00:00
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 ;
2014-01-01 14:07:03 +00:00
IO_Error : exception ;
2014-01-07 17:02:12 +00:00
Stream_End_Error : exception ;
2013-12-10 16:14:06 +00:00
2013-12-21 04:57:44 +00:00
-----------------------------------------------------------------------------
2013-12-10 16:14:06 +00:00
-- INTERNALLY-USED TYPES
2013-12-21 04:57:44 +00:00
-----------------------------------------------------------------------------
type Heap_Element_Pointer is access all Heap_Element ;
for Heap_Element_Pointer ' Size use Object_Pointer_Bits ; -- ensure that it can be overlayed by an ObjectPointer
2013-12-10 16:14:06 +00:00
2013-12-28 16:52:31 +00:00
2013-12-21 04:57:44 +00:00
type Thin_Heap_Element_Array is array ( 1 . . Heap_Size ' Last ) of Heap_Element ;
type Thin_Heap_Element_Array_Pointer is access all Thin_Heap_Element_Array ;
for Thin_Heap_Element_Array_Pointer ' Size use Object_Pointer_Bits ;
2013-12-10 16:14:06 +00:00
2013-12-28 16:52:31 +00:00
subtype Moved_Object_Record is Object_Record ( Moved_Object , 0 ) ;
2014-01-08 14:59:48 +00:00
subtype Opcode_Type is Object_Integer range 0 . . 11 ;
2013-12-17 16:04:55 +00:00
Opcode_Exit : constant Opcode_Type := Opcode_Type ' ( 0 ) ;
2014-01-08 14:59:48 +00:00
Opcode_Evaluate_Result : constant Opcode_Type := Opcode_Type ' ( 1 ) ;
Opcode_Evaluate_Object : constant Opcode_Type := Opcode_Type ' ( 2 ) ;
Opcode_Evaluate_Group : constant Opcode_Type := Opcode_Type ' ( 3 ) ; -- (begin ...) and closure apply
2013-12-19 13:54:47 +00:00
Opcode_Evaluate_Procedure : constant Opcode_Type := Opcode_Type ' ( 4 ) ;
Opcode_Apply : constant Opcode_Type := Opcode_Type ' ( 5 ) ;
2013-12-28 16:52:31 +00:00
Opcode_Read_Object : constant Opcode_Type := Opcode_Type ' ( 6 ) ;
2014-01-07 17:02:12 +00:00
Opcode_Read_List : constant Opcode_Type := Opcode_Type ' ( 7 ) ;
2014-01-08 07:18:14 +00:00
Opcode_Read_List_Cdr : constant Opcode_Type := Opcode_Type ' ( 8 ) ;
Opcode_Read_List_End : constant Opcode_Type := Opcode_Type ' ( 9 ) ;
Opcode_Close_List : constant Opcode_Type := Opcode_Type ' ( 10 ) ;
2014-01-08 14:59:48 +00:00
Opcode_Close_Quote : constant Opcode_Type := Opcode_Type ' ( 11 ) ;
2013-12-17 16:04:55 +00:00
2013-12-21 04:57:44 +00:00
-----------------------------------------------------------------------------
2013-12-10 16:14:06 +00:00
-- COMMON OBJECTS
2013-12-21 04:57:44 +00:00
-----------------------------------------------------------------------------
2013-12-10 16:14:06 +00:00
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 ;
2014-01-08 14:59:48 +00:00
Frame_Result_Index : constant Pointer_Object_Size := 5 ;
2013-12-17 16:04:55 +00:00
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-28 16:52:31 +00:00
procedure Set_New_Location ( Object : in Object_Pointer ;
Ptr : in Heap_Element_Pointer ) ;
procedure Set_New_Location ( Object : in Object_Pointer ;
Ptr : in Object_Pointer ) ;
2013-12-10 16:14:06 +00:00
pragma Inline ( Set_New_Location ) ;
function Get_New_Location ( Object : in Object_Pointer ) return Object_Pointer ;
pragma Inline ( Get_New_Location ) ;
2013-12-21 04:57:44 +00:00
-----------------------------------------------------------------------------
2013-12-10 16:14:06 +00:00
-- POINTER AND DATA CONVERSION
2013-12-21 04:57:44 +00:00
-----------------------------------------------------------------------------
2013-12-10 16:14:06 +00:00
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 ;
2014-01-09 15:32:36 +00:00
--return Object_Label_To_Object_Pointer (Word);
2013-12-10 16:14:06 +00:00
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.
2014-01-01 14:07:03 +00:00
Word := Object_Character ' Pos ( Char ) ;
2013-12-10 16:14:06 +00:00
Word := ( Word * ( 2 * * Object_Pointer_Type_Bits ) ) or Object_Word ( Object_Pointer_Type_Character ) ;
2014-01-09 15:32:36 +00:00
--return Object_Label_To_Object_Pointer (Word);
2013-12-10 16:14:06 +00:00
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
2014-01-01 14:07:03 +00:00
return Object_Character ' Val ( Word / ( 2 * * Object_Pointer_Type_Bits ) ) ;
2013-12-10 16:14:06 +00:00
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
2014-01-09 15:32:36 +00:00
-- X: Object_Size;
2013-12-10 16:14:06 +00:00
--begin
2014-01-09 15:32:36 +00:00
-- X := Target'First;
-- for I in Source'Range loop
-- Target(X) := Source(I);
-- X := X + 1;
2013-12-10 16:14:06 +00:00
-- end loop;
2014-01-09 15:32:36 +00:00
-- Target(X) := Object_Character'First; -- Object_Character'Val(0);
2013-12-10 16:14:06 +00:00
--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
2014-01-09 15:32:36 +00:00
Target ( Target ' First . . Target ' Last - 1 ) := To_Character_Array ( Source ) ;
2013-12-10 16:14:06 +00:00
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 ) ;
2014-01-09 15:32:36 +00:00
--declare
-- X: Standard.Natural;
--begin
-- X := Target'First;
-- for I in Source'First .. Source'Last - 1 loop
-- Target(X) := Source(I);
-- X := X + 1;
-- end loop;
--end;
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 ( Target ' Range ) ;
2014-01-09 15:32:36 +00:00
function To_Character_Array is new Ada . Unchecked_Conversion ( Character_Array , String_Array ) ;
2013-12-10 16:14:06 +00:00
begin
Target := To_Character_Array ( Source ( Source ' First . . Source ' Last - 1 ) ) ;
end ;
end Copy_String ;
2014-01-01 14:07:03 +00:00
function Character_Array_To_String ( Source : in Object_Character_Array ) return Object_String is
2013-12-10 16:14:06 +00:00
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 ;
2014-01-01 14:07:03 +00:00
end Character_Array_To_String ;
2013-12-10 16:14:06 +00:00
2014-01-09 15:32:36 +00:00
--Text_IO.Put (Character_Array_To_String (Atom.Character_Slot));
procedure Output_Character_Array ( Source : in Object_Character_Array ) is
-- for debugging only.
begin
for I in Source ' First . . Source ' Last loop
--Ada.Text_IO.Put (Source(I));
-- TODO: note this is a hack for quick printing.
Ada . Text_IO . Put ( Standard . Character ' Val ( Object_Character ' Pos ( Source ( I ) ) ) ) ;
end loop ;
end Output_Character_Array ;
2013-12-10 16:14:06 +00:00
-- 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;
2014-01-02 16:28:18 +00:00
2013-12-10 16:14:06 +00:00
-- 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
2014-01-09 15:32:36 +00:00
procedure Print_Object_Pointer ( Msg : in Standard . String ; Source : in Object_Pointer ) is
2013-12-10 16:14:06 +00:00
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
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put_Line ( Msg & Object_Character ' Image ( Pointer_To_Character ( Source ) ) ) ;
2013-12-17 16:04:55 +00:00
elsif Ptr_Type = Object_Pointer_Type_Integer then
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put_Line ( Msg & Object_Integer ' Image ( Pointer_To_Integer ( Source ) ) ) ;
2013-12-17 16:04:55 +00:00
elsif Is_Special_Pointer ( Source ) then
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put_Line ( Msg & " at " & Object_Word ' Image ( W ) ) ;
2013-12-10 16:14:06 +00:00
elsif Source . Kind = Character_Object then
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put ( Msg & " at " & Object_Word ' Image ( W ) &
" at " & Object_Kind ' Image ( Source . Kind ) &
" size " & Object_Size ' Image ( Source . Size ) & " - " ) ;
2013-12-10 16:14:06 +00:00
if Source . Kind = Moved_Object then
2014-01-09 15:32:36 +00:00
--Text_IO.Put_Line (Character_Array_To_String (Get_New_Location(Source).Character_Slot));
null ;
2013-12-10 16:14:06 +00:00
else
2014-01-09 15:32:36 +00:00
--Text_IO.Put_Line (Character_Array_To_String (Source.Character_Slot));
null ;
2013-12-10 16:14:06 +00:00
end if ;
else
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put_Line ( Msg & " at " & Object_Word ' Image ( W ) & " at " & Object_Kind ' Image ( Source . Kind ) ) ;
2013-12-10 16:14:06 +00:00
end if ;
end Print_Object_Pointer ;
2014-01-08 14:59:48 +00:00
function String_To_Integer_Pointer ( Source : in Object_String ) return Object_Pointer is
V : Object_Integer := 0 ;
Negative : Standard . Boolean := False ;
First : Standard . Natural ;
begin
-- TODO: BIGNUM, RANGE CHECK, ETC
pragma Assert ( Source ' Length > 0 ) ;
First := Source ' First ;
2014-01-09 15:32:36 +00:00
if Source ( First ) = Ch . Minus_Sign then
2014-01-08 14:59:48 +00:00
First := First + 1 ;
Negative := Standard . True ;
2014-01-09 15:32:36 +00:00
elsif Source ( First ) = Ch . Plus_Sign then
2014-01-08 14:59:48 +00:00
First := First + 1 ;
end if ;
for I in First . . Source ' Last loop
2014-01-09 15:32:36 +00:00
V := V * 10 + Object_Character ' Pos ( Source ( I ) ) - Object_Character ' Pos ( Ch . Zero ) ;
2014-01-08 14:59:48 +00:00
end loop ;
if Negative then
V := - V ;
end if ;
return Integer_To_Pointer ( V ) ;
end String_To_Integer_Pointer ;
2013-12-21 04:57:44 +00:00
-----------------------------------------------------------------------------
2013-12-10 16:14:06 +00:00
-- MEMORY MANAGEMENT
2013-12-21 04:57:44 +00:00
-----------------------------------------------------------------------------
2013-12-10 16:14:06 +00:00
-- (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.
--------------------------------------------------------------------
2013-12-21 04:57:44 +00:00
--procedure Set_New_Location (Object: in Object_Pointer; Ptr: in Heap_Element_Pointer) is
--New_Addr: Heap_Element_Pointer;
2013-12-10 16:14:06 +00:00
--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.
2013-12-21 04:57:44 +00:00
procedure Set_New_Location ( Object : in Object_Pointer ; Ptr : in Heap_Element_Pointer ) is
2013-12-10 16:14:06 +00:00
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.
2013-12-21 04:57:44 +00:00
function To_Object_Pointer is new Ada . Unchecked_Conversion ( Heap_Element_Pointer , Object_Pointer ) ;
2013-12-10 16:14:06 +00:00
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
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 ;
2013-12-21 04:57:44 +00:00
Heap_Bytes : in Heap_Size ) return Heap_Element_Pointer is
Avail : Heap_Size ;
Result : Heap_Element_Pointer ;
2013-12-28 16:52:31 +00:00
Real_Bytes : Heap_Size := Heap_Bytes ;
2013-12-10 16:14:06 +00:00
begin
2013-12-28 16:52:31 +00:00
if Real_Bytes < Moved_Object_Record ' Max_Size_In_Storage_Elements then
-- Guarantee the minimum object size to be greater than or
-- equal to the size of a moved object for GC to work.
Real_Bytes := Moved_Object_Record ' Max_Size_In_Storage_Elements ;
end if ;
2013-12-10 16:14:06 +00:00
Avail := Heap . Size - Heap . Bound ;
2013-12-28 16:52:31 +00:00
if Real_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 ;
2013-12-28 16:52:31 +00:00
Heap . Bound := Heap . Bound + Real_Bytes ;
2013-12-19 13:54:47 +00:00
return Result ;
2013-12-10 16:14:06 +00:00
end Allocate_Bytes_In_Heap ;
procedure Copy_Object ( Source : in Object_Pointer ;
2013-12-21 04:57:44 +00:00
Target : in out Heap_Element_Pointer ) is
2013-12-10 16:14:06 +00:00
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
2013-12-28 16:52:31 +00:00
-- it's supposed to be 96. Use Copy_Object_With_Size() below instead.
2013-12-10 16:14:06 +00:00
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 ;
2013-12-21 04:57:44 +00:00
Target : in out Heap_Element_Pointer ;
Bytes : in Heap_Size ) is
2013-12-11 16:30:56 +00:00
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.
2013-12-21 04:57:44 +00:00
Tgt : Thin_Heap_Element_Array_Pointer ;
2013-12-10 16:14:06 +00:00
for Tgt ' Address use Target ' Address ;
pragma Import ( Ada , Tgt ) ;
2013-12-21 04:57:44 +00:00
Src : Thin_Heap_Element_Array_Pointer ;
2013-12-10 16:14:06 +00:00
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
2013-12-21 04:57:44 +00:00
Last_Pos : Heap_Size ;
2013-12-10 16:14:06 +00:00
New_Heap : Heap_Number ;
2013-12-21 04:57:44 +00:00
--function To_Object_Pointer is new Ada.Unchecked_Conversion (Heap_Element_Pointer, Object_Pointer);
2013-12-10 16:14:06 +00:00
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
2013-12-21 04:57:44 +00:00
Bytes : Heap_Size ;
2013-12-10 16:14:06 +00:00
-- This variable holds the allocation result
2013-12-21 04:57:44 +00:00
Ptr : Heap_Element_Pointer ;
2013-12-10 16:14:06 +00:00
-- 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 ) ;
2014-01-01 14:07:03 +00:00
Ada . Text_IO . Put_Line ( Object_Word ' Image ( Pointer_To_Word ( Object ) ) & Object_Word ' Image ( Pointer_To_Word ( New_Object ) ) ) ;
Ada . 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 ) ) ) ;
2013-12-10 16:14:06 +00:00
-- Return the new object
return New_Object ;
end ;
end if ;
end Move_One_Object ;
2013-12-21 04:57:44 +00:00
function Scan_New_Heap ( Start_Position : in Heap_Size ) return Heap_Size is
Ptr : Heap_Element_Pointer ;
2013-12-10 16:14:06 +00:00
2013-12-21 04:57:44 +00:00
Position : Heap_Size ;
2013-12-10 16:14:06 +00:00
begin
Position := Start_Position ;
2013-12-21 04:57:44 +00:00
--Text_IO.Put_Line ("Start Scanning New Heap from " & Heap_Size'Image (Start_Position) & " Bound: " & Heap_Size'Image (Interp.Heap(New_Heap).Bound));
2013-12-10 16:14:06 +00:00
while Position < = Interp . Heap ( New_Heap ) . Bound loop
2013-12-21 04:57:44 +00:00
--Text_IO.Put_Line (">>> Scanning New Heap from " & Heap_Size'Image (Position) & " Bound: " & Heap_Size'Image (Interp.Heap(New_Heap).Bound));
2013-12-10 16:14:06 +00:00
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);
2013-12-21 04:57:44 +00:00
Bytes : Heap_Size ;
2013-12-10 16:14:06 +00:00
begin
--Bytes := Target_Object_Record'Max_Size_In_Storage_Elements;
Bytes := Object . all ' Size / System . Storage_Unit ;
2013-12-21 04:57:44 +00:00
--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 " & Heap_Size'Image(Bytes));
2013-12-10 16:14:06 +00:00
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.
2014-01-09 15:32:36 +00:00
--Text_IO.Put_Line ("COMPACT_SYMBOL_TABLE Unlinking " & Character_Array_To_String (Car.Character_Slot));
2013-12-10 16:14:06 +00:00
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
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put_Line ( ">>> [COMPACTING SYMBOL TABLE]" ) ;
2013-12-10 16:14:06 +00:00
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 ) ;
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put_Line ( ">>> [SCANNING HEAP AGAIN AFTER SYMBOL TABLE MIGRATION]" ) ;
2013-12-10 16:14:06 +00:00
-- 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 ;
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put_Line ( ">>> [GC DONE]" ) ;
2013-12-10 16:14:06 +00:00
end Collect_Garbage ;
2013-12-19 13:54:47 +00:00
function Allocate_Bytes ( Interp : access Interpreter_Record ;
2013-12-21 04:57:44 +00:00
Bytes : in Heap_Size ) return Heap_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.
2013-12-21 04:57:44 +00:00
Tmp : Heap_Element_Pointer ;
2013-12-10 16:14:06 +00:00
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 ;
2013-12-21 04:57:44 +00:00
Ptr : Heap_Element_Pointer ;
2013-12-10 16:14:06 +00:00
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-21 04:57:44 +00:00
Heap_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 ;
2013-12-21 04:57:44 +00:00
Ptr : Heap_Element_Pointer ;
2013-12-10 16:14:06 +00:00
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 ,
2013-12-21 04:57:44 +00:00
Heap_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 ;
2013-12-21 04:57:44 +00:00
Ptr : Heap_Element_Pointer ;
2013-12-10 16:14:06 +00:00
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-21 04:57:44 +00:00
Ptr := Allocate_Bytes ( Interp . Self , Heap_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 ;
2013-12-21 04:57:44 +00:00
-----------------------------------------------------------------------------
2013-12-19 13:54:47 +00:00
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
2014-01-08 07:18:14 +00:00
function Reverse_Cons ( Source : in Object_Pointer ;
Last_Cdr : in Object_Pointer := Nil_Pointer ) return Object_Pointer is
2013-12-18 14:58:46 +00:00
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
2014-01-08 07:18:14 +00:00
--Prev := Nil_Pointer;
Prev := Last_Cdr ;
2013-12-18 14:58:46 +00:00
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-21 04:57:44 +00:00
-----------------------------------------------------------------------------
2013-12-17 16:04:55 +00:00
2013-12-19 13:54:47 +00:00
function Make_String ( Interp : access Interpreter_Record ;
2014-01-07 17:02:12 +00:00
Source : in Object_String ) return Object_Pointer is
2013-12-19 13:54:47 +00:00
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 ;
2014-01-09 15:32:36 +00:00
--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 ) ;
return Ptr ;
2013-12-17 16:04:55 +00:00
end Make_Symbol ;
2013-12-21 04:57:44 +00:00
-----------------------------------------------------------------------------
2013-12-17 16:04:55 +00:00
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 ;
2013-12-21 04:57:44 +00:00
-----------------------------------------------------------------------------
2013-12-19 13:54:47 +00:00
--
-- 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 ;
2013-12-21 04:57:44 +00:00
-----------------------------------------------------------------------------
2013-12-19 13:54:47 +00:00
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 ;
2014-01-09 15:32:36 +00:00
--Ada.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-21 04:57:44 +00:00
-----------------------------------------------------------------------------
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 ;
2014-01-08 14:59:48 +00:00
function Get_Frame_Result ( Frame : in Object_Pointer ) return Object_Pointer is
pragma Inline ( Get_Frame_Result ) ;
2013-12-17 16:04:55 +00:00
pragma Assert ( Is_Frame ( Frame ) ) ;
2013-12-18 14:58:46 +00:00
begin
2014-01-08 14:59:48 +00:00
return Frame . Pointer_Slot ( Frame_Result_Index ) ;
end Get_Frame_Result ;
2013-12-17 16:04:55 +00:00
2014-01-08 14:59:48 +00:00
--procedure Set_Frame_Result (Frame: in out Object_Pointer;
2014-01-07 17:02:12 +00:00
-- Value: in Object_Pointer) is
2014-01-08 14:59:48 +00:00
-- pragma Inline (Set_Frame_Result);
2014-01-07 17:02:12 +00:00
-- pragma Assert (Is_Frame(Frame));
--begin
2014-01-08 14:59:48 +00:00
-- Frame.Pointer_Slot(Frame_Result_Index) := Value;
--end Set_Frame_Result;
2013-12-17 16:04:55 +00:00
2014-01-08 14:59:48 +00:00
procedure Chain_Frame_Result ( Interp : in out Interpreter_Record ;
2013-12-18 14:58:46 +00:00
Frame : in out Object_Pointer ;
Value : in Object_Pointer ) is
2014-01-08 14:59:48 +00:00
pragma Inline ( Chain_Frame_Result ) ;
2013-12-18 14:58:46 +00:00
pragma Assert ( Is_Frame ( Frame ) ) ;
2014-01-08 14:59:48 +00:00
Ret_Head : Object_Pointer renames Frame . Pointer_Slot ( Frame_Result_Index ) ;
2013-12-18 14:58:46 +00:00
begin
-- TODO: make it GC-aware
-- Add a new cons cell to the front
2014-01-07 17:02:12 +00:00
Ret_Head := Make_Cons ( Interp . Self , Value , Ret_Head ) ;
2014-01-08 14:59:48 +00:00
end Chain_Frame_Result ;
2013-12-18 14:58:46 +00:00
2014-01-08 14:59:48 +00:00
procedure Clear_Frame_Result ( Frame : in out Object_Pointer ) is
2013-12-18 14:58:46 +00:00
begin
2014-01-08 14:59:48 +00:00
Frame . Pointer_Slot ( Frame_Result_Index ) := Nil_Pointer ;
end Clear_Frame_Result ;
2013-12-18 14:58:46 +00:00
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-21 04:57:44 +00:00
-----------------------------------------------------------------------------
2013-12-17 16:04:55 +00:00
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-21 04:57:44 +00:00
-----------------------------------------------------------------------------
2013-12-18 14:58:46 +00:00
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-21 04:57:44 +00:00
-----------------------------------------------------------------------------
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 ;
2014-01-01 14:07:03 +00:00
procedure Close_Stream ( Stream : in out Stream_Pointer ) is
begin
Close ( Stream . all ) ;
Stream := null ;
exception
when others =>
Stream := null ; -- ignore exception
end Close_Stream ;
procedure Start_Named_Input_Stream ( Interp : in out Interpreter_Record ;
Name : in Constant_Object_String_Pointer ) is
package IO_Pool is new H2.Pool ( IO_Record, IO_Pointer, Interp.Storage_Pool) ;
IO : IO_Pointer := null ;
Stream : Stream_Pointer := null ;
begin
begin
IO := IO_Pool . Allocate ;
Interp . Stream . Allocate ( Interp , Name , Stream ) ;
exception
when others =>
if IO / = null then
if Stream / = null then
Interp . Stream . Deallocate ( Interp , Stream ) ;
end if ;
IO_Pool . Deallocate ( IO ) ;
end if ;
raise ;
end ;
--IO.Stream := Stream;
--IO.Pos := IO.Data'First - 1;
--IO.Last := IO.Data'First - 1;
--IO.Flags := 0;
--IO.Next := Interp.Input;
--Interp.Input := IO;
IO . all := IO_Record ' (
Stream => Stream ,
2014-01-09 15:32:36 +00:00
Data => ( others => Object_Character ' First ) ,
2014-01-01 14:07:03 +00:00
Pos | Last => IO . Data ' First - 1 ,
Flags => 0 ,
Next => Interp . Input ,
Iochar => IO_Character_Record ' ( End_Character , Object_Character ' First )
) ;
Interp . Input := IO ;
end Start_Named_Input_Stream ;
procedure Stop_Named_Input_Stream ( Interp : in out Interpreter_Record ) is
package IO_Pool is new H2.Pool ( IO_Record, IO_Pointer, Interp.Storage_Pool) ;
IO : IO_Pointer ;
begin
pragma Assert ( Interp . Input / = Interp . Base_Input ' Unchecked_Access ) ;
IO := Interp . Input ;
Interp . Input := IO . Next ;
pragma Assert ( IO . Stream / = null ) ;
Close_Stream ( IO . Stream ) ;
Interp . Stream . Deallocate ( Interp , IO . Stream ) ;
IO_Pool . Deallocate ( IO ) ;
end Stop_Named_Input_Stream ;
-----------------------------------------------------------------------------
2013-12-10 16:14:06 +00:00
procedure Open ( Interp : in out Interpreter_Record ;
2013-12-21 04:57:44 +00:00
Initial_Heap_Size : in Heap_Size ;
2013-12-10 16:14:06 +00:00
Storage_Pool : in Storage_Pool_Pointer := null ) is
2013-12-21 04:57:44 +00:00
procedure Initialize_Heap ( Size : Heap_Size ) is
2013-12-10 16:14:06 +00:00
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 ;
2013-12-28 16:52:31 +00:00
2013-12-10 16:14:06 +00:00
exception
when others =>
Deinitialize_Heap ( Interp ) ;
raise ;
end Initialize_Heap ;
procedure Make_Syntax_Objects is
Dummy : Object_Pointer ;
begin
2014-01-09 15:32:36 +00:00
Dummy := Make_Syntax ( Interp . Self , And_Syntax , Label_And ) ; -- "and"
Dummy := Make_Syntax ( Interp . Self , Begin_Syntax , Label_Begin ) ; -- "begin"
Dummy := Make_Syntax ( Interp . Self , Case_Syntax , Label_Case ) ; -- "case"
Dummy := Make_Syntax ( Interp . Self , Cond_Syntax , Label_Cond ) ; -- "cond"
Dummy := Make_Syntax ( Interp . Self , Define_Syntax , Label_Define ) ; -- "define"
Dummy := Make_Syntax ( Interp . Self , If_Syntax , Label_If ) ; -- "if"
Dummy := Make_Syntax ( Interp . Self , Lambda_Syntax , Label_Lambda ) ; -- "lamba"
Dummy := Make_Syntax ( Interp . Self , Let_Syntax , Label_Let ) ; -- "let"
Dummy := Make_Syntax ( Interp . Self , Letast_Syntax , Label_Letast ) ; -- "let*"
Dummy := Make_Syntax ( Interp . Self , Letrec_Syntax , Label_Letrec ) ; -- "letrc"
Dummy := Make_Syntax ( Interp . Self , Or_Syntax , Label_Or ) ; -- "or"
Dummy := Make_Syntax ( Interp . Self , Quote_Syntax , Label_Quote ) ; -- "quote"
Dummy := Make_Syntax ( Interp . Self , Set_Syntax , Label_Set ) ; -- "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
2014-01-09 15:32:36 +00:00
Dummy := Make_Procedure ( Interp . Self , Car_Procedure , Label_Car ) ; -- "car"
Dummy := Make_Procedure ( Interp . Self , Cdr_Procedure , Label_Cdr ) ; -- "cdr"
Dummy := Make_Procedure ( Interp . Self , Setcar_Procedure , Label_Setcar ) ; -- "setcar"
Dummy := Make_Procedure ( Interp . Self , Setcdr_Procedure , Label_Setcdr ) ; -- "setcdr"
Dummy := Make_Procedure ( Interp . Self , Add_Procedure , Label_Plus ) ; -- "+"
Dummy := Make_Procedure ( Interp . Self , Subtract_Procedure , Label_Minus ) ; -- "-"
Dummy := Make_Procedure ( Interp . Self , Multiply_Procedure , Label_Multiply ) ; -- "*"
Dummy := Make_Procedure ( Interp . Self , Divide_Procedure , Label_Divide ) ; -- "/"
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
2014-01-01 14:07:03 +00:00
Interp . Base_Input . Stream := null ;
Interp . Input := Interp . Base_Input ' Unchecked_Access ;
2014-01-02 16:28:18 +00:00
Interp . Token := ( End_Token , ( null , 0 , 0 ) ) ;
2013-12-10 16:14:06 +00:00
-- TODO: disallow garbage collecion during initialization.
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put_Line ( "1111111111" ) ;
2013-12-10 16:14:06 +00:00
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 ;
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put_Line ( "99999" ) ;
2013-12-18 14:58:46 +00:00
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put_Line ( IO_Character_Record ' Size ' Img ) ;
Ada . Text_IO . Put_Line ( IO_Character_Record ' Max_Size_In_Storage_Elements ' Img ) ;
2013-12-10 16:14:06 +00:00
exception
when others =>
Deinitialize_Heap ( Interp ) ;
end Open ;
2014-01-01 14:07:03 +00:00
procedure Close ( Interp : in out Interpreter_Record ) is
2013-12-28 16:52:31 +00:00
begin
2014-01-01 14:07:03 +00:00
-- Destroy all unstacked named input streams
while Interp . Input / = Interp . Base_Input ' Unchecked_Access loop
Stop_Named_Input_Stream ( Interp ) ;
end loop ;
2013-12-28 16:52:31 +00:00
2014-01-01 14:07:03 +00:00
if Interp . Base_Input . Stream / = null then
-- Close the main input stream.
Close_Stream ( Interp . Base_Input . Stream ) ;
2013-12-28 16:52:31 +00:00
end if ;
2013-12-10 16:14:06 +00:00
Deinitialize_Heap ( Interp ) ;
2014-01-04 06:31:14 +00:00
Token . Purge ( Interp ) ;
2013-12-10 16:14:06 +00:00
end Close ;
2013-12-28 16:52:31 +00:00
function Get_Storage_Pool ( Interp : in Interpreter_Record ) return Storage_Pool_Pointer is
begin
return Interp . Storage_Pool ;
end Get_Storage_Pool ;
2013-12-10 16:14:06 +00:00
procedure Set_Option ( Interp : in out Interpreter_Record ;
Option : in Option_Record ) is
begin
case Option . Kind is
2013-12-28 16:52:31 +00:00
when Trait_Option =>
2013-12-10 16:14:06 +00:00
Interp . Trait := Option ;
2013-12-28 16:52:31 +00:00
when Stream_Option =>
Interp . Stream := Option ;
2013-12-10 16:14:06 +00:00
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-28 16:52:31 +00:00
when Trait_Option =>
2013-12-10 16:14:06 +00:00
Option := Interp . Trait ;
2013-12-28 16:52:31 +00:00
when Stream_Option =>
Option := Interp . Stream ;
2013-12-10 16:14:06 +00:00
end case ;
end Get_Option ;
2013-12-28 16:52:31 +00:00
procedure Set_Input_Stream ( Interp : in out Interpreter_Record ;
Stream : in out Stream_Record ' Class ) is
begin
--Open (Stream, Interp);
Open ( Stream ) ;
-- if Open raised an exception, it wouldn't reach here.
-- so the existing stream still remains intact.
2014-01-01 14:07:03 +00:00
if Interp . Base_Input . Stream / = null then
Close_Stream ( Interp . Base_Input . Stream ) ;
2013-12-28 16:52:31 +00:00
end if ;
2014-01-01 14:07:03 +00:00
Interp . Base_Input := IO_Record ' (
Stream => Stream ' Unchecked_Access ,
Data => ( others => Object_Character ' First ) ,
Pos | Last => Interp . Base_Input . Data ' First - 1 ,
Flags => 0 ,
Next => null ,
Iochar => IO_Character_Record ' ( End_Character , Object_Character ' First )
) ;
2013-12-28 16:52:31 +00:00
end Set_Input_Stream ;
--procedure Set_Output_Stream (Interp: in out Interpreter_Record;
-- Stream: in out Stream_Record'Class) is
--begin
--
--end Set_Output_Stream;
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 =>
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put ( "()" ) ;
2013-12-10 16:14:06 +00:00
2013-12-17 16:04:55 +00:00
when True_Word =>
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put ( "#t" ) ;
2013-12-10 16:14:06 +00:00
2013-12-17 16:04:55 +00:00
when False_Word =>
2014-01-09 15:32:36 +00:00
Ada . 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 =>
2014-01-09 15:32:36 +00:00
Output_Character_Array ( Atom . Character_Slot ) ;
2013-12-10 16:14:06 +00:00
2013-12-17 16:04:55 +00:00
when String_Object =>
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put ( "" "" ) ;
Output_Character_Array ( Atom . Character_Slot ) ;
Ada . Text_IO . Put ( "" "" ) ;
2013-12-10 16:14:06 +00:00
2013-12-21 04:57:44 +00:00
when Closure_Object =>
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put ( "#Closure" ) ;
2013-12-21 04:57:44 +00:00
2013-12-17 16:04:55 +00:00
when Continuation_Object =>
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put ( "#Continuation" ) ;
2013-12-17 16:04:55 +00:00
when Procedure _Object =>
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put ( "#Procedure" ) ;
2013-12-17 16:04:55 +00:00
2013-12-19 13:54:47 +00:00
when Array_Object =>
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put ( "#Array" ) ;
2013-12-19 13:54:47 +00:00
2013-12-17 16:04:55 +00:00
when Others =>
if Atom . Kind = Character_Object then
2014-01-09 15:32:36 +00:00
Output_Character_Array ( Atom . Character_Slot ) ;
2013-12-17 16:04:55 +00:00
else
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put ( "#NOIMPL#" ) ;
2013-12-17 16:04:55 +00:00
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
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put ( Object_Integer ' Image ( X ) ) ;
2013-12-10 16:14:06 +00:00
end Print_Integer ;
procedure Print_Character is
X : constant Object_Character := Pointer_To_Character ( Atom ) ;
begin
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put ( Object_Character ' Image ( X ) ) ;
2013-12-10 16:14:06 +00:00
end Print_Character ;
procedure Print_Byte is
X : constant Object_Byte := Pointer_To_Byte ( Atom ) ;
begin
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put ( Object_Byte ' Image ( X ) ) ;
2013-12-10 16:14:06 +00:00
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 ;
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put ( "(" ) ;
2013-12-10 16:14:06 +00:00
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
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put ( " " ) ;
2013-12-10 16:14:06 +00:00
Cons := Cdr ;
exit when Cons = Nil_Pointer ;
else
if Cdr / = Nil_Pointer then
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put ( " . " ) ;
2013-12-10 16:14:06 +00:00
Print_Atom ( Cdr ) ;
end if ;
exit ;
end if ;
end loop ;
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put ( ")" ) ;
2013-12-10 16:14:06 +00:00
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
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put ( "(" ) ;
2013-12-17 16:04:55 +00:00
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
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put ( " " ) ;
2013-12-17 16:04:55 +00:00
Operand := Get_Car ( Operand ) ; -- car
Opcode := 1 ;
else
if Operand / = Nil_Pointer then
-- cdr of the last cons cell is not null.
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put ( " . " ) ;
2013-12-17 16:04:55 +00:00
Print_Atom ( Operand ) ;
end if ;
2014-01-09 15:32:36 +00:00
Ada . 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);
2014-01-09 15:32:36 +00:00
Ada . Text_IO . New_Line ;
2013-12-10 16:14:06 +00:00
end Print ;
2013-12-17 16:04:55 +00:00
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 ;
2014-01-07 17:02:12 +00:00
procedure Push_Frame ( Interp : in out Interpreter_Record ;
Opcode : in Opcode_Type ;
Operand : in Object_Pointer ) is
pragma Inline ( Push_Frame ) ;
begin
Interp . Stack := Make_Frame ( Interp . Self , Interp . Stack , Opcode_To_Pointer ( Opcode ) , Operand , Interp . Environment ) ;
end Push_Frame ;
2013-12-17 16:04:55 +00:00
2014-01-07 17:02:12 +00:00
--procedure Pop_Frame (Interp.Stack: out Object_Pointer;
-- Opcode: out Opcode_Type;
-- Operand: out Object_Pointer) is
-- pragma Inline (Pop_Frame);
--begin
-- 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
--end Pop_Frame;
procedure Pop_Frame ( Interp : in out Interpreter_Record ) is
pragma Inline ( Pop_Frame ) ;
begin
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
end Pop_Frame ;
procedure Execute ( Interp : in out Interpreter_Record ) is
LC : IO_Character_Record renames Interp . Input . Iochar ;
2013-12-17 16:04:55 +00:00
2014-01-08 14:59:48 +00:00
procedure Evaluate_Result is
pragma Inline ( Evaluate_Result ) ;
begin
-- The result from the previous frame is stored in the current frame.
-- This procedure takes the result and switch it to an operand and clears it.
-- It is used to evaluate the result of Read_Object in principle.
-- It takes only the head(car) element of the result chain.
-- Calling this function to evaluate the result of any arbitrary frame
-- other than 'Read_Object' is not recommended.
Set_Frame_Operand ( Interp . Stack , Get_Car ( Get_Frame_Result ( Interp . Stack ) ) ) ;
Clear_Frame_Result ( Interp . Stack ) ;
Set_Frame_Opcode ( Interp . Stack , Opcode_Evaluate_Object ) ;
end Evaluate_Result ;
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.
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put_Line ( "$$$$..................FUCKING CDR. FOR GROUP....................$$$$" ) ;
2013-12-19 13:54:47 +00:00
-- raise Syntax_Error;
end if ;
2014-01-07 17:02:12 +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.
2013-12-19 13:54:47 +00:00
Set_Frame_Operand ( Interp . Stack , Interp . Mark ) ;
end if ;
-- Clear the return value from the previous expression.
2014-01-08 14:59:48 +00:00
Clear_Frame_Result ( Interp . Stack ) ;
2013-12-19 13:54:47 +00:00
-- Arrange to evaluate the current expression
2014-01-07 17:02:12 +00:00
Push_Frame ( Interp , Opcode_Evaluate_Object , Car ) ;
2013-12-19 13:54:47 +00:00
when Mark_Object =>
2014-01-08 14:59:48 +00:00
Operand := Get_Frame_Result ( Interp . Stack ) ;
2014-01-07 17:02:12 +00:00
Pop_Frame ( Interp ) ; -- Done
-- There must be only 1 return value chained in the Group frame.
pragma Assert ( Get_Cdr ( Operand ) = Nil_Pointer ) ;
-- Transfer the only return value to the upper chain
2014-01-08 14:59:48 +00:00
Chain_Frame_Result ( Interp , Interp . Stack , Get_Car ( Operand ) ) ;
2013-12-19 13:54:47 +00:00
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
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put_Line ( "Unbound symbol...." ) ;
2014-01-07 17:02:12 +00:00
Print ( Interp , Operand ) ;
2013-12-19 13:54:47 +00:00
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-21 04:57:44 +00:00
Operand := Cdr ; -- Skip "begin"
2013-12-19 13:54:47 +00:00
2013-12-21 04:57:44 +00:00
if not Is_Cons ( Operand ) then
-- e.g) (begin)
-- (begin . 10)
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put_LINE ( "FUCKNING CDR FOR BEGIN" ) ;
2013-12-21 04:57:44 +00:00
raise Syntax_Error ;
2014-01-07 17:02:12 +00:00
--Pop_Frame (Interp); -- Done
2013-12-19 13:54:47 +00:00
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 ;
2014-01-08 14:59:48 +00:00
2013-12-19 13:54:47 +00:00
when Define_Syntax =>
2014-01-08 14:59:48 +00:00
-- (define x 10)
-- (define (add x y) (+ x y)) -> (define add (lambda (x y) (+ x y)))
Operand := Cdr ; -- Skip "define"
if not Is_Cons ( Operand ) then
-- e.g) (define)
-- (define . 10)
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put_LINE ( "FUCKNING CDR FOR DEFINE" ) ;
2014-01-08 14:59:48 +00:00
raise Syntax_Error ;
elsif Get_Cdr ( Operand ) / = Nil_Pointer then
-- TODO: IMPLEMENT OTHER CHECK
2014-01-09 15:32:36 +00:00
null ;
2014-01-08 14:59:48 +00:00
end if ;
--Pop_Frame (Interp); -- Done
--Chain_Frame_Result (Interp, Interp.Stack, Get_Car(Operand));
-- TODO: IMPLEMENT DEFINE.
2013-12-21 04:57:44 +00:00
when Lambda_Syntax =>
-- (lambda (x y) (+ x y));
Operand := Cdr ; -- Skip "lambda"
if not Is_Cons ( Operand ) then
-- e.g) (lambda)
-- (lambda . 10)
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put_LINE ( "FUCKNING CDR FOR BEGIN" ) ;
2013-12-21 04:57:44 +00:00
raise Syntax_Error ;
2014-01-07 17:02:12 +00:00
--Pop_Frame (Interp); -- Done
2013-12-21 04:57:44 +00:00
else
if not Is_Cons ( Get_Car ( Operand ) ) then
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put_Line ( "INVALID PARRAMETER LIST" ) ;
2013-12-21 04:57:44 +00:00
raise Syntax_Error ;
2014-01-07 17:02:12 +00:00
--Pop_Frame (Interp); -- Done
2013-12-21 04:57:44 +00:00
end if ;
--Print (Interp, Get_Cdr(Operand));
if not Is_Cons ( Get_Cdr ( Operand ) ) then
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put_Line ( "NO BODY" ) ;
2013-12-21 04:57:44 +00:00
raise Syntax_Error ;
2014-01-07 17:02:12 +00:00
--Pop_Frame (Interp); -- Done
2013-12-21 04:57:44 +00:00
end if ;
declare
Closure : Object_Pointer ;
begin
Closure := Make_Closure ( Interp . Self , Operand , Interp . Environment ) ;
2014-01-07 17:02:12 +00:00
Pop_Frame ( Interp ) ; -- Done
2014-01-08 14:59:48 +00:00
Chain_Frame_Result ( Interp , Interp . Stack , Closure ) ;
2013-12-21 04:57:44 +00:00
end ;
end if ;
2014-01-08 14:59:48 +00:00
when Quote_Syntax =>
Operand := Cdr ; -- Skip "quote"
if not Is_Cons ( Operand ) then
-- e.g) (quote)
-- (quote . 10)
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put_LINE ( "FUCKNING CDR FOR QUOTE" ) ;
2014-01-08 14:59:48 +00:00
raise Syntax_Error ;
elsif Get_Cdr ( Operand ) / = Nil_Pointer then
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put_LINE ( "WRONG NUMBER OF ARGUMENTS FOR QUOTE" ) ;
2014-01-08 14:59:48 +00:00
raise Syntax_Error ;
end if ;
Pop_Frame ( Interp ) ; -- Done
Chain_Frame_Result ( Interp , Interp . Stack , Get_Car ( Operand ) ) ;
2013-12-19 13:54:47 +00:00
when others =>
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put_Line ( "Unknown syntax" ) ;
--Set_Frame_Opcode (Interp.Stack, Opcode_Evaluate_Syntax); -- Switch to syntax evaluation
raise Internal_Error ;
2013-12-19 13:54:47 +00:00
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
2014-01-08 14:59:48 +00:00
Chain_Frame_Result ( Interp , Interp . Stack , Car ) ;
2013-12-19 14:42:14 +00:00
if Is_Cons ( Cdr ) then
Operand := Cdr ;
Car := Get_Car ( Operand ) ;
Cdr := Get_Cdr ( Operand ) ;
else
-- last cons
2014-01-08 14:59:48 +00:00
Operand := Reverse_Cons ( Get_Frame_Result ( Interp . Stack ) ) ;
Clear_Frame_Result ( Interp . Stack ) ;
2013-12-19 14:42:14 +00:00
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.
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put_Line ( "$$$$..................FUCKING CDR.....................$$$$" ) ;
2013-12-19 13:54:47 +00:00
-- 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
2014-01-07 17:02:12 +00:00
Push_Frame ( Interp , Opcode_Evaluate_Object , Car ) ;
2013-12-19 14:42:14 +00:00
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
2014-01-08 14:59:48 +00:00
-- chain must be reversed Chain_Frame_Result reverse-chains values.
Operand := Reverse_Cons ( Get_Frame_Result ( Interp . Stack ) ) ;
2013-12-19 13:54:47 +00:00
-- 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);
2014-01-07 17:02:12 +00:00
-- Pop_Frame (Interp); -- done
-- Push_Frame (Interp, Opcode_Apply, Operand, Envir);
2014-01-08 14:59:48 +00:00
Clear_Frame_Result ( Interp . Stack ) ;
2013-12-19 13:54:47 +00:00
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>>
2014-01-07 17:02:12 +00:00
Pop_Frame ( Interp ) ; -- done
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put ( "Return => " ) ;
2013-12-18 14:58:46 +00:00
Print ( Interp , Operand ) ;
2014-01-08 14:59:48 +00:00
Chain_Frame_Result ( 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_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
2014-01-07 17:02:12 +00:00
Pop_Frame ( Interp ) ; -- Done with the current frame
2014-01-08 14:59:48 +00:00
Chain_Frame_Result ( Interp , Interp . Stack , Get_Car ( Args ) ) ;
2013-12-18 14:58:46 +00:00
end Apply_Car_Procedure ;
procedure Apply_Cdr_Procedure is
begin
2014-01-07 17:02:12 +00:00
Pop_Frame ( Interp ) ; -- Done with the current frame
2014-01-08 14:59:48 +00:00
Chain_Frame_Result ( 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
2014-01-07 17:02:12 +00:00
Ada . Text_IO . Put ( "NOT INTEGER FOR ADD" ) ; Print ( Interp , Car ) ;
2013-12-18 14:58:46 +00:00
raise Evaluation_Error ;
end if ;
Num := Num + Pointer_To_Integer ( Car ) ;
Ptr := Get_Cdr ( Ptr ) ;
end loop ;
2014-01-07 17:02:12 +00:00
Pop_Frame ( Interp ) ; -- Done with the current frame
2014-01-08 14:59:48 +00:00
Chain_Frame_Result ( 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 ;
2014-01-07 17:02:12 +00:00
Pop_Frame ( Interp ) ; -- Done with the current frame
2014-01-08 14:59:48 +00:00
Chain_Frame_Result ( Interp , Interp . Stack , Integer_To_Pointer ( Num ) ) ;
2013-12-18 14:58:46 +00:00
end Apply_Subtract_Procedure ;
procedure Apply_Closure is
2013-12-21 04:57:44 +00:00
Fbody : Object_Pointer ;
2013-12-18 14:58:46 +00:00
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))"
2013-12-21 04:57:44 +00:00
-- Push a new environmen for the closure
Interp . Environment := Make_Environment ( Interp . Self , Get_Closure_Environment ( Func ) ) ;
-- TODO: GC. Func may be invalid if GC has been invoked.
Fbody := Get_Closure_Code ( Func ) ;
pragma Assert ( Is_Cons ( Fbody ) ) ; -- the reader must ensure this.
Param := Get_Car ( Fbody ) ; -- Parameter list
--Arg := Get_Car(Args); -- Actual argument list
Arg := Args ; -- Actual argument list
Fbody := Get_Cdr ( Fbody ) ; -- Real function body
pragma Assert ( Is_Cons ( Fbody ) ) ; -- the reader must ensure this as wel..
2013-12-18 14:58:46 +00:00
while Is_Cons ( Param ) loop
2013-12-21 04:57:44 +00:00
if not Is_Cons ( Arg ) then
Print ( Interp , Arg ) ;
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put_Line ( ">>>> Too few arguments <<<<" ) ;
2013-12-21 04:57:44 +00:00
raise Evaluation_Error ;
end if ;
-- Insert the key/value pair into the environment
Set_Environment ( Interp , Get_Car ( Param ) , Get_Car ( Arg ) ) ;
2013-12-18 14:58:46 +00:00
Param := Get_Cdr ( Param ) ;
Arg := Get_Cdr ( Arg ) ;
end loop ;
2013-12-21 04:57:44 +00:00
-- Perform cosmetic checks for the parameter list
if Param / = Nil_Pointer then
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put_Line ( ">>> GARBAGE IN PARAMETER LIST <<<" ) ;
2013-12-21 04:57:44 +00:00
raise Syntax_Error ;
end if ;
-- Perform cosmetic checks for the argument list
if Is_Cons ( Arg ) then
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put_Line ( ">>>> Two many arguments <<<<" ) ;
2013-12-21 04:57:44 +00:00
raise Evaluation_Error ;
elsif Arg / = Nil_Pointer then
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put_Line ( ">>> GARBAGE IN ARGUMENT LIST <<<" ) ;
2013-12-21 04:57:44 +00:00
raise Syntax_Error ;
end if ;
2013-12-18 14:58:46 +00:00
2013-12-21 04:57:44 +00:00
-- TODO: GC. the environment construction can cause GC. so Fbody here may be invalid.
-- TODO: is it correct to keep the environement in the frame?
Set_Frame_Opcode ( Interp . Stack , Opcode_Evaluate_Group ) ;
Set_Frame_Operand ( Interp . Stack , Fbody ) ;
2014-01-08 14:59:48 +00:00
Clear_Frame_Result ( Interp . Stack ) ;
2013-12-18 14:58:46 +00:00
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
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put_Line ( "INVALID FUNCTION TYPE" ) ;
2013-12-18 14:58:46 +00:00
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 =>
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put_Line ( "INVALID FUNCTION TYPE" ) ;
2013-12-18 14:58:46 +00:00
raise Internal_Error ;
end case ;
2013-12-17 16:04:55 +00:00
end Apply ;
2014-01-07 17:02:12 +00:00
procedure Fetch_Character is
begin
-- TODO: calculate Interp.Input.Row, Interp.Input.Column
if Interp . Input . Pos > = Interp . Input . Last then
if Interp . Input . Flags / = 0 then
-- An error has occurred or EOF has been reached previously.
-- Note calling this procedure after EOF results in an error.
Interp . Input . Iochar := ( Error_Character , Object_Character ' First ) ;
--return;
raise IO_Error ;
end if ;
Interp . Input . Pos := Interp . Input . Data ' First - 1 ;
begin
Read ( Interp . Input . Stream . all , Interp . Input . Data , Interp . Input . Last ) ;
exception
when others =>
-- The callee can raise an exception upon errors.
-- If an exception is raised, data read into the buffer
-- is also ignored.
Interp . Input . Flags := Interp . Input . Flags and IO_Error_Occurred ;
Interp . Input . Iochar := ( Error_Character , Object_Character ' First ) ;
--return;
raise IO_Error ;
end ;
if Interp . Input . Last < Interp . Input . Data ' First then
-- The callee must read 0 bytes on EOF
Interp . Input . Flags := Interp . Input . Flags and IO_End_Reached ;
Interp . Input . Iochar := ( End_Character , Object_Character ' First ) ;
return ;
end if ;
end if ;
Interp . Input . Pos := Interp . Input . Pos + 1 ;
Interp . Input . Iochar := ( Normal_Character , Interp . Input . Data ( Interp . Input . Pos ) ) ;
end Fetch_Character ;
function Is_White_Space ( X : in Object_Character ) return Standard . Boolean is
begin
2014-01-09 15:32:36 +00:00
return X = Ch . Space or else X = Ch . HT or else X = Ch . VT or else
X = Ch . CR or else X = Ch . LF or else X = Ch . FF ;
2014-01-07 17:02:12 +00:00
end Is_White_Space ;
2014-01-09 15:32:36 +00:00
function Is_Identifier_Stopper ( X : in Object_Character ) return Standard . Boolean is
begin
return X = Ch . Left_Parenthesis or else X = Ch . Right_Parenthesis or else
X = Ch . Apostrophe or else LC . Value = Ch . Quotation or else
X = Ch . Number_Sign or else LC . Value = Ch . Semicolon or else
Is_White_Space ( X ) ;
end Is_Identifier_Stopper ;
2014-01-07 17:02:12 +00:00
procedure Skip_Spaces_And_Comments is
begin
loop
exit when LC . Kind / = Normal_Character ;
-- Normal character
if Is_White_Space ( LC . Value ) then
Fetch_Character ;
2014-01-09 15:32:36 +00:00
elsif LC . Value = Ch . Semicolon then
2014-01-07 17:02:12 +00:00
-- Comment.
loop
Fetch_Character ;
exit when LC . Kind = End_Character ; -- EOF before LF
if LC . Kind = Normal_Character and then
LC . Value = Object_Character ' Val ( Standard . Character ' Pos ( Standard . ASCII . LF ) ) then
Fetch_Character ; -- Read the next character after LF
exit ;
end if ;
end loop ;
else
exit ;
end if ;
end loop ;
end Skip_Spaces_And_Comments ;
procedure Fetch_Token is
2014-01-08 14:59:48 +00:00
Tmp : Object_String ( 1. . 10 ) ; -- large enough???
2014-01-07 17:02:12 +00:00
begin
if not Interp . LC_Unfetched then
Fetch_Character ;
else
-- Reuse the last character unfetched
Interp . LC_Unfetched := Standard . False ;
end if ;
Skip_Spaces_And_Comments ;
if LC . Kind / = Normal_Character then
2014-01-09 15:32:36 +00:00
Token . Set ( Interp , End_Token ) ;
2014-01-07 17:02:12 +00:00
return ;
end if ;
-- TODO: Pass Token Location when calling Token.Set
2014-01-09 15:32:36 +00:00
-- Pity that "case .. end case" can't be used instead of "if .. end if"
-- because Ch.XXX values are not static. This is a pain to take
-- for making this package generic.
if LC . Value = Ch . Left_Parenthesis then
Token . Set ( Interp , Left_Parenthesis_Token , LC . Value ) ;
elsif LC . Value = Ch . Right_Parenthesis then
Token . Set ( Interp , Right_Parenthesis_Token , LC . Value ) ;
elsif LC . Value = Ch . Period then
Token . Set ( Interp , Period_Token , LC . Value ) ;
elsif LC . Value = Ch . Apostrophe then
Token . Set ( Interp , Single_Quote_Token , LC . Value ) ;
elsif LC . Value = Ch . Quotation then
Fetch_Character ;
Token . Set ( Interp , String_Token ) ;
loop
if LC . Kind / = Normal_Character then
-- String ended prematurely.
-- TODO: Set Error code, Error Number.... Error location
raise Syntax_Error ;
end if ;
2014-01-07 17:02:12 +00:00
2014-01-09 15:32:36 +00:00
if LC . Value = Ch . Backslash then
Fetch_Character ;
2014-01-07 17:02:12 +00:00
if LC . Kind / = Normal_Character then
-- String ended prematurely.
-- TODO: Set Error code, Error Number.... Error location
raise Syntax_Error ;
end if ;
2014-01-09 15:32:36 +00:00
-- TODO: escape letters??? \n \r \\ etc....
Token . Append_Character ( Interp , LC . Value ) ;
elsif LC . Value = Ch . Quotation then
exit ;
else
Token . Append_Character ( Interp , LC . Value ) ;
Fetch_Character ;
end if ;
end loop ;
elsif LC . Value = Ch . Number_Sign then
Fetch_Character ;
-- TODO: t, false, etc
elsif LC . Value in Ch . Zero . . Ch . Nine then
-- TODO; negative number, floating-point number, bignum, hexdecimal, etc
Token . Set ( Interp , Integer_Token ) ;
loop
Token . Append_Character ( Interp , LC . Value ) ;
2014-01-07 17:02:12 +00:00
Fetch_Character ;
2014-01-09 15:32:36 +00:00
if LC . Kind / = Normal_Character or else
LC . Value not in Ch . Zero . . Ch . Nine then
-- Unfetch the last character
Interp . LC_Unfetched := Standard . True ;
exit ;
end if ;
end loop ;
elsif LC . Value = Ch . Plus_Sign or else LC . Value = Ch . Minus_Sign then
Tmp ( 1 ) := LC . Value ;
2014-01-07 17:02:12 +00:00
2014-01-09 15:32:36 +00:00
Fetch_Character ;
if LC . Kind = Normal_Character and then
LC . Value in Ch . Zero . . Ch . Nine then
Token . Set ( Interp , Integer_Token , Tmp ( 1. . 1 ) ) ;
2014-01-08 14:59:48 +00:00
loop
Token . Append_Character ( Interp , LC . Value ) ;
Fetch_Character ;
if LC . Kind / = Normal_Character or else
2014-01-09 15:32:36 +00:00
LC . Value not in Ch . Zero . . Ch . Nine then
2014-01-08 14:59:48 +00:00
-- Unfetch the last character
Interp . LC_Unfetched := Standard . True ;
exit ;
end if ;
end loop ;
2014-01-09 15:32:36 +00:00
else
Token . Set ( Interp , Identifier_Token , Tmp ( 1. . 1 ) ) ;
2014-01-07 17:02:12 +00:00
loop
2014-01-09 15:32:36 +00:00
-- TODO: more characters
2014-01-08 14:59:48 +00:00
if LC . Kind / = Normal_Character or else
2014-01-09 15:32:36 +00:00
Is_Identifier_Stopper ( LC . Value ) then
2014-01-07 17:02:12 +00:00
-- Unfetch the last character
Interp . LC_Unfetched := Standard . True ;
exit ;
end if ;
2014-01-09 15:32:36 +00:00
Token . Append_Character ( Interp , LC . Value ) ;
Fetch_Character ;
2014-01-07 17:02:12 +00:00
end loop ;
2014-01-09 15:32:36 +00:00
end if ;
else
Token . Set ( Interp , Identifier_Token ) ;
loop
Token . Append_Character ( Interp , LC . Value ) ;
Fetch_Character ;
--exit when not Is_Ident_Char(C.Value);
-- TODO: more characters
if LC . Kind / = Normal_Character or else
Is_Identifier_Stopper ( LC . Value ) then
-- Unfetch the last character
Interp . LC_Unfetched := Standard . True ;
exit ;
end if ;
end loop ;
end if ;
2014-01-07 17:02:12 +00:00
2014-01-09 15:32:36 +00:00
--Ada.Text_IO.Put (">>>>>>>>>>>>>>>>>>>>>>> Token: " & Interp.Token.Value.Ptr(1..Interp.Token.Value.Last));
2014-01-07 17:02:12 +00:00
end Fetch_Token ;
procedure Read_List is
2014-01-08 14:59:48 +00:00
pragma Inline ( Read_List ) ;
2014-01-07 17:02:12 +00:00
V : Object_Pointer ;
begin
2014-01-08 07:18:14 +00:00
-- This procedure reads each token in a list.
-- If the list contains no period, this procedure reads up to the
-- closing right paranthesis; If a period is contained, it transfers
-- the control over to Read_List_Cdr.
2014-01-07 17:02:12 +00:00
Fetch_Token ;
case Interp . Token . Kind is
when End_Token =>
Ada . Text_IO . Put_Line ( "ERROR: PREMATURE LIST END" ) ;
raise Syntax_Error ;
when Left_Parenthesis_Token =>
Push_Frame ( Interp , Opcode_Read_List , Nil_Pointer ) ;
2014-01-08 14:59:48 +00:00
2014-01-07 17:02:12 +00:00
when Right_Parenthesis_Token =>
2014-01-08 14:59:48 +00:00
V := Get_Frame_Result ( Interp . Stack ) ;
2014-01-07 17:02:12 +00:00
if V / = Nil_Pointer then
V := Reverse_Cons ( V ) ; -- TODO: GC
end if ;
Pop_Frame ( Interp ) ;
2014-01-08 14:59:48 +00:00
Chain_Frame_Result ( Interp , Interp . Stack , V ) ;
2014-01-07 17:02:12 +00:00
when Period_Token =>
2014-01-08 14:59:48 +00:00
V := Get_Frame_Result ( Interp . Stack ) ;
2014-01-07 17:02:12 +00:00
if V = Nil_Pointer then
-- . immediately after (
raise Syntax_Error ;
else
2014-01-08 07:18:14 +00:00
Set_Frame_Opcode ( Interp . Stack , Opcode_Read_List_Cdr ) ;
2014-01-07 17:02:12 +00:00
end if ;
2014-01-08 14:59:48 +00:00
when Single_Quote_Token =>
Push_Frame ( Interp , Opcode_Close_Quote , Nil_Pointer ) ;
Push_Frame ( Interp , Opcode_Read_Object , Nil_Pointer ) ;
when Integer_Token =>
-- TODO: bignum
V := String_To_Integer_Pointer ( Interp . Token . Value . Ptr . all ( 1. . Interp . Token . Value . Last ) ) ;
Chain_Frame_Result ( Interp , Interp . Stack , V ) ;
2014-01-07 17:02:12 +00:00
when String_Token =>
V := Make_String ( Interp . Self , Interp . Token . Value . Ptr . all ( 1. . Interp . Token . Value . Last ) ) ;
-- TODO: make V gc-aware
2014-01-08 14:59:48 +00:00
Chain_Frame_Result ( Interp , Interp . Stack , V ) ;
2014-01-07 17:02:12 +00:00
when Identifier_Token =>
V := Make_Symbol ( Interp . Self , Interp . Token . Value . Ptr . all ( 1. . Interp . Token . Value . Last ) ) ;
-- TODO: make V gc-aware
2014-01-08 14:59:48 +00:00
Chain_Frame_Result ( Interp , Interp . Stack , V ) ;
2014-01-07 17:02:12 +00:00
when others =>
-- TODO: set various error info
raise Syntax_Error ;
end case ;
end Read_List ;
2014-01-08 07:18:14 +00:00
procedure Read_List_Cdr is
2014-01-08 14:59:48 +00:00
pragma Inline ( Read_List_Cdr ) ;
2014-01-08 07:18:14 +00:00
V : Object_Pointer ;
begin
-- This procedure reads the first token after a period has been read.
-- It transfers the control over to Read_List_End once it has read
-- and processed the token. It chains the value made of the token
-- to the front of the frame's return value list expecting Read_List_End
2014-01-08 14:59:48 +00:00
-- to handle the head item specially.
2014-01-08 07:18:14 +00:00
Fetch_Token ;
case Interp . Token . Kind is
when End_Token =>
Ada . Text_IO . Put_Line ( "ERROR: PREMATURE LIST END" ) ;
raise Syntax_Error ;
when Left_Parenthesis_Token =>
Set_Frame_Opcode ( Interp . Stack , Opcode_Read_List_End ) ;
Push_Frame ( Interp , Opcode_Read_List , Nil_Pointer ) ;
2014-01-08 14:59:48 +00:00
when Single_Quote_Token =>
Ada . Text_IO . Put_Line ( "ERROR: CDR QUOT LIST END" ) ;
Set_Frame_Opcode ( Interp . Stack , Opcode_Read_List_End ) ;
Push_Frame ( Interp , Opcode_Close_Quote , Nil_Pointer ) ;
Push_Frame ( Interp , Opcode_Read_Object , Nil_Pointer ) ;
when Integer_Token =>
-- TODO: bignum
V := String_To_Integer_Pointer ( Interp . Token . Value . Ptr . all ( 1. . Interp . Token . Value . Last ) ) ;
Set_Frame_Opcode ( Interp . Stack , Opcode_Read_List_End ) ;
Chain_Frame_Result ( Interp , Interp . Stack , V ) ;
2014-01-08 07:18:14 +00:00
when String_Token =>
V := Make_String ( Interp . Self , Interp . Token . Value . Ptr . all ( 1. . Interp . Token . Value . Last ) ) ;
-- TODO: make V gc-aware
Set_Frame_Opcode ( Interp . Stack , Opcode_Read_List_End ) ;
2014-01-08 14:59:48 +00:00
Chain_Frame_Result ( Interp , Interp . Stack , V ) ;
2014-01-08 07:18:14 +00:00
when Identifier_Token =>
V := Make_Symbol ( Interp . Self , Interp . Token . Value . Ptr . all ( 1. . Interp . Token . Value . Last ) ) ;
-- TODO: make V gc-aware
Set_Frame_Opcode ( Interp . Stack , Opcode_Read_List_End ) ;
2014-01-08 14:59:48 +00:00
Chain_Frame_Result ( Interp , Interp . Stack , V ) ;
2014-01-08 07:18:14 +00:00
when others =>
-- TODO: set various error info
raise Syntax_Error ;
end case ;
end Read_List_Cdr ;
procedure Read_List_End is
2014-01-08 14:59:48 +00:00
pragma Inline ( Read_List_End ) ;
2014-01-08 07:18:14 +00:00
V : Object_Pointer ;
begin
Fetch_Token ;
case Interp . Token . Kind is
when Right_Parenthesis_Token =>
2014-01-08 14:59:48 +00:00
V := Get_Frame_Result ( Interp . Stack ) ;
2014-01-08 07:18:14 +00:00
pragma Assert ( V / = Nil_Pointer ) ;
-- The first item in the chain is actually Cdr of the last cell.
V := Reverse_Cons ( Get_Cdr ( V ) , Get_Car ( V ) ) ; -- TODO: GC
Pop_Frame ( Interp ) ;
2014-01-08 14:59:48 +00:00
Chain_Frame_Result ( Interp , Interp . Stack , V ) ;
2014-01-08 07:18:14 +00:00
when others =>
raise Syntax_Error ;
end case ;
end Read_List_End ;
2014-01-07 17:02:12 +00:00
procedure Close_List is
2014-01-08 14:59:48 +00:00
pragma Inline ( Close_List ) ;
2014-01-07 17:02:12 +00:00
V : Object_Pointer ;
begin
2014-01-08 14:59:48 +00:00
V := Get_Frame_Result ( Interp . Stack ) ;
2014-01-07 17:02:12 +00:00
pragma Assert ( Get_Cdr ( V ) = Nil_Pointer ) ;
Pop_Frame ( Interp ) ; -- Done with the current frame
2014-01-08 14:59:48 +00:00
Chain_Frame_Result ( Interp , Interp . Stack , Get_Car ( V ) ) ;
2014-01-07 17:02:12 +00:00
end Close_List ;
2014-01-08 14:59:48 +00:00
procedure Close_Quote is
pragma Inline ( Close_Quote ) ;
V : Object_Pointer ;
begin
-- TODO: use Interp.Quote_Syntax instead of Make_Symbol("quote")
2014-01-09 15:32:36 +00:00
Chain_Frame_Result ( Interp , Interp . Stack , Make_Symbol ( Interp . Self , Label_Quote ) ) ;
2014-01-08 14:59:48 +00:00
V := Get_Frame_Result ( Interp . Stack ) ;
Pop_Frame ( Interp ) ; -- Done with the current frame
Chain_Frame_Result ( Interp , Interp . Stack , V ) ;
end Close_Quote ;
2013-12-28 16:52:31 +00:00
procedure Read_Object is
2014-01-08 14:59:48 +00:00
pragma Inline ( Read_Object ) ;
2014-01-07 17:02:12 +00:00
V : Object_Pointer ;
2013-12-28 16:52:31 +00:00
begin
2014-01-07 17:02:12 +00:00
Fetch_Token ;
case Interp . Token . Kind is
when End_Token =>
Ada . Text_IO . Put_Line ( "INFO: NO MORE TOKEN " ) ;
raise Stream_End_Error ;
when Left_Parenthesis_Token =>
Set_Frame_Opcode ( Interp . Stack , Opcode_Close_List ) ;
Push_Frame ( Interp , Opcode_Read_List , Nil_Pointer ) ;
2014-01-08 14:59:48 +00:00
when Single_Quote_Token =>
Set_Frame_Opcode ( Interp . Stack , Opcode_Close_Quote ) ;
Push_Frame ( Interp , Opcode_Read_Object , Nil_Pointer ) ;
when Integer_Token =>
-- TODO: bignum
V := String_To_Integer_Pointer ( Interp . Token . Value . Ptr . all ( 1. . Interp . Token . Value . Last ) ) ;
Pop_Frame ( Interp ) ; -- Done with the current frame
Chain_Frame_Result ( Interp , Interp . Stack , V ) ;
2014-01-07 17:02:12 +00:00
when String_Token =>
V := Make_String ( Interp . Self , Interp . Token . Value . Ptr . all ( 1. . Interp . Token . Value . Last ) ) ;
-- TODO: make V gc-aware
Pop_Frame ( Interp ) ; -- Done with the current frame
2014-01-08 14:59:48 +00:00
Chain_Frame_Result ( Interp , Interp . Stack , V ) ;
2014-01-07 17:02:12 +00:00
when Identifier_Token =>
V := Make_Symbol ( Interp . Self , Interp . Token . Value . Ptr . all ( 1. . Interp . Token . Value . Last ) ) ;
-- TODO: make V gc-aware
Pop_Frame ( Interp ) ; -- Done with the current frame
2014-01-08 14:59:48 +00:00
Chain_Frame_Result ( Interp , Interp . Stack , V ) ;
2014-01-07 17:02:12 +00:00
when others =>
-- TODO: set various error info
raise Syntax_Error ;
end case ;
2013-12-28 16:52:31 +00:00
end Read_Object ;
2013-12-17 16:04:55 +00:00
begin
2013-12-19 13:54:47 +00:00
-- Stack frames looks like this upon initialization
--
2014-01-08 14:59:48 +00:00
-- | Opcode | Operand | Result
2013-12-19 13:54:47 +00:00
-- -----------------------------------------------------------------
-- 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.
-- -----------------------------------------------------------------
2014-01-07 17:02:12 +00:00
-- top/bottom| Opcode_Exit | Nil | (3)
2013-12-19 13:54:47 +00:00
2014-01-07 17:02:12 +00:00
-- The caller must push some frames before calling this procedure
pragma Assert ( Interp . Stack / = Nil_Pointer ) ;
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-28 16:52:31 +00:00
when Opcode_Exit =>
exit ;
2014-01-08 14:59:48 +00:00
when Opcode_Evaluate_Result =>
Evaluate_Result ;
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_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
2013-12-28 16:52:31 +00:00
when Opcode_Read_Object =>
Read_Object ;
2014-01-07 17:02:12 +00:00
when Opcode_Read_List =>
Read_List ;
2014-01-08 07:18:14 +00:00
when Opcode_Read_List_Cdr =>
Read_List_Cdr ;
when Opcode_Read_List_End =>
Read_List_End ;
2014-01-07 17:02:12 +00:00
when Opcode_Close_List =>
Close_List ;
2014-01-08 07:18:14 +00:00
2014-01-08 14:59:48 +00:00
when Opcode_Close_Quote =>
Close_Quote ;
2013-12-17 16:04:55 +00:00
end case ;
end loop ;
-- the stack must be empty when the loop is terminated
2014-01-07 17:02:12 +00:00
--pragma Assert (Interp.Stack = Nil_Pointer);
2013-12-21 04:57:44 +00:00
exception
2014-01-07 17:02:12 +00:00
when Stream_End_Error =>
raise ;
2013-12-21 04:57:44 +00:00
when others =>
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put_Line ( "EXCEPTION OCCURRED" ) ;
2013-12-21 04:57:44 +00:00
-- TODO: restore stack frame???
-- TODO: restore envirronemtn frame???
2014-01-07 17:02:12 +00:00
raise ;
end Execute ;
procedure Evaluate ( Interp : in out Interpreter_Record ;
Source : in Object_Pointer ;
Result : out Object_Pointer ) is
begin
pragma Assert ( Interp . Stack = Nil_Pointer ) ;
Interp . Stack := Nil_Pointer ;
-- Push a pseudo-frame to terminate the evaluation loop
Push_Frame ( Interp , Opcode_Exit , Nil_Pointer ) ;
-- Push the actual frame for evaluation
Push_Frame ( Interp , Opcode_Evaluate_Object , Source ) ;
Execute ( Interp ) ;
pragma Assert ( Get_Frame_Opcode ( Interp . Stack ) = Opcode_Exit ) ;
2014-01-08 14:59:48 +00:00
Result := Get_Frame_Result ( Interp . Stack ) ;
2014-01-07 17:02:12 +00:00
-- There must be only 1 value chained to the top-level frame
-- once evaluation is over.
pragma Assert ( Get_Cdr ( Result ) = Nil_Pointer ) ;
-- Get the only value chained
Result := Get_Car ( Result ) ;
Pop_Frame ( Interp ) ;
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-28 16:52:31 +00:00
procedure Run_Loop ( Interp : in out Interpreter_Record ;
2014-01-07 17:02:12 +00:00
Result : out Object_Pointer ) is
2013-12-28 16:52:31 +00:00
-- standard read-eval-print loop
begin
2014-01-07 17:02:12 +00:00
Result := Nil_Pointer ;
loop
pragma Assert ( Interp . Stack = Nil_Pointer ) ;
Interp . Stack := Nil_Pointer ;
Push_Frame ( Interp , Opcode_Exit , Nil_Pointer ) ;
2014-01-08 14:59:48 +00:00
--Push_Frame (Interp, Opcode_Print_Result, Nil_Pointer);
Push_Frame ( Interp , Opcode_Evaluate_Result , Nil_Pointer ) ;
2014-01-07 17:02:12 +00:00
Push_Frame ( Interp , Opcode_Read_Object , Nil_Pointer ) ;
Execute ( Interp ) ;
pragma Assert ( Get_Frame_Opcode ( Interp . Stack ) = Opcode_Exit ) ;
-- TODO: this result must be kept at some where that GC dowsn't sweep.
2014-01-08 14:59:48 +00:00
Result := Get_Frame_Result ( Interp . Stack ) ;
2014-01-07 17:02:12 +00:00
pragma Assert ( Get_Cdr ( Result ) = Nil_Pointer ) ;
Result := Get_Car ( Result ) ;
Pop_Frame ( Interp ) ;
Ada . Text_IO . Put ( "REsULT>>>>>" ) ;
Print ( Interp , Result ) ;
pragma Assert ( Interp . Stack = Nil_Pointer ) ;
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put_Line ( ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> LOOP ITERATION XXXXXX CHECKPOINT" ) ;
2014-01-07 17:02:12 +00:00
end loop ;
exception
when Stream_End_Error =>
-- this is not a real error. this indicates the end of input stream.
2014-01-09 15:32:36 +00:00
Ada . Text_IO . Put_LINE ( "=== BYE ===" ) ;
2014-01-07 17:02:12 +00:00
when others =>
2014-01-09 15:32:36 +00:00
Ada . TEXT_IO . PUT_LINE ( "ERROR ERROR ERROR" ) ;
2014-01-07 17:02:12 +00:00
raise ;
2013-12-28 16:52:31 +00:00
end Run_Loop ;
2013-12-21 04:57:44 +00:00
-----------------------------------------------------------------------------
2014-01-09 15:32:36 +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-19 14:36:14 +00:00
2013-12-10 16:14:06 +00:00
end H2.Scheme ;