hcl/lib/h2-scheme-execute-apply.adb

593 lines
18 KiB
Ada
Raw Normal View History

separate (H2.Scheme.Execute)
procedure Apply is
--pragma Inline (Apply);
Operand: aliased Object_Pointer;
Func: aliased Object_Pointer;
Args: aliased Object_Pointer;
-- -------------------------------------------------------------
-- List manipulation procedures
-- -------------------------------------------------------------
procedure Apply_Car_Procedure is
Ptr: Object_Pointer := Args;
A: Object_Pointer;
begin
2014-01-21 10:12:15 +00:00
if not Is_Cons(Ptr) or else Get_Cdr(Ptr) /= Nil_Pointer then
2014-01-19 15:47:45 +00:00
Ada.Text_IO.Put_Line ("WRONG NUMBER OF ARGUMETNS FOR CAR");
raise Syntax_Error;
end if;
A := Get_Car(Ptr); -- the first argument
2014-01-21 10:12:15 +00:00
if not Is_Cons(A) then
Ada.Text_IO.Put_Line ("EXPECTED CONS-CELL FOR CAR");
raise Evaluation_Error;
end if;
Pop_Frame (Interp); -- Done with the current frame
Put_Frame_Result (Interp, Interp.Stack, Get_Car(A));
end Apply_Car_Procedure;
procedure Apply_Cdr_Procedure is
Ptr: Object_Pointer := Args;
A: Object_Pointer;
begin
2014-01-21 10:12:15 +00:00
if not Is_Cons(Ptr) or else Get_Cdr(Ptr) /= Nil_Pointer then
2014-01-19 15:47:45 +00:00
Ada.Text_IO.Put_Line ("WRONG NUMBER OF ARGUMETNS FOR CDR");
raise Syntax_Error;
end if;
A := Get_Car(Ptr); -- the first argument
2014-01-21 10:12:15 +00:00
if not Is_Cons(A) then
Ada.Text_IO.Put_Line ("EXPECTED CONS-CELL FOR CDR");
raise Evaluation_Error;
end if;
Pop_Frame (Interp); -- Done with the current frame
Put_Frame_Result (Interp, Interp.Stack, Get_Cdr(A));
end Apply_Cdr_Procedure;
procedure Apply_Cons_Procedure is
Ptr: Object_Pointer := Args;
A: Object_Pointer;
B: Object_Pointer;
begin
2014-01-21 10:12:15 +00:00
if not Is_Cons(Ptr) or else not Is_Cons(Get_Cdr(Ptr)) or else Get_Cdr(Get_Cdr(Ptr)) /= Nil_Pointer then
2014-01-19 15:47:45 +00:00
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
Pop_Frame (Interp); -- Done with the current frame
Put_Frame_Result (Interp, Interp.Stack, Ptr);
end Apply_Cons_Procedure;
procedure Apply_Setcar_Procedure is
Ptr: Object_Pointer := Args;
A: Object_Pointer;
B: Object_Pointer;
begin
2014-01-21 10:12:15 +00:00
if not Is_Cons(Ptr) or else not Is_Cons(Get_Cdr(Ptr)) or else Get_Cdr(Get_Cdr(Ptr)) /= Nil_Pointer then
2014-01-19 15:47:45 +00:00
Ada.Text_IO.Put_Line ("WRONG NUMBER OF ARGUMETNS FOR SET-CAR!");
raise Syntax_Error;
end if;
A := Get_Car(Ptr); -- the first argument
2014-01-21 10:12:15 +00:00
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
Pop_Frame (Interp); -- Done with the current frame
Put_Frame_Result (Interp, Interp.Stack, A);
end Apply_Setcar_Procedure;
procedure Apply_Setcdr_Procedure is
Ptr: Object_Pointer := Args;
A: Object_Pointer;
B: Object_Pointer;
begin
2014-01-21 10:12:15 +00:00
if not Is_Cons(Ptr) or else not Is_Cons(Get_Cdr(Ptr)) or else Get_Cdr(Get_Cdr(Ptr)) /= Nil_Pointer then
2014-01-19 15:47:45 +00:00
Ada.Text_IO.Put_Line ("WRONG NUMBER OF ARGUMETNS FOR SET-CDR!");
raise Syntax_Error;
end if;
A := Get_Car(Ptr); -- the first argument
2014-01-21 10:12:15 +00:00
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
Pop_Frame (Interp); -- Done with the current frame
Put_Frame_Result (Interp, Interp.Stack, A);
end Apply_Setcdr_Procedure;
-- -------------------------------------------------------------
-- Arithmetic procedures
-- -------------------------------------------------------------
procedure Apply_Add_Procedure is
Ptr: Object_Pointer := Args;
Num: Object_Integer := 0; -- TODO: support BIGNUM
Car: Object_Pointer;
begin
2014-01-21 10:12:15 +00:00
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);
if not Is_Integer(Car) then
Ada.Text_IO.Put ("NOT INTEGER FOR ADD"); Print (Interp, Car);
raise Evaluation_Error;
end if;
Num := Num + Pointer_To_Integer(Car);
Ptr := Get_Cdr(Ptr);
end loop;
Pop_Frame (Interp); -- Done with the current frame
Put_Frame_Result (Interp, Interp.Stack, Integer_To_Pointer(Num));
end Apply_Add_Procedure;
procedure Apply_Subtract_Procedure is
Ptr: Object_Pointer := Args;
Num: Object_Integer := 0; -- TODO: support BIGNUM
Car: Object_Pointer;
begin
2014-01-21 10:12:15 +00:00
if Is_Cons(Ptr) then
Car := Get_Car(Ptr);
if not Is_Integer(Car) then
raise Evaluation_Error;
end if;
Num := Pointer_To_Integer(Car);
2014-01-20 14:34:55 +00:00
Ptr := Get_Cdr(Ptr);
2014-01-21 10:12:15 +00:00
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);
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;
Pop_Frame (Interp); -- Done with the current frame
Put_Frame_Result (Interp, Interp.Stack, Integer_To_Pointer(Num));
end Apply_Subtract_Procedure;
procedure Apply_Multiply_Procedure is
Ptr: Object_Pointer := Args;
Num: Object_Integer := 1; -- TODO: support BIGNUM
Car: Object_Pointer;
begin
2014-01-21 10:12:15 +00:00
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);
if not Is_Integer(Car) then
Ada.Text_IO.Put ("NOT INTEGER FOR MULTIPLY"); Print (Interp, Car);
raise Evaluation_Error;
end if;
Num := Num * Pointer_To_Integer(Car);
Ptr := Get_Cdr(Ptr);
end loop;
Pop_Frame (Interp); -- Done with the current frame
Put_Frame_Result (Interp, Interp.Stack, Integer_To_Pointer(Num));
end Apply_Multiply_Procedure;
procedure Apply_Quotient_Procedure is
Ptr: Object_Pointer := Args;
Num: Object_Integer := 1; -- TODO: support BIGNUM
Car: Object_Pointer;
begin
2014-01-21 10:12:15 +00:00
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);
if not Is_Integer(Car) then
Ada.Text_IO.Put ("NOT INTEGER FOR MULTIPLY"); Print (Interp, Car);
raise Evaluation_Error;
end if;
Num := Num * Pointer_To_Integer(Car);
Ptr := Get_Cdr(Ptr);
end loop;
Pop_Frame (Interp); -- Done with the current frame
Put_Frame_Result (Interp, Interp.Stack, Integer_To_Pointer(Num));
end Apply_Quotient_Procedure;
2014-01-22 14:11:30 +00:00
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
-- TODO: support other values
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 ("NON INTEGER 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;
Pop_Frame (Interp); -- Done with the current frame
Put_Frame_Result (Interp, Interp.Stack, Bool);
2014-01-22 14:11:30 +00:00
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
-- TODO: support BIGNUM, OTHER DATA TYPES
begin
return Is_Integer(X) and then Is_Integer(Y);
end Validate_Numeric;
function Equal_To (X: in Object_Pointer; Y: in Object_Pointer) return Standard.Boolean is
-- TODO: support BIGNUM, OTHER DATA TYPES
begin
return Pointer_To_Integer(X) = Pointer_To_Integer(Y);
end Equal_To;
function Greater_Than (X: in Object_Pointer; Y: in Object_Pointer) return Standard.Boolean is
-- TODO: support BIGNUM, OTHER DATA TYPES
begin
return Pointer_To_Integer(X) > Pointer_To_Integer(Y);
end Greater_Than;
function Less_Than (X: in Object_Pointer; Y: in Object_Pointer) return Standard.Boolean is
-- TODO: support BIGNUM, OTHER DATA TYPES
begin
return Pointer_To_Integer(X) < Pointer_To_Integer(Y);
end Less_Than;
function Greater_Or_Equal (X: in Object_Pointer; Y: in Object_Pointer) return Standard.Boolean is
-- TODO: support BIGNUM, OTHER DATA TYPES
begin
return Pointer_To_Integer(X) >= Pointer_To_Integer(Y);
end Greater_Or_Equal;
function Less_Or_Equal (X: in Object_Pointer; Y: in Object_Pointer) return Standard.Boolean is
-- TODO: support BIGNUM, OTHER DATA TYPES
begin
return Pointer_To_Integer(X) <= Pointer_To_Integer(Y);
end Less_Or_Equal;
procedure Apply_EQ_Procedure is new Apply_Compare_Procedure (Validate_Numeric, Equal_To);
procedure Apply_GT_Procedure is new Apply_Compare_Procedure (Validate_Numeric, Greater_Than);
procedure Apply_LT_Procedure is new Apply_Compare_Procedure (Validate_Numeric, Less_Than);
procedure Apply_GE_Procedure is new Apply_Compare_Procedure (Validate_Numeric, Greater_Or_Equal);
procedure Apply_LE_Procedure is new Apply_Compare_Procedure (Validate_Numeric, Less_Or_Equal);
-- -------------------------------------------------------------
-- Closure
-- -------------------------------------------------------------
procedure Apply_Closure is
Fbody: aliased Object_Pointer;
2014-01-21 10:12:15 +00:00
Formal: aliased Object_Pointer;
Actual: aliased Object_Pointer;
Envir: aliased Object_Pointer;
begin
Push_Top (Interp, Fbody'Unchecked_Access);
2014-01-21 10:12:15 +00:00
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);
2014-01-21 10:12:15 +00:00
pragma Assert (Is_Cons(Fbody)); -- the lambda evaluator must ensure this.
2014-01-21 10:12:15 +00:00
Formal := Get_Car(Fbody); -- Formal argument list
Actual := Args; -- Actual argument list
2014-01-20 15:47:08 +00:00
Fbody := Get_Cdr(Fbody); -- Real function body
2014-01-21 05:08:46 +00:00
pragma Assert (Is_Cons(Fbody)); -- the lambda evaluator must ensure this.
2014-01-21 10:12:15 +00:00
if Is_Symbol(Formal) then
2014-01-21 05:08:46 +00:00
-- 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.
2014-01-21 10:12:15 +00:00
Put_Environment (Interp, Formal, Actual);
2014-01-21 05:08:46 +00:00
else
2014-01-21 10:12:15 +00:00
while Is_Cons(Formal) loop
if not Is_Cons(Actual) then
Ada.Text_IO.Put_Line (">>>> TOO FEW ARGUMENTS FOR CLOSURE <<<<");
2014-01-21 05:08:46 +00:00
raise Evaluation_Error;
end if;
2014-01-21 05:08:46 +00:00
-- Insert the key/value pair into the environment
2014-01-21 10:12:15 +00:00
Put_Environment (Interp, Get_Car(Formal), Get_Car(Actual));
2014-01-21 10:12:15 +00:00
Formal := Get_Cdr(Formal);
Actual := Get_Cdr(Actual);
2014-01-21 05:08:46 +00:00
end loop;
2014-01-21 05:08:46 +00:00
-- Perform cosmetic checks for the parameter list
2014-01-21 10:12:15 +00:00
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)
Put_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;
2014-01-21 05:08:46 +00:00
end if;
end if;
Set_Frame_Opcode (Interp.Stack, Opcode_Grouped_Call);
Set_Frame_Operand (Interp.Stack, Fbody);
Clear_Frame_Result (Interp.Stack);
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);
C := Get_Frame_Parent(Interp.Stack);
declare
w: object_word;
for w'address use c'address;
2014-02-01 15:59:36 +00:00
f: object_word;
for f'address use interp.stack'address;
r: object_pointer := get_frame_result(c);
begin
2014-01-29 02:30:50 +00:00
ada.text_io.put_line ("Frame" & object_word'image(f) & " " & Opcode_Type'Image(Get_Frame_Opcode(Interp.Stack)));
ada.text_io.put (" CURRENT RESULT ");
print (interp, r);
2014-02-01 15:59:36 +00:00
ada.text_io.put_line (" PARENT FRAME " & object_word'image(w));
end;
2014-02-01 15:59:36 +00:00
C := Make_Continuation (Interp.Self, C);
C := Make_Cons (Interp.Self, C, Nil_Pointer);
C := Make_Cons (Interp.Self, Get_Car(Args), C);
declare
w: object_word;
for w'address use c'address;
f: object_word;
for f'address use interp.stack'address;
begin
2014-01-29 02:30:50 +00:00
ada.text_io.put (" PUSH CONTINUATION ");
ada.text_io.put (object_word'image(w) & " ");
print (interp, c);
end;
Set_Frame_Opcode (Interp.Stack, Opcode_Apply);
Set_Frame_Operand (Interp.Stack, C);
Clear_Frame_Result (Interp.Stack);
2014-02-01 15:59:36 +00:00
ada.text_io.put_line (" CLEARED RESULT BEFORE APPLYING");
Pop_Tops (Interp, 1);
end Apply_Callcc_Procedure;
procedure Apply_Continuation is
R: Object_Pointer;
begin
declare
w: object_word;
for w'address use func'address;
f: object_word;
for f'address use interp.stack'address;
begin
2014-01-29 02:30:50 +00:00
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;
-- Get the result of the continuation frame
-- R := Get_Frame_Result(Interp.Stack);
-- 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));
2014-01-29 02:30:50 +00:00
ada.text_io.put_line (" CURRENT OPCODE " & opcode_type'image(get_Frame_opcode(interp.stack)));
end;
ada.text_io.put (" CHAIN NEW RESULT, TAKING THE FIRST ONLY FROM ");
print (interp, args);
Put_Frame_Result (Interp, Interp.Stack, Get_Car(Args));
-- if R /= Nil_Pointer then
--ada.text_io.put (" CARRY OVER RESULT ");
--print (interp, get_car(r));
-- Chain_Frame_Result (Interp, Interp.Stack, Get_Car(R));
-- end if;
--Set_Frame_Result (Interp.Stack, R);
--Chain_Frame_Result (Interp, Interp.Stack, Get_Car(Args));
ada.text_io.put (" FINAL RESULT ");
print (interp, get_Frame_result(interp.stack));
-- if Get_Frame_Parent(Interp.Stack) /= Nil_Pointer then
-- Set_Frame_Result (Get_Frame_Parent(Interp.Stack), Get_Continuation_Save(Func));
-- --Set_Frame_Operand (Get_Frame_Parent(Interp.Stack), Get_Continuation_Save2(Func));
-- end if;
end Apply_Continuation;
begin
Push_Top (Interp, Operand'Unchecked_Access);
Push_Top (Interp, Func'Unchecked_Access);
Push_Top (Interp, Args'Unchecked_Access);
Operand := Get_Frame_Operand(Interp.Stack);
pragma Assert (Is_Cons(Operand));
declare
w: object_word;
for w'address use interp.stack'address;
begin
2014-01-29 02:30:50 +00:00
ada.text_io.put_line ("Frame" & object_word'image(w) & " " & Opcode_Type'Image(Get_Frame_Opcode(Interp.Stack)));
ada.text_io.put (" OPERAND TO APPLY => ");
print (Interp, Operand);
ada.text_io.put (" CURRENT RESULT => ");
print (Interp, get_frame_result(interp.stack));
end;
Func := Get_Car(Operand);
if not Is_Normal_Pointer(Func) then
Ada.Text_IO.Put_Line ("INVALID FUNCTION TYPE");
raise Evaluation_Error;
end if;
Args := Get_Cdr(Operand);
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 Setcar_Procedure =>
Apply_Setcar_Procedure;
when Setcdr_Procedure =>
Apply_Setcdr_Procedure;
when Add_Procedure =>
Apply_Add_Procedure;
when Subtract_Procedure =>
Apply_Subtract_Procedure;
when Multiply_Procedure =>
Apply_Multiply_Procedure;
when Quotient_Procedure =>
Apply_Quotient_Procedure;
--when Remainder_Procedure =>
-- Apply_Remainder_Procedure;
2014-01-22 14:11:30 +00:00
when EQ_Procedure =>
Apply_EQ_Procedure;
when GT_Procedure =>
Apply_GT_Procedure;
when LT_Procedure =>
Apply_LT_Procedure;
when GE_Procedure =>
Apply_GE_Procedure;
when LE_Procedure =>
Apply_LE_Procedure;
when others =>
raise Internal_Error;
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, 3);
end Apply;