805 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			Ada
		
	
	
	
	
	
			
		
		
	
	
			805 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			Ada
		
	
	
	
	
	
| 
 | |
| separate (H2.Scheme.Execute)
 | |
| 
 | |
| procedure Apply is
 | |
| 	--pragma Inline (Apply);
 | |
| 
 | |
| 	Func: aliased Object_Pointer;
 | |
| 	Args: aliased Object_Pointer;
 | |
| 
 | |
| 	-- -------------------------------------------------------------
 | |
| 	-- Questioning procedures
 | |
| 	-- -------------------------------------------------------------
 | |
| 	generic 
 | |
| 		with function Question (X: in Object_Pointer) return Standard.Boolean;
 | |
| 	procedure Apply_Question_Procedure;
 | |
| 
 | |
| 	procedure Apply_Question_Procedure is
 | |
| 		Bool: Object_Pointer;
 | |
| 	begin
 | |
| 		if Is_Cons(Args) and then not Is_Cons(Get_Cdr(Args)) then
 | |
| 			-- 1 actual argument
 | |
| 			if Question(Get_Car(Args)) then
 | |
| 				Bool := True_Pointer;
 | |
| 			else
 | |
| 				Bool := False_Pointer;
 | |
| 			end if;
 | |
| 			Return_Frame (Interp, Bool);
 | |
| 		else
 | |
| Ada.Text_IO.Put_line ("WRONG NUMBER OF ARGUMETNS FOR COMPARISON");
 | |
| 			raise Syntax_Error;
 | |
| 		end if;
 | |
| 	end Apply_Question_Procedure;
 | |
| 	
 | |
| 
 | |
| 	function Is_Number_Class (X: in Object_Pointer) return Standard.Boolean is
 | |
| 		pragma Inline (Is_Number_Class);
 | |
| 	begin
 | |
| 		return Is_Integer(X); -- TODO bignum
 | |
| 	end Is_Number_Class;
 | |
| 
 | |
| 	function Is_Procedure_Class (X: in Object_Pointer) return Standard.Boolean is
 | |
| 		pragma Inline (Is_Procedure_Class);
 | |
| 	begin
 | |
| 		return Is_Closure(X) or else Is_Procedure(X) or else Is_Continuation(X);
 | |
| 	end Is_Procedure_Class;
 | |
| 
 | |
| 	procedure Apply_Q_Number_Procedure is new Apply_Question_Procedure (Is_Number_Class);	
 | |
| 	procedure Apply_Q_Procedure_Procedure is new Apply_Question_Procedure (Is_Procedure_Class);
 | |
| 	
 | |
| 	
 | |
| 	-- -------------------------------------------------------------
 | |
| 	-- Boolean procedures
 | |
| 	-- -------------------------------------------------------------
 | |
| 	procedure Apply_Not_Procedure is
 | |
| 		Ptr: Object_Pointer;
 | |
| 	begin
 | |
| 		-- (not obj)
 | |
| 		-- 'not' returns #t if obj is false, and returns #f otherwise.
 | |
