Common Lisp: Add documentation
[jackhill/mal.git] / ada / step2_eval.adb
index fea1509..6f0e281 100644 (file)
@@ -1,9 +1,7 @@
+with Ada.Containers.Hashed_Maps;
+with Ada.Strings.Unbounded.Hash;
 with Ada.Text_IO;
-with Ada.IO_Exceptions;
 with Ada.Exceptions;
-with Core;
-with Envs;
-with Eval_Callback;
 with Printer;
 with Reader;
 with Smart_Pointers;
@@ -13,9 +11,85 @@ procedure Step2_Eval is
 
    use Types;
 
-   function Eval (Param : Types.Mal_Handle; Env : Envs.Env_Handle)
+   -- primitive functions on Smart_Pointer,
+   function "+" is new Arith_Op ("+", "+");
+   function "-" is new Arith_Op ("-", "-");
+   function "*" is new Arith_Op ("*", "*");
+   function "/" is new Arith_Op ("/", "/");
+
+   -- Take a list with two parameters and produce a single result
+   -- using the Op access-to-function parameter.
+   function Reduce2
+     (Op : Binary_Func_Access; LH : Mal_Handle)
+   return Mal_Handle is
+      Left, Right : Mal_Handle;
+      L, Rest_List : List_Mal_Type;
+   begin
+      L := Deref_List (LH).all;
+      Left := Car (L);
+      Rest_List := Deref_List (Cdr (L)).all;
+      Right := Car (Rest_List);
+      return Op (Left, Right);
+   end Reduce2;
+
+
+   function Plus (Rest_Handle : Mal_Handle)
+   return Types.Mal_Handle is
+   begin
+       return Reduce2 (Step2_Eval."+"'Unrestricted_Access, Rest_Handle);
+   end Plus;
+
+
+   function Minus (Rest_Handle : Mal_Handle)
+   return Types.Mal_Handle is
+   begin
+       return Reduce2 (Step2_Eval."-"'Unrestricted_Access, Rest_Handle);
+   end Minus;
+
+
+   function Mult (Rest_Handle : Mal_Handle)
+   return Types.Mal_Handle is
+   begin
+       return Reduce2 (Step2_Eval."*"'Unrestricted_Access, Rest_Handle);
+   end Mult;
+
+
+   function Divide (Rest_Handle : Mal_Handle)
+   return Types.Mal_Handle is
+   begin
+       return Reduce2 (Step2_Eval."/"'Unrestricted_Access, Rest_Handle);
+   end Divide;
+
+
+   package String_Mal_Hash is new Ada.Containers.Hashed_Maps
+     (Key_Type        => Ada.Strings.Unbounded.Unbounded_String,
+      Element_Type    => Smart_Pointers.Smart_Pointer,
+      Hash            => Ada.Strings.Unbounded.Hash,
+      Equivalent_Keys => Ada.Strings.Unbounded."=",
+      "="             => Smart_Pointers."=");
+
+   Not_Found : exception;
+
+   function Get (M : String_Mal_Hash.Map; K : String) return Mal_Handle is
+      use String_Mal_Hash;
+      C : Cursor;
+   begin
+      C := Find (M, Ada.Strings.Unbounded.To_Unbounded_String (K));
+      if C = No_Element then
+         raise Not_Found;
+      else
+         return Element (C);
+      end if;
+   end Get;
+
+
+   Repl_Env : String_Mal_Hash.Map;
+
+
+   function Eval (Param : Types.Mal_Handle; Env : String_Mal_Hash.Map)
    return Types.Mal_Handle;
 
+
    Debug : Boolean := False;
 
 
@@ -26,7 +100,7 @@ procedure Step2_Eval is
 
 
    function Eval_Ast
-     (Ast : Mal_Handle; Env : Envs.Env_Handle)
+     (Ast : Mal_Handle; Env : String_Mal_Hash.Map)
      return Mal_Handle is
 
       function Call_Eval (A : Mal_Handle) return Mal_Handle is
@@ -47,11 +121,11 @@ procedure Step2_Eval is
                if Sym(1) = ':' then
                   return Ast;
                else
-                  return Envs.Get (Env, Sym);
+                  return Get (Env, Sym);
                end if;
             exception
-               when Envs.Not_Found =>
-                  raise Envs.Not_Found with (" '" &  Sym & "' not found ");
+               when Not_Found =>
+                  raise Not_Found with ("'" &  Sym & "' not found");
             end;
 
          when List =>
@@ -65,7 +139,7 @@ procedure Step2_Eval is
    end Eval_Ast;
 
 
-   function Eval (Param : Mal_Handle; Env : Envs.Env_Handle)
+   function Eval (Param : Mal_Handle; Env : String_Mal_Hash.Map)
                 return Mal_Handle is
       First_Elem : Mal_Handle;
    begin
@@ -80,7 +154,15 @@ procedure Step2_Eval is
          declare
             Evaled_H, First_Param : Mal_Handle;
             Evaled_List : List_Mal_Type;
+            Param_List : List_Mal_Type;
          begin
+            Param_List := Deref_List (Param).all;
+
+            -- Deal with empty list..
+            if Param_List.Length = 0 then
+               return Param;
+            end if;
+
             Evaled_H := Eval_Ast (Param, Env);
             Evaled_List := Deref_List (Evaled_H).all;
             First_Param := Car (Evaled_List);
@@ -102,7 +184,7 @@ procedure Step2_Eval is
    end Print;
 
 
-   function Rep (Param : String; Env : Envs.Env_Handle) return String is
+   function Rep (Param : String; Env : String_Mal_Hash.Map) return String is
      AST, Evaluated_AST : Types.Mal_Handle;
    begin
 
@@ -115,39 +197,40 @@ procedure Step2_Eval is
         return Print (Evaluated_AST);
      end if;
 
-   end Rep; 
-
-
-   Repl_Env : Envs.Env_Handle;
-   S : String (1..Reader.Max_Line_Len);
-   Last : Natural;
+   end Rep;
 
 begin
 
-   -- Save a function pointer back to the Eval function.
-   -- Can't use 'Access here because of Ada rules but 'Unrestricted_Access is OK
-   -- as we know Eval will be in scope for the lifetime of the program.
-   Eval_Callback.Eval := Eval'Unrestricted_Access;
+   String_Mal_Hash.Include
+     (Container => Repl_Env,
+      Key       => Ada.Strings.Unbounded.To_Unbounded_String ("+"),
+      New_Item  => New_Func_Mal_Type ("+", Plus'Unrestricted_access));
+
+   String_Mal_Hash.Include
+     (Container => Repl_Env,
+      Key       => Ada.Strings.Unbounded.To_Unbounded_String ("-"),
+      New_Item  => New_Func_Mal_Type ("-", Minus'Unrestricted_access));
 
-   Repl_Env := Envs.New_Env;
+   String_Mal_Hash.Include
+     (Container => Repl_Env,
+      Key       => Ada.Strings.Unbounded.To_Unbounded_String ("*"),
+      New_Item  => New_Func_Mal_Type ("*", Mult'Unrestricted_access));
 
-   Core.Init (Repl_Env);
+   String_Mal_Hash.Include
+     (Container => Repl_Env,
+      Key       => Ada.Strings.Unbounded.To_Unbounded_String ("/"),
+      New_Item  => New_Func_Mal_Type ("/", Divide'Unrestricted_access));
 
    loop
       begin
          Ada.Text_IO.Put ("user> ");
-         Ada.Text_IO.Get_Line (S, Last);
-         Ada.Text_IO.Put_Line (Rep (S (1..Last), Repl_Env));
+         exit when Ada.Text_IO.End_Of_File;
+         Ada.Text_IO.Put_Line (Rep (Ada.Text_IO.Get_Line, Repl_Env));
       exception
-         when Ada.IO_Exceptions.End_Error => raise;
          when E : others =>
             Ada.Text_IO.Put_Line
               (Ada.Text_IO.Standard_Error,
                Ada.Exceptions.Exception_Information (E));
       end;
    end loop;
-
-exception
-   when Ada.IO_Exceptions.End_Error => null;
-   -- i.e. exit without textual output
 end Step2_Eval;