diff --git a/lib/h2-scheme-execute-evaluate.adb b/lib/h2-scheme-execute-evaluate.adb index 04719e6..1138d4d 100644 --- a/lib/h2-scheme-execute-evaluate.adb +++ b/lib/h2-scheme-execute-evaluate.adb @@ -4,8 +4,6 @@ procedure Evaluate is --pragma Inline (Evaluate); Operand: aliased Object_Pointer; - Car: aliased Object_Pointer; - Cdr: aliased Object_Pointer; -- ---------------------------------------------------------------- @@ -23,7 +21,7 @@ procedure Evaluate is -- (and 1 2 'c '(f g)) ==> (f g) -- (and) ==> #t - Operand := Cdr; -- Skip "And" + Operand := Get_Cdr(Operand); -- Skip "And" if Operand = Nil_Pointer then -- (and) Return_Frame (Interp, Result); @@ -45,49 +43,33 @@ procedure Evaluate is -- ---------------------------------------------------------------- - procedure Evaluate_Define_Syntax is - pragma Inline (Evaluate_Define_Syntax); + procedure Evaluate_Begin_Syntax is + pragma Inline (Evaluate_Begin_Syntax); + Synlist: Object_Pointer; begin --- TODO: limit the context where define can be used. + Synlist := Operand; + Operand := Get_Cdr(Operand); -- Skip "begin" - -- (define x 10) - -- (define (add x y) (+ x y)) -> (define add (lambda (x y) (+ x y))) - Operand := Cdr; -- Skip "define" + if (Interp.State and Force_Syntax_Check) /= 0 or else + (Synlist.Flags and Syntax_Checked) = 0 then - if not Is_Cons(Operand) or else not Is_Cons(Get_Cdr(Operand)) then - -- e.g) (define) - -- (define . 10) - -- (define x . 10) - Ada.Text_IO.Put_LINE ("TOO FEW ARGUMENTS FOR DEFINE"); - raise Syntax_Error; - end if; - - Car := Get_Car(Operand); - Cdr := Get_Cdr(Operand); - if Is_Cons(Car) then - -- define a function: (define (add x y) ...) -ada.text_io.put_line ("NOT IMPLEMENTED YET"); -raise Syntax_Error; - elsif Is_Symbol(Car) then - -- define a symbol: (define x ...) - if Get_Cdr(Cdr) /= Nil_Pointer then - Ada.Text_IO.Put_LINE ("TOO MANY ARGUMENTS FOR DEFINE"); + if Operand /= Nil_Pointer and then + Get_Last_Cdr(Operand) /= Nil_Pointer then + Ada.Text_IO.Put_LINE ("FUCKNING CDR FOR BEGIN"); raise Syntax_Error; end if; - Cdr := Get_Car(Cdr); -- Value - -- Arrange to finish defining after value evaluation - -- and to evaluate the value part. - --Switch_Frame (Interp.Stack, Opccode_Define_Finish, Car); - --Push_Frame (Interp, Opcode_Evaluate_Object, Cdr); - Switch_Frame (Interp.Stack, Opcode_Evaluate_Object, Cdr, Nil_Pointer); - Push_Subframe (Interp, Opcode_Define_Finish, Car); - else - Ada.Text_IO.Put_LINE ("NO SYMBOL NOR ARGUMENT LIST AFTER DEFINE"); - raise Syntax_Error; + Synlist.Flags := Synlist.Flags or Syntax_Checked; end if; - end Evaluate_Define_Syntax; + if Operand = Nil_Pointer then + -- (begin) + -- Return nil to the upper frame for (begin). + Return_Frame (Interp, Nil_Pointer); + else + Switch_Frame (Interp.Stack, Opcode_Grouped_Call, Operand, Nil_Pointer); + end if; + end Evaluate_Begin_Syntax; -- ---------------------------------------------------------------- procedure Evaluate_Case_Syntax is @@ -101,7 +83,7 @@ raise Syntax_Error; procedure Evaluate_Cond_Syntax is pragma Inline (Evaluate_Cond_Syntax); - Ptr: Object_Pointer; + Synlist: Object_Pointer; begin -- cond ... -- A clause should be of the form: @@ -115,42 +97,111 @@ raise Syntax_Error; -- ((< 3 3) 'less) -- (else 'equal)) => equal - Operand := Cdr; -- Skip "cond" - if Not Is_Cons(Operand) then - -- e.g) (cond) - -- (cond . 10) - Ada.Text_IO.Put_LINE ("NO CLAUSE FOR COND"); - raise Syntax_Error; - end if; - - -- Check clauses - -- TODO: Skip this check of clauses that have been checked previously. - Ptr := Operand; - loop - Car := Get_Car(Ptr); -- - if not Is_Cons(Car) then - Ada.Text_IO.Put_Line ("FUCKING CLAUSE FOR COND"); + Synlist := Operand; + Operand := Get_Cdr(Operand); -- Skip "cond". list + + if (Interp.State and Force_Syntax_Check) /= 0 or else + (Synlist.Flags and Syntax_Checked) = 0 then + if Not Is_Cons(Operand) then + -- e.g) (cond) + -- (cond . 10) + Ada.Text_IO.Put_LINE ("NO CLAUSE FOR COND"); raise Syntax_Error; end if; - If Get_Last_Cdr(Car) /= Nil_Pointer then - Ada.Text_IO.Put_Line ("FUCKING CDR FOR COND CLAUSE"); - raise Syntax_Error; - end if; - Ptr := Get_Cdr(Ptr); - exit when not Is_Cons(Ptr); - end loop; - if Ptr /= Nil_Pointer then - Ada.Text_IO.Put_Line ("FUCKING LAST CLAUSE FOR COND"); - raise Syntax_Error; + + declare + Ptr1: Object_Pointer := Operand; + Ptr2: Object_Pointer; + begin + loop + Ptr2 := Get_Car(Ptr1); -- + if not Is_Cons(Ptr2) then + Ada.Text_IO.Put_Line ("FUCKING CLAUSE FOR COND"); + raise Syntax_Error; + end if; + If Get_Last_Cdr(Ptr2) /= Nil_Pointer then + Ada.Text_IO.Put_Line ("FUCKING CDR FOR COND CLAUSE"); + raise Syntax_Error; + end if; + Ptr1 := Get_Cdr(Ptr1); -- next list + exit when not Is_Cons(Ptr1); + end loop; + if Ptr1 /= Nil_Pointer then + Ada.Text_IO.Put_Line ("FUCKING LAST CLAUSE FOR COND"); + raise Syntax_Error; + end if; + end; + + Synlist.Flags := Synlist.Flags or Syntax_Checked; end if; - Car := Get_Car(Operand); -- first - - Switch_Frame (Interp.Stack, Opcode_Evaluate_Object, Get_Car(Car), Nil_Pointer); -- first - Push_Subframe (Interp, Opcode_Cond_Finish, Operand); + Switch_Frame (Interp.Stack, Opcode_Evaluate_Object, Get_Car(Get_Car(Operand)), Nil_Pointer); -- in first + Push_Subframe (Interp, Opcode_Cond_Finish, Operand); -- list end Evaluate_Cond_Syntax; -- ---------------------------------------------------------------- + + procedure Evaluate_Define_Syntax is + pragma Inline (Evaluate_Define_Syntax); + Synlist: Object_Pointer; + Ptr: Object_Pointer; + begin +-- TODO: limit the context where define can be used. + + -- (define x 10) + -- (define (add x y) (+ x y)) -> (define add (lambda (x y) (+ x y))) + Synlist := Operand; + Operand := Get_Cdr(Operand); -- Skip "define" + + if (Interp.State and Force_Syntax_Check) /= 0 or else + (Synlist.Flags and Syntax_Checked) = 0 then + if not Is_Cons(Operand) or else not Is_Cons(Get_Cdr(Operand)) then + -- e.g) (define) + -- (define . 10) + -- (define x . 10) + Ada.Text_IO.Put_LINE ("TOO FEW ARGUMENTS FOR DEFINE"); + raise Syntax_Error; + end if; + + Ptr := Get_Car(Operand); + if Is_Cons(Ptr) then +ada.text_io.put_line ("NOT IMPLEMENTED YET"); +raise Syntax_Error; + + elsif Is_Symbol(Ptr) then + if Get_Cdr(Get_Cdr(Operand)) /= Nil_Pointer then + Ada.Text_IO.Put_LINE ("TOO MANY ARGUMENTS FOR DEFINE"); + raise Syntax_Error; + end if; + else + Ada.Text_IO.Put_LINE ("NO SYMBOL NOR ARGUMENT LIST AFTER DEFINE"); + raise Syntax_Error; + end if; + + + Synlist.Flags := Synlist.Flags or Syntax_Checked; + end if; + + Ptr := Get_Car(Operand); + if Is_Cons(Ptr) then + -- define a function: (define (add x y) ...) +ada.text_io.put_line ("NOT IMPLEMENTED YET"); +raise Syntax_Error; + else + -- define a symbol: (define x ...) + pragma Assert (Is_Symbol(Ptr)); + + -- Arrange to finish defining after value evaluation + -- and to evaluate the value part. + --Switch_Frame (Interp.Stack, Opccode_Define_Finish, Ptr); + --Push_Frame (Interp, Opcode_Evaluate_Object, Get_Car(Get_Cdr(Operand))); + Switch_Frame (Interp.Stack, Opcode_Evaluate_Object, Get_Car(Get_Cdr(Operand)), Nil_Pointer); + Push_Subframe (Interp, Opcode_Define_Finish, Ptr); + end if; + end Evaluate_Define_Syntax; + + -- ---------------------------------------------------------------- + procedure Evaluate_Do_Syntax is pragma Inline (Evaluate_Do_Syntax); begin @@ -162,129 +213,146 @@ raise Syntax_Error; procedure Evaluate_If_Syntax is pragma Inline (Evaluate_If_Syntax); + Synlist: Object_Pointer; begin -- (if ) -- (if ) -- e.g) (if (> 3 2) 'yes) -- (if (> 3 2) 'yes 'no) - -- (if (> 3 2) (- 3 2) (+ 3 2)) - Operand := Cdr; -- Skip "if" - if Not Is_Cons(Operand) then - -- e.g) (if) - -- (if . 10) - Ada.Text_IO.Put_LINE ("NO CONDITIONAL FOR IF"); - raise Syntax_Error; - end if; + -- (if (> 3 2) (- 3 2) (+ 3 2)) + + Synlist := Operand; + Operand := Get_Cdr(Operand); -- Skip "if". + + if (Interp.State and Force_Syntax_Check) /= 0 or else + (Synlist.Flags and Syntax_Checked) = 0 then + declare + Ptr: Object_Pointer := Operand; + begin + if Not Is_Cons(Ptr) then + -- e.g) (if) + -- (if . 10) + Ada.Text_IO.Put_LINE ("NO CONDITIONAL FOR IF"); + raise Syntax_Error; + end if; - Car := Get_Car(Operand); -- + Ptr := Get_Cdr(Ptr); -- cons cell containg + if not Is_Cons(Ptr) then + Ada.Text_IO.Put_Line ("NO CONSEQUENT FOR IF"); + raise Syntax_Error; + end if; - Operand := Get_Cdr(Operand); -- cons cell containg - if not Is_Cons(Operand) then - Ada.Text_IO.Put_Line ("NO ACTION FOR IF"); - raise Syntax_Error; - end if; - - Cdr := Get_Cdr(Operand); -- cons cell containing - if Cdr = Nil_Pointer then - -- no . it's ok -Ada.Text_IO.Put_Line ("NO ALTERNATE"); - null; - elsif not Is_Cons(Cdr) then - -- no but reduncant cdr. - -- (if (> 3 2) 3 . 99) - Ada.Text_IO.Put_Line ("FUCKING CDR FOR IF"); - raise Syntax_Error; + Ptr := Get_Cdr(Ptr); -- cons cell containing + if Ptr = Nil_Pointer then + -- no . it's ok + null; + elsif not Is_Cons(Ptr) then + -- no but reduncant cdr. + -- (if (> 3 2) 3 . 99) + Ada.Text_IO.Put_Line ("FUCKING CDR FOR IF"); + raise Syntax_Error; + + elsif Get_Cdr(Ptr) /= Nil_Pointer then + -- (if (> 3 2) 3 2 . 99) + -- (if (> 3 2) 3 2 99) + Ada.Text_IO.Put_Line ("TOO MANY ARGUMENTS FOR IF"); + raise Syntax_Error; + end if; + end; - elsif Get_Cdr(Cdr) /= Nil_Pointer then - -- (if (> 3 2) 3 2 . 99) - -- (if (> 3 2) 3 2 99) - Ada.Text_IO.Put_Line ("TOO MANY ARGUMENTS FOR IF"); - raise Syntax_Error; + Synlist.Flags := Synlist.Flags or Syntax_Checked; end if; - + + -- Arrange to evaluate or after -- evaluation and to evaluate . Use Switch_Frame/Push_Subframe -- instead of Switch_Frame/Push_Frame for continuation to work. - --Switch_Frame (Interp.Stack, Opcode_If_Finish, Operand, Nil_Pointer); - --Push_Frame (Interp, Opcode_Evaluate_Object, Car); - Switch_Frame (Interp.Stack, Opcode_Evaluate_Object, Car, Nil_Pointer); - Push_Subframe (Interp, Opcode_If_Finish, Operand); + Switch_Frame (Interp.Stack, Opcode_Evaluate_Object, Get_Car(Operand), Nil_Pointer); -- + Push_Subframe (Interp, Opcode_If_Finish, Get_Cdr(Operand)); -- and later end Evaluate_If_Syntax; -- ---------------------------------------------------------------- procedure Evaluate_Lambda_Syntax is pragma Inline (Evaluate_Lambda_Syntax); + Synlist: Object_Pointer; begin -- (lambda ) -- e.g) (lambda (x y) (+ x y)) -- e.g) (lambda (x y . z) z) -- e.g) (lambda x (car x)) - Operand := Cdr; -- Skip "lambda". cons cell pointing to - if not Is_Cons(Operand) then - -- e.g) (lambda) - -- (lambda . 10) - Ada.Text_IO.Put_LINE ("FUCKNING CDR FOR LAMBDA"); - raise Syntax_Error; - end if; + Synlist := Operand; + Operand := Get_Cdr(Operand); -- Skip "lambda". cons cell pointing to - Car := Get_Car(Operand); -- - if Car = Nil_Pointer or else Is_Symbol(Car) then - -- (lambda () ...) or (lambda x ...) - -- nothing to do - null; - elsif Is_Cons(Car) then - declare - Formals: Object_Pointer := Car; - V: Object_Pointer; - begin - Cdr := Formals; - loop - Car := Get_Car(Cdr); -- - if not Is_Symbol(Car) then - Ada.Text_IO.Put_Line ("WRONG FORMAL FOR LAMBDA"); - raise Syntax_Error; - end if; - - -- Check for a duplication formal argument --- TODO: make duplication check optional or change the implementation more efficient so that this check is not repeated - V := Formals; - loop - exit when V = Cdr; - - if Get_Car(V) = Car then - Ada.Text_IO.Put_Line ("DUPLICATE FORMAL FOR LAMBDA"); - raise Syntax_Error; - end if; - - V := Get_Cdr(V); - end loop; - - -- Move on to the next formal argument - Cdr := Get_Cdr(Cdr); - exit when not Is_Cons(Cdr); - end loop; - end; - - if Cdr /= Nil_Pointer and then not Is_Symbol(Cdr) then - Ada.Text_IO.Put_Line ("FUCKING CDR IN FORMALS FOR LAMBDA"); + if (Interp.State and Force_Syntax_Check) /= 0 or else + (Synlist.Flags and Syntax_Checked) = 0 then + if not Is_Cons(Operand) then + -- e.g) (lambda) + -- (lambda . 10) + Ada.Text_IO.Put_LINE ("FUCKNING CDR FOR LAMBDA"); raise Syntax_Error; end if; - else - Ada.Text_IO.Put_Line ("INVALID FORMALS FOR LAMBDA"); - raise Syntax_Error; - end if; - Cdr := Get_Cdr(Operand); -- cons cell containing - if not Is_Cons(Cdr) then - Ada.Text_IO.Put_Line ("NO BODY"); - raise Syntax_Error; - end if; + declare + Ptr1: Object_Pointer; + Ptr2: Object_Pointer; + Ptr3: Object_Pointer; + Ptr4: Object_Pointer; + begin + + Ptr1 := Get_Car(Operand); -- + if Ptr1 = Nil_Pointer or else Is_Symbol(Ptr1) then + -- (lambda () ...) or (lambda x ...) + -- nothing to do + null; + elsif Is_Cons(Ptr1) then + Ptr2 := Ptr1; + loop + Ptr3 := Get_Car(Ptr2); -- + if not Is_Symbol(Ptr3) then + Ada.Text_IO.Put_Line ("WRONG FORMAL FOR LAMBDA"); + raise Syntax_Error; + end if; + + -- Check for a duplication formal argument + -- TODO: make duplication check optional or change the implementation more efficient so that this check is not repeated + Ptr4 := Ptr1; + while Ptr4 /= Ptr2 loop + if Get_Car(Ptr4) = Ptr3 then + Ada.Text_IO.Put_Line ("DUPLICATE FORMAL FOR LAMBDA"); + raise Syntax_Error; + end if; + Ptr4 := Get_Cdr(Ptr4); + end loop; + + -- Move on to the next formal argument + Ptr2 := Get_Cdr(Ptr2); + exit when not Is_Cons(Ptr2); + end loop; + + if Ptr2 /= Nil_Pointer and then not Is_Symbol(Ptr2) then + Ada.Text_IO.Put_Line ("FUCKING CDR IN FORMALS FOR LAMBDA"); + raise Syntax_Error; + end if; + else + Ada.Text_IO.Put_Line ("INVALID FORMALS FOR LAMBDA"); + raise Syntax_Error; + end if; + + Ptr1 := Get_Cdr(Operand); -- cons cell containing + if not Is_Cons(Ptr1) then + Ada.Text_IO.Put_Line ("NO BODY"); + raise Syntax_Error; + end if; + + if Get_Last_Cdr(Ptr1) /= Nil_Pointer then + -- (lambda (x y) (+ x y) . 99) + Ada.Text_IO.Put_Line ("FUCKING CDR IN BODY FOR LAMBDA"); + raise Syntax_Error; + end if; + end; - if Get_Last_Cdr(Cdr) /= Nil_Pointer then - -- (lambda (x y) (+ x y) . 99) - Ada.Text_IO.Put_Line ("FUCKING CDR IN BODY FOR LAMBDA"); - raise Syntax_Error; + Synlist.Flags := Synlist.Flags or Syntax_Checked; end if; -- Create a closure object and return it the the upper frame. @@ -295,12 +363,10 @@ Ada.Text_IO.Put_Line ("NO ALTERNATE"); procedure Check_Let_Syntax is pragma Inline (Check_Let_Syntax); - Bindings: Object_Pointer; LetBody: Object_Pointer; begin - -- let - Operand := Cdr; -- Skip "let". + -- (let ) if not Is_Cons(Operand) then -- e.g) (let) -- (let . 10) @@ -324,58 +390,55 @@ Ada.Text_IO.Put_Line ("NO ALTERNATE"); end if; if Is_Cons(Bindings) then - Cdr := Bindings; - loop - Car := Get_Car(Cdr); -- - if not Is_Cons(Car) or else not Is_Cons(Get_Cdr(Car)) or else Get_Cdr(Get_Cdr(Car)) /= Nil_Pointer then - -- no binding name or no binding value or garbage after that - Ada.Text_IO.Put_Line ("WRONG BINDING FOR LET"); - raise Syntax_Error; - end if; - - if not Is_Symbol(Get_Car(Car)) then - Ada.Text_IO.Put_Line ("WRONG BINDING NAME FOR LET"); - raise Syntax_Error; - end if; - - -- Check for a duplicate binding name --- TODO: make duplication check optional or change the implementation more efficient so that this check is not repeated - declare - V: Object_Pointer; - begin - V := Bindings; - loop - exit when V = Cdr; - - if Get_Car(Get_Car(V)) = Get_Car(Car) then + declare + Ptr1: Object_Pointer := Bindings; + Ptr2: Object_Pointer; + Ptr3: Object_Pointer; + begin + loop + Ptr2 := Get_Car(Ptr1); -- + if not Is_Cons(Ptr2) or else not Is_Cons(Get_Cdr(Ptr2)) or else Get_Cdr(Get_Cdr(Ptr2)) /= Nil_Pointer then + -- no binding name or no binding value or garbage after that + Ada.Text_IO.Put_Line ("WRONG BINDING FOR LET"); + raise Syntax_Error; + end if; + + Ptr2 := Get_Car(Ptr2); -- name + if not Is_Symbol(Ptr2) then + Ada.Text_IO.Put_Line ("WRONG BINDING NAME FOR LET"); + raise Syntax_Error; + end if; + + -- Check for a duplicate binding name + -- TODO: make duplication check optional or change the implementation more efficient so that this check is not repeated + Ptr3 := Bindings; + while Ptr3 /= Ptr1 loop + if Get_Car(Get_Car(Ptr3)) = Ptr2 then Ada.Text_IO.Put_Line ("DUPLICATE BINDING FOR LET"); raise Syntax_Error; end if; - - V := Get_Cdr(V); + Ptr3 := Get_Cdr(Ptr3); end loop; - end; - - -- Move on to the next binding - Cdr := Get_Cdr(Cdr); - exit when not Is_Cons(Cdr); - end loop; - - if Cdr /= Nil_Pointer then - -- The last cdr is not nil. - Ada.Text_IO.Put_Line ("FUCKING CDR FOR LET BINDING"); - raise Syntax_Error; - end if; + + -- Move on to the next binding + Ptr1 := Get_Cdr(Ptr1); + exit when not Is_Cons(Ptr1); + end loop; + + if Ptr1 /= Nil_Pointer then + -- The last cdr is not nil. + Ada.Text_IO.Put_Line ("FUCKING CDR FOR LET BINDING"); + raise Syntax_Error; + end if; + end; end if; - - -- To avoid problems of temporary object pointer problems. - Car := Bindings; - Cdr := LetBody; end Check_Let_Syntax; procedure Evaluate_Let_Syntax is pragma Inline (Evaluate_Let_Syntax); - Envir: aliased Object_Pointer; + Synlist: Object_Pointer; + Envir: aliased Object_Pointer; + Bindings: aliased Object_Pointer; begin -- Some let samples: -- #1. @@ -393,106 +456,137 @@ Ada.Text_IO.Put_Line ("NO ALTERNATE"); -- (define x (let ((x x)) x)) -- - Check_Let_Syntax; - -- Car: , Cdr: + Synlist := Operand; + Operand := Get_Cdr(Operand); -- Skip "let". + + if (Interp.State and Force_Syntax_Check) /= 0 or else + (Synlist.Flags and Syntax_Checked) = 0 then + Check_Let_Syntax; + Synlist.Flags := Synlist.Flags or Syntax_Checked; + end if; -- Switch the frame to Opcode_Grouped_Call and let its environment -- be the new environment created. Use Reload_Frame() instead -- of Switch_Frame() for continuation. This frame is executed once -- the Opcode_Let_Binding frame pushed in the 'if' block is finished. - Reload_Frame (Interp, Opcode_Grouped_Call, Cdr); + Reload_Frame (Interp, Opcode_Grouped_Call, Get_Cdr(Operand)); -- -- Create a new environment over the current environment. Envir := Make_Environment(Interp.Self, Get_Frame_Environment(Interp.Stack)); Set_Frame_Environment (Interp.Stack, Envir); -- update the environment - if Car /= Nil_Pointer then + Bindings := Get_Car(Operand); -- + if Bindings /= Nil_Pointer then -- is not empty Push_Top (Interp, Envir'Unchecked_Access); + Push_Top (Interp, Bindings'Unchecked_Access); + Envir := Get_Frame_Environment(Get_Frame_Parent(Interp.Stack)); -- Say, is ((x 2) (y 2)). - -- Get_Car(Car) is (x 2). - -- To get x, Get_Car(Get_Car(Car)) - -- To get 2, Get_Car(Get_Cdr(Get_Car(Car))) + -- Get_Car(Bindings) is (x 2). + -- To get x, Get_Car(Get_Car(Bindings)) + -- To get 2, Get_Car(Get_Cdr(Get_Car(Bindings))) -- Arrange to evaluate the first expression in the parent environment. - Push_Frame_With_Environment (Interp, Opcode_Evaluate_Object, Get_Car(Get_Cdr(Get_Car(Car))), Envir); + Push_Frame_With_Environment (Interp, Opcode_Evaluate_Object, Get_Car(Get_Cdr(Get_Car(Bindings))), Envir); -- Arrange to perform actual binding. Pass the name as an intermediate -- and the next remaing list as an operand. - Push_Subframe_With_Environment_And_Intermediate (Interp, Opcode_Let_Binding, Get_Cdr(Car), Envir, Get_Car(Get_Car(Car))); + Push_Subframe_With_Environment_And_Intermediate (Interp, Opcode_Let_Binding, Get_Cdr(Bindings), Envir, Get_Car(Get_Car(Bindings))); - Pop_Tops (Interp, 1); + Pop_Tops (Interp, 2); end if; end Evaluate_Let_Syntax; procedure Evaluate_Letast_Syntax is pragma Inline (Evaluate_Letast_Syntax); + Synlist: Object_Pointer; Envir: aliased Object_Pointer; + Bindings: aliased Object_Pointer; begin - Check_Let_Syntax; - -- Car: , Cdr: + Synlist := Operand; + Operand := Get_Cdr(Operand); -- Skip "let". + + if (Interp.State and Force_Syntax_Check) /= 0 or else + (Synlist.Flags and Syntax_Checked) = 0 then + Check_Let_Syntax; + Synlist.Flags := Synlist.Flags or Syntax_Checked; + end if; - Reload_Frame (Interp, Opcode_Grouped_Call, Cdr); + Reload_Frame (Interp, Opcode_Grouped_Call, Get_Cdr(Operand)); -- -- Create a new environment over the current environment. Envir := Make_Environment(Interp.Self, Get_Frame_Environment(Interp.Stack)); Set_Frame_Environment (Interp.Stack, Envir); -- update the environment - if Car /= Nil_Pointer then + Bindings := Get_Car(Operand); -- + if Bindings /= Nil_Pointer then -- is not empty Push_Top (Interp, Envir'Unchecked_Access); + Push_Top (Interp, Bindings'Unchecked_Access); -- Say, is ((x 2) (y 2)). - -- Get_Car(Car) is (x 2). - -- To get x, Get_Car(Get_Car(Car)) - -- To get 2, Get_Car(Get_Cdr(Get_Car(Car))) + -- Get_Car(Bindings) is (x 2). + -- To get x, Get_Car(Get_Car(Bindings)) + -- To get 2, Get_Car(Get_Cdr(Get_Car(Bindings))) -- Arrange to evaluate the first expression in the parent environment. - Push_Frame_With_Environment (Interp, Opcode_Evaluate_Object, Get_Car(Get_Cdr(Get_Car(Car))), Envir); + Push_Frame_With_Environment (Interp, Opcode_Evaluate_Object, Get_Car(Get_Cdr(Get_Car(Bindings))), Envir); -- Arrange to perform actual binding. Pass the name as an intermediate -- and the next remaing list as an operand. - Push_Subframe_With_Environment_And_Intermediate (Interp, Opcode_Letast_Binding, Get_Cdr(Car), Envir, Get_Car(Get_Car(Car))); + Push_Subframe_With_Environment_And_Intermediate (Interp, Opcode_Letast_Binding, Get_Cdr(Bindings), Envir, Get_Car(Get_Car(Bindings))); - Pop_Tops (Interp, 1); + Pop_Tops (Interp, 2); end if; end Evaluate_Letast_Syntax; procedure Evaluate_Letrec_Syntax is pragma Inline (Evaluate_Letrec_Syntax); + Synlist: Object_Pointer; Envir: Object_Pointer; + Bindings: aliased Object_Pointer; begin - Check_Let_Syntax; - -- Car: , Cdr: + Synlist := Operand; + Operand := Get_Cdr(Operand); -- Skip "let". + + if (Interp.State and Force_Syntax_Check) /= 0 or else + (Synlist.Flags and Syntax_Checked) = 0 then + Check_Let_Syntax; + Synlist.Flags := Synlist.Flags or Syntax_Checked; + end if; -- Switch the frame to Opcode_Grouped_Call and let its environment -- be the new environment created. Use Reload_Frame() instead -- of Switch_Frame() for continuation. This frame is executed once -- the Opcode_Letrec_Binding frame pushed in the 'if' block is finished. - Reload_Frame (Interp, Opcode_Grouped_Call, Cdr); + Reload_Frame (Interp, Opcode_Grouped_Call, Get_Cdr(Operand)); -- -- Create a new environment over the current environment. Envir := Make_Environment(Interp.Self, Get_Frame_Environment(Interp.Stack)); Set_Frame_Environment (Interp.Stack, Envir); -- update the environment - if Car /= Nil_Pointer then + Bindings := Get_Car(Operand); -- + if Bindings /= Nil_Pointer then -- is not empty + Push_Top (Interp, Bindings'Unchecked_Access); -- Say, is ((x 2) (y 2)). - -- Get_Car(Car) is (x 2). - -- To get x, Get_Car(Get_Car(Car)) - -- To get 2, Get_Car(Get_Cdr(Get_Car(Car))) + -- Get_Car(Bindings) is (x 2). + -- To get x, Get_Car(Get_Car(Bindings)) + -- To get 2, Get_Car(Get_Cdr(Get_Car(Bindings))) -- Arrange to evaluate the first expression in the parent environment. - Push_Frame (Interp, Opcode_Evaluate_Object, Get_Car(Get_Cdr(Get_Car(Car)))); + Push_Frame (Interp, Opcode_Evaluate_Object, Get_Car(Get_Cdr(Get_Car(Bindings)))); -- Arrange to perform actual binding. Pass the name as an intermediate -- and the next remaing list as an operand. - Push_Subframe_With_Intermediate (Interp, Opcode_Letrec_Binding, Get_Cdr(Car), Get_Car(Get_Car(Car))); + Push_Subframe_With_Intermediate (Interp, Opcode_Letrec_Binding, Get_Cdr(Bindings), Get_Car(Get_Car(Bindings))); + + Pop_Tops (Interp, 1); end if; end Evaluate_Letrec_Syntax; @@ -508,17 +602,27 @@ Ada.Text_IO.Put_Line ("NO ALTERNATE"); procedure Evaluate_Quote_Syntax is pragma Inline (Evaluate_Quote_Syntax); + Synlist: Object_Pointer; begin - Operand := Cdr; -- Skip "quote". Get the first argument. - if not Is_Cons(Operand) then - -- e.g) (quote) - -- (quote . 10) - Ada.Text_IO.Put_LINE ("FUCKNING CDR FOR QUOTE"); - raise Syntax_Error; - elsif Get_Cdr(Operand) /= Nil_Pointer then - Ada.Text_IO.Put_LINE ("WRONG NUMBER OF ARGUMENTS FOR QUOTE"); - raise Syntax_Error; + Synlist := Operand; + Operand := Get_Cdr(Operand); -- Skip "quote". Get the first argument. + + if (Interp.State and Force_Syntax_Check) /= 0 or else + (Synlist.Flags and Syntax_Checked) = 0 then + + if not Is_Cons(Operand) then + -- e.g) (quote) + -- (quote . 10) + Ada.Text_IO.Put_LINE ("TOO FEW ARGUMETNS FOR QUOTE"); + raise Syntax_Error; + elsif Get_Cdr(Operand) /= Nil_Pointer then + Ada.Text_IO.Put_LINE ("TOO MANY ARGUMENTS FOR QUOTE"); + raise Syntax_Error; + end if; + + Synlist.Flags := Synlist.Flags or Syntax_Checked; end if; + Return_Frame (Interp, Get_Car(Operand)); end Evaluate_Quote_Syntax; @@ -526,51 +630,124 @@ Ada.Text_IO.Put_Line ("NO ALTERNATE"); procedure Evaluate_Set_Syntax is pragma Inline (Evaluate_Set_Syntax); + Synlist: Object_Pointer; begin -- (set! ) -- e.g) (set! x 10) - Operand := Cdr; -- Skip "set!" + Synlist := Operand; + Operand := Get_Cdr(Operand); -- Skip "set!" - if not Is_Cons(Operand) or else not Is_Cons(Get_Cdr(Operand)) then - -- e.g) (set!) - -- (set . 10) - -- (set x . 10) - Ada.Text_IO.Put_LINE ("TOO FEW ARGUMENTS FOR SET!"); - raise Syntax_Error; - end if; + if (Interp.State and Force_Syntax_Check) /= 0 or else + (Synlist.Flags and Syntax_Checked) = 0 then + if not Is_Cons(Operand) or else not Is_Cons(Get_Cdr(Operand)) then + -- e.g) (set!) + -- (set . 10) + -- (set x . 10) + Ada.Text_IO.Put_LINE ("TOO FEW ARGUMENTS FOR SET!"); + raise Syntax_Error; + end if; - Car := Get_Car(Operand); -- - Cdr := Get_Cdr(Operand); -- cons cell to - if Is_Symbol(Car) then - if Get_Cdr(Cdr) /= Nil_Pointer then + if not Is_Symbol(Get_Car(Operand)) then -- + Ada.Text_IO.Put_LINE ("INVALID SYMBOL AFTER SET!"); + raise Syntax_Error; + end if; + + if Get_Cdr(Get_Cdr(Operand)) /= Nil_Pointer then + -- (set x 10 20) + -- (set x 10 . 20) Ada.Text_IO.Put_LINE ("TOO MANY ARGUMENTS FOR SET!"); raise Syntax_Error; end if; - Cdr := Get_Car(Cdr); -- - -- Arrange to finish setting a variable after evaluation. - --Switch_Frame (Interp.Stack, Opcode_Set_Finish, Car, Nil_Pointer); - -- Arrange to evalaute the value part - --Push_Frame (Interp, Opcode_Evaluate_Object, Cdr); - - -- These 2 lines derives the same result as the 2 lines commented out above. - Switch_Frame (Interp.Stack, Opcode_Evaluate_Object, Cdr, Nil_Pointer); - Push_Subframe (Interp, Opcode_Set_Finish, Car); - else - Ada.Text_IO.Put_LINE ("INVALID SYMBOL AFTER SET!"); - raise Syntax_Error; + Synlist.Flags := Synlist.Flags or Syntax_Checked; end if; + + Switch_Frame (Interp.Stack, Opcode_Evaluate_Object, Get_Car(Get_Cdr(Operand)), Nil_Pointer); -- + Push_Subframe (Interp, Opcode_Set_Finish, Get_Car(Operand)); -- end Evaluate_Set_Syntax; -- ---------------------------------------------------------------- + procedure Evaluate_List is + Ptr: Object_Pointer; + begin + Ptr := Get_Car(Operand); + if Is_Syntax(Ptr) then + -- special syntax symbol. normal evaluation rule doesn't + -- apply for special syntax objects. + + case Ptr.Scode is + when And_Syntax => + Evaluate_And_Syntax; + + when Begin_Syntax => + Evaluate_Begin_Syntax; + + when Case_Syntax => + Evaluate_Case_Syntax; + + when Cond_Syntax => + Evaluate_Cond_Syntax; + + when Define_Syntax => + Evaluate_Define_Syntax; + + when Do_Syntax => + Evaluate_Do_Syntax; + + when If_Syntax => + Evaluate_If_Syntax; + + when Lambda_Syntax => + Evaluate_Lambda_Syntax; + + when Let_Syntax => + Evaluate_Let_Syntax; + + when Letast_Syntax => + Evaluate_Letast_Syntax; + + when Letrec_Syntax => + Evaluate_Letrec_Syntax; + + when Or_Syntax => + Evaluate_Or_Syntax; + + when Quasiquote_Syntax => + Evaluate_Quasiquote_Syntax; + + when Quote_Syntax => + Evaluate_Quote_Syntax; + + when Set_Syntax => -- set! + Evaluate_Set_Syntax; + + end case; + else + -- procedure call + -- ( ...) + if (Interp.State and Force_Syntax_Check) /= 0 or else + (Operand.Flags and Syntax_Checked) = 0 then + + if Get_Last_Cdr(Operand) /= Nil_Pointer then + Ada.Text_IO.Put_Line ("ERROR: FUCKING CDR FOR PROCEDURE CALL.$$$$"); + raise Syntax_Error; + end if; + + Operand.Flags := Operand.Flags or Syntax_Checked; + end if; + + -- Switch the current frame to evaluate + Switch_Frame (Interp.Stack, Opcode_Evaluate_Object, Ptr, Nil_Pointer); + -- Push a new frame to evaluate arguments. + Push_Subframe (Interp, Opcode_Procedure_Call, Get_Cdr(Operand)); + end if; + end Evaluate_List; + begin Push_Top (Interp, Operand'Unchecked_Access); - Push_Top (Interp, Car'Unchecked_Access); - Push_Top (Interp, Cdr'Unchecked_Access); -<> Operand := Get_Frame_Operand(Interp.Stack); declare @@ -594,107 +771,25 @@ end; 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 - Ada.Text_IO.Put_Line ("Unbound symbol...."); - Print (Interp, Operand); - 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; + declare + Ptr: Object_Pointer; + begin + Ptr := Get_Environment (Interp.Self, Operand); + if Ptr = null then + -- unbound + Ada.Text_IO.Put_Line ("Unbound symbol...."); + Print (Interp, Operand); + raise Evaluation_Error; + else + -- symbol found in the environment + Operand := Ptr; + goto Literal; -- In fact, this is not a literal, but can be handled in the same way + end if; + end; 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 And_Syntax => - Evaluate_And_Syntax; - - when Begin_Syntax => - Operand := Cdr; -- Skip "begin" - - if Operand = Nil_Pointer then - -- (begin) - -- Return nil to the upper frame for (begin). - Return_Frame (Interp, Nil_Pointer); - else - if Get_Last_Cdr(Operand) /= Nil_Pointer then - Ada.Text_IO.Put_LINE ("FUCKNING CDR FOR BEGIN"); - raise Syntax_Error; - end if; - - Switch_Frame (Interp.Stack, Opcode_Grouped_Call, Operand, Nil_Pointer); - end if; - - --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; - - when Case_Syntax => - Evaluate_Case_Syntax; - - when Cond_Syntax => - Evaluate_Cond_Syntax; - - when Define_Syntax => - Evaluate_Define_Syntax; - - when Do_Syntax => - Evaluate_Do_Syntax; - - when If_Syntax => - Evaluate_If_Syntax; - - when Lambda_Syntax => - Evaluate_Lambda_Syntax; - - when Let_Syntax => - Evaluate_Let_Syntax; - - when Letast_Syntax => - Evaluate_Letast_Syntax; - - when Letrec_Syntax => - Evaluate_Letrec_Syntax; - - when Or_Syntax => - Evaluate_Or_Syntax; - - when Quasiquote_Syntax => - Evaluate_Quasiquote_Syntax; - - when Quote_Syntax => - Evaluate_Quote_Syntax; - - when Set_Syntax => -- set! - Evaluate_Set_Syntax; - - end case; - else - -- procedure call - -- ( ...) - if Get_Last_Cdr(Operand) /= Nil_Pointer then - Ada.Text_IO.Put_Line ("ERROR: FUCKING CDR FOR PROCEDURE CALL.$$$$"); - raise Syntax_Error; - end if; - - -- Switch the current frame to evaluate - Switch_Frame (Interp.Stack, Opcode_Evaluate_Object, Car, Nil_Pointer); - -- Push a new frame to evaluate arguments. - Push_Subframe (Interp, Opcode_Procedure_Call, Cdr); - end if; + -- ( ... ) + Evaluate_List; when others => -- normal literal object @@ -703,16 +798,9 @@ end; goto Done; <> -declare -w: object_word; -for w'address use operand'address; -begin -Ada.Text_IO.Put ("Return => (" & object_word'image(w) & ") =>" ); -Print (Interp, Operand); -end; Return_Frame (Interp, Operand); goto Done; <> - Pop_Tops (Interp, 3); + Pop_Tops (Interp, 1); end Evaluate; diff --git a/lib/h2-scheme-execute.adb b/lib/h2-scheme-execute.adb index 3e81049..87572cb 100644 --- a/lib/h2-scheme-execute.adb +++ b/lib/h2-scheme-execute.adb @@ -80,7 +80,7 @@ procedure Execute (Interp: in out Interpreter_Record) is if Is_Cons(O) then Reload_Frame (Interp, Opcode_Grouped_Call, O); else - Pop_Frame (Interp); + Pop_Frame (Interp); -- no to evaluate end if; else O := Get_Cdr(O); -- next list @@ -96,7 +96,7 @@ procedure Execute (Interp: in out Interpreter_Record) is if Is_Cons(O) then Reload_Frame (Interp, Opcode_Grouped_Call, O); else - Pop_Frame (Interp); + Pop_Frame (Interp); -- no to evaluate end if; else Switch_Frame (Interp.Stack, Opcode_Evaluate_Object, Get_Car(R), Nil_Pointer); diff --git a/lib/h2-scheme.adb b/lib/h2-scheme.adb index a3d153f..190f1d6 100644 --- a/lib/h2-scheme.adb +++ b/lib/h2-scheme.adb @@ -1863,6 +1863,7 @@ end if; Interp.Self := Aliased_Interp'Unchecked_Access; end; + Interp.State := 0; Interp.Storage_Pool := Storage_Pool; Interp.Symbol_Table := Nil_Pointer; diff --git a/lib/h2-scheme.ads b/lib/h2-scheme.ads index d79bd3f..399147f 100644 --- a/lib/h2-scheme.ads +++ b/lib/h2-scheme.ads @@ -163,6 +163,7 @@ package H2.Scheme is -- represents the value that can be stored in this field. type Object_Flags is mod 2 ** 4; Syntax_Object: constant Object_Flags := Object_Flags'(2#0001#); + Syntax_Checked: constant Object_Flags := Object_Flags'(2#0010#); type Syntax_Code is ( And_Syntax, @@ -503,9 +504,13 @@ private Data: Top_Array(1 .. 100) := (others => null); end record; + type Interpreter_State is mod 2 ** 4; + Force_Syntax_Check: constant Interpreter_State := Interpreter_State'(2#0001#); + --type Interpreter_Record is tagged limited record type Interpreter_Record is limited record Self: Interpreter_Pointer := Interpreter_Record'Unchecked_Access; -- Current instance's pointer + State: Interpreter_State := 0; -- Internal housekeeping state Storage_Pool: Storage_Pool_Pointer := null; Trait: Option_Record(Trait_Option);