| 		--   (not #t) ; #f
 | |
| 		--   (not 0) ; #f
 | |
| 		--   (not #f) ; #t
 | |
| 		
 | |
| 		if not Is_Cons(Args) or else Get_Cdr(Args) /= Nil_Pointer then
 | |
| Ada.Text_IO.Put_Line ("WRONG NUMBER OF ARGUMETNS FOR NOT?"); 
 | |
| 			raise Syntax_Error;
 | |
| 		end if;
 | |
| 
 | |
| 		Ptr := Get_Car(Args);
 | |
| 		if Is_True_Class(Ptr) then
 | |
| 			Ptr := False_Pointer;
 | |
| 		else
 | |
| 			Ptr := True_Pointer;
 | |
| 		end if;
 | |
| 		Return_Frame (Interp, Ptr);
 | |
| 	end Apply_Not_Procedure;
 | |
| 
 | |
| 	procedure Apply_Q_Boolean_Procedure is
 | |
| 		Ptr: Object_Pointer;
 | |
| 	begin
 | |
| 		-- (boolean? obj)
 | |
| 		-- it returns #t if obj is either #t or #f and 
 | |
| 		-- returns #f otherwise.
 | |
| 		--  (boolean? #f) ; #t
 | |
| 		--  (boolean? 0)  ; #f
 | |
| 
 | |
| 		if not Is_Cons(Args) or else Get_Cdr(Args) /= Nil_Pointer then
 | |
| Ada.Text_IO.Put_Line ("WRONG NUMBER OF ARGUMETNS FOR BOOLEAN?"); 
 | |
| 			raise Syntax_Error;
 | |
| 		end if;
 | |
| 
 | |
| 		Ptr := Get_Car(Args);
 | |
| 		if Ptr = True_Pointer or else Ptr = False_Pointer then
 | |
| 			Ptr := True_Pointer;
 | |
| 		else
 | |
| 			Ptr := False_Pointer;
 | |
| 		end if;
 | |
| 		Return_Frame (Interp, Ptr);
 | |
| 	end Apply_Q_Boolean_Procedure;
 | |
| 
 | |
| 	-- -------------------------------------------------------------
 | |
| 	-- Equivalence predicates
 | |
| 	-- -------------------------------------------------------------
 | |
| 	procedure Apply_Q_Eq_Procedure is
 | |
| 		Ptr: Object_Pointer;
 | |
| 	begin
 | |
| 		if not Is_Cons(Args) or else Get_Cdr(Args) = Nil_Pointer or else Get_Cdr(Get_Cdr(Args)) /= Nil_Pointer then
 | |
| Ada.Text_IO.Put_Line ("WRONG NUMBER OF ARGUMETNS FOR EQ?"); 
 | |
| 			raise Syntax_Error;
 | |
| 		end if;
 | |
| 		if Get_Car(Args) = Get_Car(Get_Cdr(Args)) then
 | |
| 			Ptr := True_Pointer;
 | |
| 		else
 | |
| 			Ptr := False_Pointer;
 | |
| 		end if;
 | |
| 		Return_Frame (Interp, Ptr);
 | |
| 	end Apply_Q_Eq_Procedure;
 | |
| 
 | |
| 	procedure Apply_Q_Eqv_Procedure is
 | |
| 		Ptr: Object_Pointer;
 | |
| 	begin
 | |
| 		if not Is_Cons(Args) or else Get_Cdr(Args) = Nil_Pointer or else Get_Cdr(Get_Cdr(Args)) /= Nil_Pointer then
 | |
| Ada.Text_IO.Put_Line ("WRONG NUMBER OF ARGUMETNS FOR EQV?"); 
 | |
| 			raise Syntax_Error;
 | |
| 		end if;
 | |
| 
 | |
| 		if Equal_Values(Get_Car(Args), Get_Car(Get_Cdr(Args))) then
 | |
| 			Ptr := True_Pointer;
 | |
| 		else
 | |
| 			Ptr := False_Pointer;
 | |
| 		end if;
 | |
| 		Return_Frame (Interp, Ptr);
 | |
| 	end Apply_Q_Eqv_Procedure;
 | |
| 	
 | |
| 	-- -------------------------------------------------------------
 | |
| 	-- List manipulation procedures
 | |
| 	-- -------------------------------------------------------------
 | |
| 	function Is_Null_Class (X: in Object_Pointer) return Standard.Boolean is
 | |
| 		pragma Inline (Is_Null_Class);
 | |
| 	begin
 | |
| 		return X = Nil_Pointer;
 | |
| 	end Is_Null_Class;
 | |
| 
 | |
| 	function Is_Pair_Class (X: in Object_Pointer) return Standard.Boolean is
 | |
| 		pragma Inline (Is_Pair_Class);
 | |
| 	begin
 | |
| 		return Is_Cons(X);
 | |
| 	end Is_Pair_Class;
 | |
| 	
 | |
| 	procedure Apply_Q_Null_Procedure is new Apply_Question_Procedure (Is_Null_Class);
 | |
| 	procedure Apply_Q_Pair_Procedure is new Apply_Question_Procedure (Is_Pair_Class);
 | |
| 
 | |
| 	procedure Apply_Car_Procedure is
 | |
| 		Ptr: Object_Pointer := Args;
 | |
| 		A: Object_Pointer;
 | |
| 	begin
 | |
| 		if not Is_Cons(Ptr) or else Get_Cdr(Ptr) /= Nil_Pointer then
 | |
| Ada.Text_IO.Put_Line ("WRONG NUMBER OF ARGUMETNS FOR CAR"); 
 | |
| 			raise Syntax_Error;
 | |
| 		end if;
 | |
| 
 | |
| 		A := Get_Car(Ptr); -- the first argument
 | |
| 		if not Is_Cons(A) then
 | |
| Ada.Text_IO.Put_Line ("EXPECTED CONS-CELL FOR CAR"); 
 | |
| 			raise Evaluation_Error;
 | |
| 		end if;
 | |
| 
 | |
| 		Return_Frame (Interp, Get_Car(A)); 
 | |
| 	end Apply_Car_Procedure;
 | |
| 
 | |
| 	procedure Apply_Cdr_Procedure is
 | |
| 		Ptr: Object_Pointer := Args;
 | |
| 		A: Object_Pointer;
 | |
| 	begin
 | |
| 		if not Is_Cons(Ptr) or else Get_Cdr(Ptr) /= Nil_Pointer then
 | |
| Ada.Text_IO.Put_Line ("WRONG NUMBER OF ARGUMETNS FOR CDR"); 
 | |
| 			raise Syntax_Error;
 | |
| 		end if;
 | |
| 
 | |
| 		A := Get_Car(Ptr); -- the first argument
 | |
| 		if not Is_Cons(A) then
 | |
| Ada.Text_IO.Put_Line ("EXPECTED CONS-CELL FOR CDR"); 
 | |
| 			raise Evaluation_Error;
 | |
| 		end if;
 | |
| 
 | |
| 		Return_Frame (Interp, Get_Cdr(A));
 | |
| 	end Apply_Cdr_Procedure;
 | |
| 
 | |
| 	procedure Apply_Cons_Procedure is
 | |
| 		Ptr: Object_Pointer := Args;
 | |
| 		A: Object_Pointer;
 | |
| 		B: Object_Pointer;
 | |
| 	begin
 | |
| 		if not Is_Cons(Ptr) or else not Is_Cons(Get_Cdr(Ptr)) or else Get_Cdr(Get_Cdr(Ptr)) /= Nil_Pointer  then
 | |
| Ada.Text_IO.Put_Line ("WRONG NUMBER OF ARGUMETNS FOR CONS"); 
 | |
| 			raise Syntax_Error;
 | |
| 		end if;
 | |
| 
 | |
| 		A := Get_Car(Ptr); -- the first argument
 | |
| 		B := Get_Car(Get_Cdr(Ptr)); -- the second argument
 | |
| 		Ptr := Make_Cons (Interp.Self, A, B); -- change car
 | |
| 
 | |
| 		Return_Frame (Interp, Ptr);
 | |
| 	end Apply_Cons_Procedure;
 | |
| 
 | |
| 	procedure Apply_Setcar_Procedure is
 | |
| 		Ptr: Object_Pointer := Args;
 | |
| 		A: Object_Pointer;
 | |
| 		B: Object_Pointer;
 | |
| 	begin
 | |
| 		if not Is_Cons(Ptr) or else not Is_Cons(Get_Cdr(Ptr)) or else Get_Cdr(Get_Cdr(Ptr)) /= Nil_Pointer  then
 | |
| Ada.Text_IO.Put_Line ("WRONG NUMBER OF ARGUMETNS FOR SET-CAR!"); 
 | |
| 			raise Syntax_Error;
 | |
| 		end if;
 | |
| 
 | |
| 		A := Get_Car(Ptr); -- the first argument
 | |
| 		if not Is_Cons(A) then
 | |
| Ada.Text_IO.Put_Line ("EXPECTED CONS-CELL FOR Setcar"); 
 | |
| 			raise Evaluation_Error;
 | |
| 		end if;
 | |
| 		B := Get_Car(Get_Cdr(Ptr)); -- the second argument
 | |
| 		Set_Car (A, B); -- change car
 | |
| 
 | |
| 		Return_Frame (Interp, A);
 | |
| 	end Apply_Setcar_Procedure;
 | |
| 
 | |
| 	procedure Apply_Setcdr_Procedure is
 | |
| 		Ptr: Object_Pointer := Args;
 | |
| 		A: Object_Pointer;
 | |
| 		B: Object_Pointer;
 | |
| 	begin
 | |
| 		if not Is_Cons(Ptr) or else not Is_Cons(Get_Cdr(Ptr)) or else Get_Cdr(Get_Cdr(Ptr)) /= Nil_Pointer  then
 | |
| Ada.Text_IO.Put_Line ("WRONG NUMBER OF ARGUMETNS FOR SET-CDR!"); 
 | |
| 			raise Syntax_Error;
 | |
| 		end if;
 | |
| 
 | |
| 		A := Get_Car(Ptr); -- the first argument
 | |
| 		if not Is_Cons(A) then
 | |
| Ada.Text_IO.Put_Line ("EXPECTED CONS-CELL FOR Setcdr"); 
 | |
| 			raise Evaluation_Error;
 | |
| 		end if;
 | |
| 		B := Get_Car(Get_Cdr(Ptr)); -- the second argument
 | |
| 		Set_Cdr (A, B); -- change cdr
 | |
| 
 | |
| 		Return_Frame (Interp, A);
 | |
| 	end Apply_Setcdr_Procedure;
 | |
| 
 | |
| 	-- -------------------------------------------------------------
 | |
| 	-- Symbol procedures
 | |
| 	-- -------------------------------------------------------------
 | |
| 	procedure Apply_Q_Symbol_Procedure is new Apply_Question_Procedure (Is_Symbol);
 | |
| 
 | |
| 	-- -------------------------------------------------------------
 | |
| 	-- String procedures
 | |
| 	-- -------------------------------------------------------------
 | |
| 	procedure Apply_Q_String_Procedure is new Apply_Question_Procedure (Is_String);
 | |
| 	
 | |
| 	procedure Apply_Q_String_EQ_Procedure is
 | |
| 		Ptr1: Object_Pointer;
 | |
| 		Ptr2: Object_Pointer;
 | |
| 	begin
 | |
| 		if not Is_Cons(Args) or else Get_Cdr(Args) = Nil_Pointer or else Get_Cdr(Get_Cdr(Args)) /= Nil_Pointer then
 | |
| Ada.Text_IO.Put_Line ("WRONG NUMBER OF ARGUMETNS FOR STRING=?"); 
 | |
| 			raise Syntax_Error;
 | |
| 		end if;
 | |
| 
 | |
| 		Ptr1 := Get_Car(Args);
 | |
| 		Ptr2 := Get_Car(Get_Cdr(Args));
 | |
| 		if not Is_String(Ptr1) or else not Is_String(Ptr2) then
 | |
| Ada.Text_IO.Put_Line ("STRING EXPECTED FOR STRING=?");
 | |
| 			raise Evaluation_Error;
 | |
| 		end if;
 | |
| 		
 | |
| 		if Ptr1.Character_Slot = Ptr2.Character_Slot then
 | |
| 			Ptr1 := True_Pointer;
 | |
| 		else
 | |
| 			Ptr1 := False_Pointer;
 | |
| 		end if;
 | |
| 		
 | |
| 		Return_Frame (Interp, Ptr1);
 | |
| 	end Apply_Q_String_EQ_Procedure;
 | |
| 	
 | |
| 	-- -------------------------------------------------------------
 | |
| 	-- Arithmetic procedures
 | |
| 	-- -------------------------------------------------------------
 | |
| 	
 | |
| 	function Is_Numeric (X: in Object_Pointer) return Standard.Boolean is
 | |
| 		pragma Inline (Is_Numeric);
 | |
| 	begin
 | |
| 		return Is_Integer(X) or else Is_Bigint(X);
 | |
| 	end Is_Numeric;
 | |
| 	
 | |
| 	procedure Apply_Add_Procedure is
 | |
| 		Ptr: aliased Object_Pointer := Args;
 | |
| 		Num: Object_Pointer;
 | |
| 		Car: Object_Pointer;
 | |
| 	begin
 | |
| 		Push_Top (Interp, Ptr'Unchecked_Access);
 | |
| 		
 | |
| 		Num := Integer_To_Pointer(0);
 | |
| 		while Is_Cons(Ptr) loop
 | |
| 			Car := Get_Car(Ptr);
 | |
| 			Ptr := Get_Cdr(Ptr);
 | |
| 			
 | |
| 			if not Is_Numeric(Car) then
 | |
| Ada.Text_IO.Put ("NOT NUMERIC FOR ADD"); Print (Interp, Car);
 | |
| 				raise Evaluation_Error;
 | |
| 			end if;
 | |
| 			Bigint.Add (Interp, Num, Car, Num);
 | |
| 		end loop;
 | |
| 
 | |
| 		Pop_Tops (Interp, 1);
 | |
| 		Return_Frame (Interp, Num);
 | |
| 	end Apply_Add_Procedure;
 | |
| 
 | |
| 	procedure Apply_Subtract_Procedure is
 | |
| 		Ptr: aliased Object_Pointer := Args;
 | |
| 		Num: Object_Pointer;
 | |
| 		Car: Object_Pointer;
 | |
| 	begin
 | |
| 		if Is_Cons(Ptr) then
 | |
| 			Push_Top (Interp, Ptr'Unchecked_Access);
 | |
| 			
 | |
| 			Car := Get_Car(Ptr);
 | |
| 			Ptr := Get_Cdr(Ptr);
 | |
| 			if not Is_Numeric(Car) then
 | |
| 				raise Evaluation_Error;
 | |
| 			end if;
 | |
| 			Num := Car;
 | |
| 
 | |
| 			while Is_Cons(Ptr) loop
 | |
| 				Car := Get_Car(Ptr);
 | |
| 				Ptr := Get_Cdr(Ptr);
 | |
| 				if not Is_Numeric(Car) then
 | |
| 					raise Evaluation_Error;
 | |
| 				end if;
 | |
| 				Bigint.Subtract (Interp, Num, Car, Num);
 | |
| 			end loop;
 | |
| 			
 | |
| 			Pop_Tops (Interp, 1);
 | |
| 		else
 | |
| Ada.Text_IO.Put_line ("NO ARGUMETNS FOR SUBNTRATION");
 | |
| 			raise Evaluation_Error;
 | |
| 		end if;
 | |
| 
 | |
| 		Return_Frame (Interp, Num);
 | |
| 	end Apply_Subtract_Procedure;
 | |
| 
 | |
| 	procedure Apply_Multiply_Procedure is
 | |
| 		Ptr: aliased Object_Pointer := Args;
 | |
| 		Num: Object_Pointer;
 | |
| 		Car: Object_Pointer;
 | |
| 	begin
 | |
| 		Push_Top (Interp, Ptr'Unchecked_Access);
 | |
| 		
 | |
| 		Num := Integer_To_Pointer(1);
 | |
| 		while Is_Cons(Ptr) loop
 | |
| 			Car := Get_Car(Ptr);
 | |
| 			Ptr := Get_Cdr(Ptr);
 | |
| 			if not Is_Numeric(Car) then
 | |
| Ada.Text_IO.Put ("NOT NUMERIC FOR MULTIPLY"); Print (Interp, Car);
 | |
| 				raise Evaluation_Error;
 | |
| 			end if;
 | |
| 			Bigint.Multiply (Interp, Num, Car, Num);
 | |
| 		end loop;
 | |
| 
 | |
| 		Pop_Tops (Interp, 1);
 | |
| 		Return_Frame (Interp, Num);
 | |
| 	end Apply_Multiply_Procedure;
 | |
| 
 | |
| 	procedure Apply_Quotient_Procedure is
 | |
| 		Ptr: aliased Object_Pointer := Args;
 | |
| 		Num: Object_Pointer;
 | |
| 		Car: Object_Pointer;
 | |
| 		Rmn: Object_Pointer;
 | |
| 	begin
 | |
| 		if Is_Cons(Ptr) then
 | |
| 			Push_Top (Interp, Ptr'Unchecked_Access);
 | |
| 			
 | |
| 			Car := Get_Car(Ptr);
 | |
| 			Ptr := Get_Cdr(Ptr);
 | |
| 			if not Is_Numeric(Car) then
 | |
| 				raise Evaluation_Error;
 | |
| 			end if;
 | |
| 			Num := Car;
 | |
| 			
 | |
| 			while Is_Cons(Ptr) loop
 | |
| 				-- TODO: check if car is an integer or bignum or something else.
 | |
| 				--       if something else, error
 | |
| 				Car := Get_Car(Ptr);
 | |
| 				Ptr := Get_Cdr(Ptr);
 | |
| 				if not Is_Numeric(Car) then
 | |
| 	Ada.Text_IO.Put ("NOT INTEGER FOR QUOTIENT"); Print (Interp, Car);
 | |
| 					raise Evaluation_Error;
 | |
| 				end if;
 | |
| 				Bigint.Divide (Interp, Num, Car, Num, Rmn);
 | |
| 			end loop;
 | |
| 			
 | |
| 			Pop_Tops (Interp, 1);
 | |
| 		else
 | |
| 			Ada.Text_IO.Put_line ("NO ARGUMETNS FOR QUOTIENT");
 | |
| 			raise Evaluation_Error;
 | |
| 		end if;
 | |
| 		
 | |
| 		Return_Frame (Interp, Num);
 | |
| 	end Apply_Quotient_Procedure;
 | |
| 	
 | |
| 	procedure Apply_Remainder_Procedure is
 | |
| 		Ptr: aliased Object_Pointer := Args;
 | |
| 		Num: Object_Pointer;
 | |
| 		Car: Object_Pointer;
 | |
| 		Quo: Object_Pointer;
 | |
| 	begin
 | |
| 		if Is_Cons(Ptr) then
 | |
| 			Push_Top (Interp, Ptr'Unchecked_Access);
 | |
| 			
 | |
| 			Car := Get_Car(Ptr);
 | |
| 			Ptr := Get_Cdr(Ptr);
 | |
| 			if not Is_Numeric(Car) then
 | |
| 				raise Evaluation_Error;
 | |
| 			end if;
 | |
| 			Num := Car;
 | |
| 			
 | |
| 			while Is_Cons(Ptr) loop
 | |
| 				-- TODO: check if car is an integer or bignum or something else.
 | |
| 				--       if something else, error
 | |
| 				Car := Get_Car(Ptr);
 | |
| 				Ptr := Get_Cdr(Ptr);
 | |
| 				if not Is_Numeric(Car) then
 | |
| 	Ada.Text_IO.Put ("NOT INTEGER FOR QUOTIENT"); Print (Interp, Car);
 | |
| 					raise Evaluation_Error;
 | |
| 				end if;
 | |
| 				Bigint.Divide (Interp, Num, Car, Quo, Num);
 | |
| 			end loop;
 | |
| 			
 | |
| 			Pop_Tops (Interp, 1);
 | |
| 		else
 | |
| 			Ada.Text_IO.Put_line ("NO ARGUMETNS FOR QUOTIENT");
 | |
| 			raise Evaluation_Error;
 | |
| 		end if;
 | |
| 		
 | |
| 		Return_Frame (Interp, Num);
 | |
| 	end Apply_Remainder_Procedure;
 | |
| 
 | |
| 	-- -------------------------------------------------------------
 | |
| 	-- Comparions procedures
 | |
| 	-- -------------------------------------------------------------
 | |
| 
 | |
| 	generic 
 | |
| 		with function Validate (X: in Object_Pointer;
 | |
| 		                        Y: in Object_Pointer) return Standard.Boolean;
 | |
| 		                        
 | |
| 		with function Compare (X: in Object_Pointer;
 | |
| 		                       Y: in Object_Pointer) return Standard.Boolean;
 | |
| 	procedure Apply_Compare_Procedure;
 | |
| 
 | |
| 	procedure Apply_Compare_Procedure is
 | |
| 		Ptr: Object_Pointer := Args;
 | |
| 		X: Object_Pointer;
 | |
| 		Y: Object_Pointer;
 | |
| 		Bool: Object_Pointer := True_Pointer;
 | |
| 	begin
 | |
| 		if Is_Cons(Ptr) and then Is_Cons(Get_Cdr(Ptr)) then
 | |
| 			-- at least 2 actual arguments
 | |
| 			X := Get_Car(Ptr);
 | |
| 			
 | |
| 			Ptr := Get_Cdr(Ptr);
 | |
| 			while Is_Cons(Ptr) loop
 | |
| 				Y := Get_Car(Ptr);
 | |
| 
 | |
| 				if not Validate(X, Y) then
 | |
| 					ADA.TEXT_IO.PUT_LINE ("INVALID TYPE FOR COMPARISION");
 | |
| 					raise Evaluation_Error;
 | |
| 				end if;
 | |
| 
 | |
| 				if not Compare(X, Y) then
 | |
| 					Bool := False_Pointer;
 | |
| 					exit;
 | |
| 				end if;
 | |
| 
 | |
| 				X := Y;
 | |
| 				Ptr := Get_Cdr(Ptr);
 | |
| 			end loop;
 | |
| 
 | |
| 			Return_Frame (Interp, Bool);
 | |
| 		else
 | |
| Ada.Text_IO.Put_line ("TOO FEW ARGUMETNS FOR COMPARISON");
 | |
| 			raise Syntax_Error;
 | |
| 		end if;
 | |
| 	end Apply_Compare_Procedure;
 | |
| 
 | |
| 	function Validate_Numeric (X: in Object_Pointer; 
 | |
| 	                           Y: in Object_Pointer) return Standard.Boolean is
 | |
| 	begin
 | |
| 		return Is_Numeric(X) and then Is_Numeric(Y);
 | |
| 	end Validate_Numeric;
 | |
| 
 | |
| 	function Equal_To (X: in Object_Pointer;
 | |
| 	                   Y: in Object_Pointer) return Standard.Boolean is
 | |
| 	begin
 | |
| 		return Bigint.Compare (Interp.Self, X, Y) = 0;
 | |
| 	end Equal_To;
 | |
| 
 | |
| 	function Greater_Than (X: in Object_Pointer;
 | |
| 	                       Y: in Object_Pointer) return Standard.Boolean is
 | |
| 	begin
 | |
| 		return Bigint.Compare (Interp.Self, X, Y) > 0;
 | |
| 	end Greater_Than;
 | |
| 
 | |
| 	function Less_Than (X: in Object_Pointer;
 | |
| 	                    Y: in Object_Pointer) return Standard.Boolean is
 | |
| 	begin
 | |
| 		return Bigint.Compare (Interp.Self, X, Y) < 0;
 | |
| 	end Less_Than;
 | |
| 
 | |
| 	function Greater_Or_Equal (X: in Object_Pointer;
 | |
| 	                           Y: in Object_Pointer) return Standard.Boolean is
 | |
| 	begin
 | |
| 		return Bigint.Compare (Interp.Self, X, Y) >= 0;
 | |
| 	end Greater_Or_Equal;
 | |
| 
 | |
| 	function Less_Or_Equal (X: in Object_Pointer;
 | |
| 	                        Y: in Object_Pointer) return Standard.Boolean is
 | |
| 	begin
 | |
| 		return Bigint.Compare (Interp.Self, X, Y) <= 0;
 | |
| 	end Less_Or_Equal;
 | |
| 
 | |
| 	procedure Apply_N_EQ_Procedure is new Apply_Compare_Procedure (Validate_Numeric, Equal_To);
 | |
| 	procedure Apply_N_GT_Procedure is new Apply_Compare_Procedure (Validate_Numeric, Greater_Than);
 | |
| 	procedure Apply_N_LT_Procedure is new Apply_Compare_Procedure (Validate_Numeric, Less_Than);
 | |
| 	procedure Apply_N_GE_Procedure is new Apply_Compare_Procedure (Validate_Numeric, Greater_Or_Equal);
 | |
| 	procedure Apply_N_LE_Procedure is new Apply_Compare_Procedure (Validate_Numeric, Less_Or_Equal);
 | |
| 
 | |
| 	-- -------------------------------------------------------------
 | |
| 	-- Closure
 | |
| 	-- -------------------------------------------------------------
 | |
| 	procedure Apply_Closure is
 | |
| 		Fbody: aliased Object_Pointer;
 | |
| 		Formal: aliased Object_Pointer;
 | |
| 		Actual: aliased Object_Pointer;
 | |
| 		Envir: aliased Object_Pointer;
 | |
| 	begin
 | |
| 		Push_Top (Interp, Fbody'Unchecked_Access);
 | |
| 		Push_Top (Interp, Formal'Unchecked_Access);
 | |
| 		Push_Top (Interp, Actual'Unchecked_Access);
 | |
| 		Push_Top (Interp, Envir'Unchecked_Access);
 | |
| 
 | |
| 		-- For a closure created of "(lambda (x y) (+ x y) (* x y))"
 | |
| 		-- Get_Closure_Code(Func) returns "((x y) (+ x y) (* x y))"
 | |
| 
 | |
| 		-- Create a new environment for the closure
 | |
| 		Envir := Make_Environment(Interp.Self, Get_Closure_Environment(Func));
 | |
| 		-- Update the environment of the frame to the one created above
 | |
| 		-- so as to put the arguments into the new environment.
 | |
| 		Set_Frame_Environment (Interp.Stack, Envir);
 | |
| 
 | |
| 		Fbody := Get_Closure_Code(Func);
 | |
| 		pragma Assert (Is_Cons(Fbody)); -- the lambda evaluator must ensure this.
 | |
| 
 | |
| 		Formal := Get_Car(Fbody); -- Formal argument list
 | |
| 		Actual := Args; -- Actual argument list
 | |
| 
 | |
| 		Fbody := Get_Cdr(Fbody); -- Real function body
 | |
| 		pragma Assert (Is_Cons(Fbody)); -- the lambda evaluator must ensure this.
 | |
| 
 | |
| 		if Is_Symbol(Formal) then
 | |
| 			-- Closure made of a lambda expression with a single formal argument
 | |
| 			-- e.g) (lambda x (car x))
 | |
| 			-- Apply the whole actual argument list to the closure.
 | |
| 			Set_Current_Environment (Interp, Formal, Actual);
 | |
| 		else
 | |
| 			while Is_Cons(Formal) loop
 | |
| 				if not Is_Cons(Actual) then
 | |
| 					Ada.Text_IO.Put_Line (">>>> TOO FEW ARGUMENTS FOR CLOSURE <<<<");	
 | |
| 					raise Evaluation_Error;
 | |
| 				end if;
 | |
| 
 | |
| 				-- Insert the key/value pair into the environment
 | |
| 				Set_Current_Environment (Interp, Get_Car(Formal), Get_Car(Actual));
 | |
| 
 | |
| 				Formal := Get_Cdr(Formal);
 | |
| 				Actual := Get_Cdr(Actual);
 | |
| 			end loop;
 | |
| 
 | |
| 			-- Perform cosmetic checks for the parameter list
 | |
| 			if Is_Symbol(Formal) then
 | |
| 				-- The last formal argument to the closure is in a CDR.
 | |
| 				-- Assign the remaining actual arguments to the last formal argument
 | |
| 				-- e.g) ((lambda (x y . z) z) 1 2 3 4 5)
 | |
| 				Set_Current_Environment (Interp, Formal, Actual);
 | |
| 			else
 | |
| 				-- The lambda evaluator must ensure all formal arguments are symbols.
 | |
| 				pragma Assert (Formal = Nil_Pointer); 
 | |
| 
 | |
| 				if Actual /= Nil_Pointer then	
 | |
| 					Ada.Text_IO.Put_Line (">>>> TOO MANY ARGUMETNS FOR CLOSURE  <<<<");	
 | |
| 					raise Evaluation_Error;
 | |
| 				end if;
 | |
| 			end if;
 | |
| 		end if;
 | |
| 			
 | |
| 		Switch_Frame (Interp.Stack, Opcode_Grouped_Call, Fbody, Nil_Pointer);
 | |
| 
 | |
| 		Pop_Tops (Interp, 4);
 | |
| 	end Apply_Closure;
 | |
| 
 | |
| 	-- -------------------------------------------------------------
 | |
| 	-- Continuation
 | |
| 	-- -------------------------------------------------------------
 | |
| 
 | |
| 	function Is_Callcc_Friendly (A: Object_Pointer) return Standard.Boolean is
 | |
| 		pragma Inline (Is_Callcc_Friendly);
 | |
| 	begin
 | |
| 		return Is_Closure(A) or else Is_Procedure(A) or else Is_Continuation(A);
 | |
| 	end Is_Callcc_Friendly;
 | |
| 
 | |
| 	procedure Apply_Callcc_Procedure is
 | |
| 		C: aliased Object_Pointer;
 | |
| 	begin
 | |
| 		-- (call-with-current-continuation proc) 
 | |
| 		-- where proc is a procedure accepting one argument.
 | |
| 		--
 | |
| 		--   (define f (lambda (return) (return 2) 3))
 | |
| 		--   (f (lambda (x) x)) ; 3
 | |
| 		--   (call-with-current-continuation f) ; 2
 | |
| 		--
 | |
| 		--   (call-with-current-continuation (lambda (return) (return 2) 3))
 | |
| 		--
 | |
| 		--   (define c (call-with-current-continuation call-with-current-continuation))
 | |
| 		--   c ; continuation
 | |
| 		--   (c (+ 1 2 3)) ; 6 becomes the result of the frame that continuation remembers.
 | |
| 		--                 ; subsequently, its parent frames are executed. 
 | |
| 		--   c ; 6
 | |
| 
 | |
| 		if not Is_Cons(Args) or else Get_Cdr(Args) /= Nil_Pointer then
 | |
| 			Ada.Text_IO.Put_Line ("WRONG NUMBER OF ARGUMETNS FOR CALL/CC"); 
 | |
| 			raise Syntax_Error;
 | |
| 		end if;
 | |
| 
 | |
| 		if not Is_Callcc_Friendly(Get_Car(Args)) then
 | |
| 			ada.text_io.put_line ("NON CLOSURE/PROCEDURE/CONTINUATION FOR CALL/CC");
 | |
| 			raise Syntax_Error;
 | |
| 		end if; 
 | |
| 
 | |
| 		Push_Top (Interp, C'Unchecked_Access); -- this is not needed. TOOD: remove this
 | |
| 		C := Make_Continuation (Interp.Self, Get_Frame_Parent(Interp.Stack));
 | |
| 
 | |
| 		Set_Frame_Opcode (Interp.Stack, Opcode_Apply);
 | |
| 		Set_Frame_Operand (Interp.Stack, Get_Car(Args)); -- (call/cc xxx), xxx becomes this.
 | |
| 		Set_Frame_Intermediate (Interp.Stack, Nil_Pointer); -- pass the continuation object
 | |
| 		Chain_Frame_Intermediate (Interp, Interp.Stack, C); -- as an actual parameter. (xxx #continuation)
 | |
| 		Clear_Frame_Result (Interp.Stack);
 | |
| 
 | |
| 		Pop_Tops (Interp, 1);
 | |
| 	end Apply_Callcc_Procedure;
 | |
| 
 | |
| 	procedure Apply_Continuation is
 | |
| 	begin
 | |
| --declare
 | |
| --w: object_word;
 | |
| --for w'address use func'address;
 | |
| --f: object_word;
 | |
| --for f'address use interp.stack'address;
 | |
| --begin
 | |
| --ada.text_io.put_line ("Frame" & object_word'image(f) & " " & Opcode_Type'Image(Get_Frame_Opcode(Interp.Stack)));
 | |
| --ada.text_io.put ("                      POPPING ...  APPLY CONTINUATION -->> ");
 | |
| --ada.text_io.put (object_word'image(w) & " ");
 | |
| --end;
 | |
| --Print (Interp, Args);
 | |
| --ada.text_io.put ("                      CURRENT FREME RESULT " );
 | |
| --Print (Interp, get_Frame_result(interp.stack));
 | |
| 		if not Is_Cons(Args) or else Get_Cdr(Args) /= Nil_Pointer then
 | |
| 			Ada.Text_IO.Put_Line ("WRONG NUMBER OF ARGUMETNS FOR CONTINUATION"); 
 | |
| 			raise Syntax_Error;
 | |
| 		end if;
 | |
| 
 | |
|           -- Restore the frame to the remembered one
 | |
| 		Interp.Stack := Get_Continuation_Frame(Func);
 | |
| 	
 | |
| --declare
 | |
| --f: object_word;
 | |
| --for f'address use interp.stack'address;
 | |
| --begin
 | |
| --ada.text_io.put_line ("                      SWITCHED STACK TO FREME " & object_word'image(f) );
 | |
| --ada.text_io.put ("                      CURRENT RESULT " );
 | |
| --print (interp, get_Frame_result(interp.stack));
 | |
| --ada.text_io.put ("                      CURRENT OPERAND " );
 | |
| --print (interp, get_Frame_operand(interp.stack));
 | |
| --ada.text_io.put ("                      CURRENT INTERMEDIATE " );
 | |
| --print (interp, get_Frame_intermediate(interp.stack));
 | |
| --ada.text_io.put_line ("                      CURRENT OPCODE " & opcode_type'image(get_Frame_opcode(interp.stack)));
 | |
| --end;
 | |
| 
 | |
| 		Set_Frame_Result (Interp.Stack, Get_Car(Args)); 
 | |
| 
 | |
| --ada.text_io.put ("                      FINAL RESULT ");
 | |
| --print (interp, get_Frame_result(interp.stack));
 | |
| 
 | |
| 	end Apply_Continuation;
 | |
| 
 | |
| begin
 | |
| 	Push_Top (Interp, Func'Unchecked_Access);
 | |
| 	Push_Top (Interp, Args'Unchecked_Access);
 | |
| 
 | |
| 	Func := Get_Frame_Operand(Interp.Stack);
 | |
| 	if not Is_Normal_Pointer(Func) then
 | |
| 		Ada.Text_IO.Put_Line ("INVALID FUNCTION TYPE");
 | |
| 		raise Evaluation_Error;
 | |
| 	end if;
 | |
| 
 | |
| 	Args := Get_Frame_Intermediate(Interp.Stack);
 | |
| 
 | |
| --declare
 | |
| --w: object_word;
 | |
| --for w'address use interp.stack'address;
 | |
| --begin
 | |
| --ada.text_io.put_line ("Frame" & object_word'image(w) & " " & Opcode_Type'Image(Get_Frame_Opcode(Interp.Stack)));
 | |
| --ada.text_io.put ("                      FUNCTION => ");
 | |
| --print (Interp, Func);
 | |
| --ada.text_io.put ("                      ARGUMENTS => ");
 | |
| --print (Interp, Args);
 | |
| --ada.text_io.put ("                      CURRENT RESULT => ");
 | |
| --print (Interp, get_frame_result(interp.stack));
 | |
| --end;
 | |
| 
 | |
| 
 | |
| 	case Func.Tag is
 | |
| 		when Procedure_Object => 
 | |
| 			case Get_Procedure_Opcode(Func) is
 | |
| 
 | |
| 				when Callcc_Procedure =>
 | |
| 					Apply_Callcc_Procedure;
 | |
| 				when Car_Procedure =>
 | |
| 					Apply_Car_Procedure;
 | |
| 				when Cdr_Procedure =>
 | |
| 					Apply_Cdr_Procedure;
 | |
| 				when Cons_Procedure =>
 | |
| 					Apply_Cons_Procedure;
 | |
| 				when Not_Procedure =>
 | |
| 					Apply_Not_Procedure;
 | |
| 
 | |
| 				when N_Add_Procedure =>
 | |
| 					Apply_Add_Procedure;
 | |
| 				when N_EQ_Procedure =>
 | |
| 					Apply_N_EQ_Procedure;
 | |
| 				when N_GT_Procedure =>
 | |
| 					Apply_N_GT_Procedure;
 | |
| 				when N_LT_Procedure =>
 | |
| 					Apply_N_LT_Procedure;
 | |
| 				when N_GE_Procedure =>
 | |
| 					Apply_N_GE_Procedure;
 | |
| 				when N_LE_Procedure =>
 | |
| 					Apply_N_LE_Procedure;
 | |
| 				when N_Multiply_Procedure =>
 | |
| 					Apply_Multiply_Procedure;
 | |
| 				when N_Quotient_Procedure =>
 | |
| 					Apply_Quotient_Procedure;
 | |
| 				when N_Remainder_Procedure =>
 | |
| 					Apply_Remainder_Procedure;
 | |
| 				when N_Subtract_Procedure =>
 | |
| 					Apply_Subtract_Procedure;
 | |
| 
 | |
| 				when Q_Boolean_Procedure =>
 | |
| 					Apply_Q_Boolean_Procedure;
 | |
| 				when Q_Eq_Procedure =>
 | |
| 					Apply_Q_Eq_Procedure;
 | |
| 				when Q_Eqv_Procedure =>
 | |
| 					Apply_Q_Eqv_Procedure;
 | |
| 
 | |
| 				when Q_Null_Procedure =>
 | |
| 					Apply_Q_Null_Procedure;
 | |
| 				when Q_Number_Procedure =>
 | |
| 					Apply_Q_Number_Procedure;
 | |
| 				when Q_Pair_Procedure =>
 | |
| 					Apply_Q_Pair_Procedure;
 | |
| 				when Q_Procedure_Procedure =>
 | |
| 					Apply_Q_Procedure_Procedure;
 | |
| 				when Q_String_Procedure =>
 | |
| 					Apply_Q_String_Procedure;
 | |
| 				when Q_String_EQ_Procedure =>
 | |
| 					Apply_Q_String_EQ_Procedure;
 | |
| 				when Q_Symbol_Procedure =>
 | |
| 					Apply_Q_Symbol_Procedure;
 | |
| 
 | |
| 				when Setcar_Procedure =>
 | |
| 					Apply_Setcar_Procedure;
 | |
| 				when Setcdr_Procedure =>
 | |
| 					Apply_Setcdr_Procedure;
 | |
| 
 | |
| 			end case;	
 | |
| 
 | |
| 		when Closure_Object =>
 | |
| 			Apply_Closure;
 | |
| 
 | |
| 		when Continuation_Object =>
 | |
| 			Apply_Continuation;
 | |
| 
 | |
| 		when others =>
 | |
| 			Ada.Text_IO.Put_Line ("INVALID FUNCTION TYPE");
 | |
| 			raise Internal_Error;
 | |
| 
 | |
| 	end case;
 | |
| 
 | |
| 	Pop_Tops (Interp, 2);
 | |
| end Apply;
 |