2015-03-15 22:56:09 +03:00
|
|
|
with Ada.Characters.Latin_1;
|
2015-03-28 21:44:29 +03:00
|
|
|
with Ada.Strings.Fixed;
|
2015-04-19 20:08:51 +03:00
|
|
|
with Ada.Strings.Maps.Constants;
|
2015-03-15 22:56:09 +03:00
|
|
|
with Ada.Text_IO;
|
2015-03-19 00:12:54 +03:00
|
|
|
with Ada.Unchecked_Deallocation;
|
2015-04-19 20:08:51 +03:00
|
|
|
with Envs;
|
2016-03-15 11:05:20 +03:00
|
|
|
with Eval_Callback;
|
2015-03-28 21:44:29 +03:00
|
|
|
with Smart_Pointers;
|
2016-02-12 02:48:10 +03:00
|
|
|
with Types.Vector;
|
2016-02-29 00:45:38 +03:00
|
|
|
with Types.Hash_Map;
|
2015-03-15 22:56:09 +03:00
|
|
|
|
|
|
|
package body Types is
|
|
|
|
|
|
|
|
package ACL renames Ada.Characters.Latin_1;
|
|
|
|
|
2016-02-12 02:48:10 +03:00
|
|
|
function Nodes_Equal (A, B : Mal_Handle) return Boolean;
|
|
|
|
|
2015-03-17 01:48:48 +03:00
|
|
|
|
2015-04-19 20:08:51 +03:00
|
|
|
function "=" (A, B : Mal_Handle) return Mal_Handle is
|
|
|
|
begin
|
|
|
|
return New_Bool_Mal_Type (A = B);
|
|
|
|
end "=";
|
|
|
|
|
|
|
|
|
2016-02-12 02:48:10 +03:00
|
|
|
function Compare_List_And_Vector (A : List_Mal_Type; B : List_Mal_Type'Class)
|
|
|
|
return Boolean is
|
|
|
|
First_Node, First_Index : Mal_Handle;
|
|
|
|
I : Natural := 0;
|
|
|
|
begin
|
|
|
|
First_Node := A.The_List;
|
|
|
|
loop
|
|
|
|
if not Is_Null (First_Node) and I < B.Length then
|
|
|
|
First_Index := B.Nth (I);
|
|
|
|
if not "=" (Deref_Node (First_Node).Data, First_Index) then
|
|
|
|
return False;
|
|
|
|
end if;
|
|
|
|
First_Node := Deref_Node (First_Node).Next;
|
|
|
|
I := I + 1;
|
|
|
|
else
|
|
|
|
return Is_Null (First_Node) and I = B.Length;
|
|
|
|
end if;
|
|
|
|
end loop;
|
|
|
|
end Compare_List_And_Vector;
|
|
|
|
|
|
|
|
|
2015-04-19 20:08:51 +03:00
|
|
|
function "=" (A, B : Mal_Handle) return Boolean is
|
2016-02-12 02:48:10 +03:00
|
|
|
use Types.Vector;
|
2016-02-29 00:45:38 +03:00
|
|
|
use Types.Hash_Map;
|
2015-04-19 20:08:51 +03:00
|
|
|
begin
|
|
|
|
|
|
|
|
if (not Is_Null (A) and not Is_Null (B)) and then
|
|
|
|
Deref (A).Sym_Type = Deref (B).Sym_Type then
|
|
|
|
|
|
|
|
case Deref (A).Sym_Type is
|
2016-03-20 00:09:48 +03:00
|
|
|
when Nil =>
|
|
|
|
return True; -- Both nil.
|
2015-04-19 20:08:51 +03:00
|
|
|
when Int =>
|
|
|
|
return (Deref_Int (A).Get_Int_Val = Deref_Int (B).Get_Int_Val);
|
|
|
|
when Floating =>
|
|
|
|
return (Deref_Float (A).Get_Float_Val = Deref_Float (B).Get_Float_Val);
|
|
|
|
when Bool =>
|
|
|
|
return (Deref_Bool (A).Get_Bool = Deref_Bool (B).Get_Bool);
|
|
|
|
when List =>
|
2016-02-12 02:48:10 +03:00
|
|
|
-- When Types.Vector was added, the choice was:
|
|
|
|
-- 1) use interfaces (because you need a class hierachy for the containers
|
|
|
|
-- and a corresponding hierarchy for the cursors and Ada is single dispatch
|
|
|
|
-- + interfaces.
|
|
|
|
-- 2) map out the combinations here and use nth to access vector items.
|
|
|
|
case Deref_List (A).Get_List_Type is
|
|
|
|
when List_List =>
|
|
|
|
case Deref_List (B).Get_List_Type is
|
|
|
|
when List_List =>
|
|
|
|
return Nodes_Equal (Deref_List (A).The_List, Deref_List (B).The_List);
|
|
|
|
when Vector_List =>
|
|
|
|
return Compare_List_And_Vector
|
|
|
|
(Deref_List (A).all, Deref_List_Class (B).all);
|
|
|
|
when Hashed_List => return False; -- Comparing a list and a hash
|
|
|
|
end case;
|
|
|
|
when Vector_List =>
|
|
|
|
case Deref_List (B).Get_List_Type is
|
|
|
|
when List_List =>
|
|
|
|
return Compare_List_And_Vector
|
|
|
|
(Deref_List (B).all, Deref_List_Class (A).all);
|
|
|
|
when Vector_List =>
|
|
|
|
return Vector."=" (Deref_Vector (A).all, Deref_Vector (B).all);
|
|
|
|
when Hashed_List => return False; -- Comparing a vector and a hash
|
|
|
|
end case;
|
|
|
|
when Hashed_List =>
|
|
|
|
case Deref_List (B).Get_List_Type is
|
|
|
|
when List_List => return False; -- Comparing a list and a hash
|
|
|
|
when Vector_List => return False; -- Comparing a vector and a hash
|
2016-02-29 00:45:38 +03:00
|
|
|
when Hashed_List =>
|
|
|
|
return Hash_Map."=" (Deref_Hash (A).all, Deref_Hash (B).all);
|
2016-02-12 02:48:10 +03:00
|
|
|
end case;
|
|
|
|
end case;
|
2015-04-19 20:08:51 +03:00
|
|
|
when Str =>
|
|
|
|
return (Deref_String (A).Get_String = Deref_String (B).Get_String);
|
2016-02-23 01:22:56 +03:00
|
|
|
when Sym =>
|
|
|
|
return (Deref_Sym (A).Get_Sym = Deref_Sym (B).Get_Sym);
|
2015-04-19 20:08:51 +03:00
|
|
|
when Atom =>
|
|
|
|
return (Deref_Atom (A).Get_Atom = Deref_Atom (B).Get_Atom);
|
2015-04-26 19:15:58 +03:00
|
|
|
when Func =>
|
|
|
|
return (Deref_Func (A).Get_Func_Name = Deref_Func (B).Get_Func_Name);
|
2015-04-19 20:08:51 +03:00
|
|
|
when Node =>
|
|
|
|
return (Deref_Int(A).Get_Int_Val = Deref_Int(B).Get_Int_Val);
|
|
|
|
when Lambda =>
|
|
|
|
return (Deref_Int(A).Get_Int_Val = Deref_Int(B).Get_Int_Val);
|
|
|
|
when Error =>
|
|
|
|
return (Deref_Int(A).Get_Int_Val = Deref_Int(B).Get_Int_Val);
|
|
|
|
end case;
|
|
|
|
elsif Is_Null (A) and Is_Null (B) then
|
|
|
|
return True;
|
|
|
|
else -- either one of the args is null or the sym_types don't match
|
|
|
|
return False;
|
|
|
|
end if;
|
|
|
|
end "=";
|
|
|
|
|
2015-04-03 16:35:24 +03:00
|
|
|
function Get_Meta (T : Mal_Type) return Mal_Handle is
|
2015-03-28 21:44:29 +03:00
|
|
|
begin
|
2016-02-21 03:50:47 +03:00
|
|
|
if T.Meta = Smart_Pointers.Null_Smart_Pointer then
|
2016-03-20 00:09:48 +03:00
|
|
|
return New_Nil_Mal_Type;
|
2016-02-21 03:50:47 +03:00
|
|
|
else
|
|
|
|
return T.Meta;
|
|
|
|
end if;
|
2015-03-28 21:44:29 +03:00
|
|
|
end Get_Meta;
|
|
|
|
|
2015-04-03 16:35:24 +03:00
|
|
|
procedure Set_Meta (T : in out Mal_Type'Class; SP : Mal_Handle) is
|
2015-03-28 21:44:29 +03:00
|
|
|
begin
|
|
|
|
T.Meta := SP;
|
|
|
|
end Set_Meta;
|
|
|
|
|
2016-02-21 03:50:47 +03:00
|
|
|
function Copy (M : Mal_Handle) return Mal_Handle is
|
|
|
|
begin
|
|
|
|
return Smart_Pointers.New_Ptr
|
|
|
|
(new Mal_Type'Class'(Deref (M).all));
|
|
|
|
end Copy;
|
|
|
|
|
2015-05-02 00:55:52 +03:00
|
|
|
function To_String (T : Mal_Type'Class; Print_Readably : Boolean := True)
|
|
|
|
return Mal_String is
|
2015-03-28 21:44:29 +03:00
|
|
|
begin
|
2016-03-03 01:05:00 +03:00
|
|
|
return To_Str (T, Print_Readably);
|
2015-03-28 21:44:29 +03:00
|
|
|
end To_String;
|
|
|
|
|
2015-08-12 00:42:47 +03:00
|
|
|
function Is_Macro_Call (T : Mal_Type'Class; Env : Envs.Env_Handle) return Boolean is
|
|
|
|
L : List_Mal_Type;
|
|
|
|
First_Elem, Func : Mal_Handle;
|
|
|
|
begin
|
|
|
|
|
|
|
|
if T.Sym_Type /= List then
|
|
|
|
return False;
|
|
|
|
end if;
|
|
|
|
|
|
|
|
L := List_Mal_Type (T);
|
|
|
|
|
|
|
|
if Is_Null (L) then
|
|
|
|
return False;
|
|
|
|
end if;
|
|
|
|
|
|
|
|
First_Elem := Car (L);
|
|
|
|
|
2016-02-23 01:22:56 +03:00
|
|
|
if Deref (First_Elem).Sym_Type /= Sym then
|
2015-08-12 00:42:47 +03:00
|
|
|
return False;
|
|
|
|
end if;
|
|
|
|
|
2016-02-23 01:22:56 +03:00
|
|
|
Func := Envs.Get (Env, Deref_Sym (First_Elem).Get_Sym);
|
2015-08-12 00:42:47 +03:00
|
|
|
|
|
|
|
if Deref (Func).Sym_Type /= Lambda then
|
|
|
|
return False;
|
|
|
|
end if;
|
|
|
|
|
|
|
|
return Deref_Lambda (Func).Get_Is_Macro;
|
|
|
|
|
|
|
|
exception
|
|
|
|
when Envs.Not_Found => return False;
|
|
|
|
end Is_Macro_Call;
|
|
|
|
|
2015-03-28 21:44:29 +03:00
|
|
|
|
|
|
|
-- A helper function that just view converts the smart pointer.
|
2015-04-03 16:35:24 +03:00
|
|
|
function Deref (S : Mal_Handle) return Mal_Ptr is
|
2015-03-28 21:44:29 +03:00
|
|
|
begin
|
|
|
|
return Mal_Ptr (Smart_Pointers.Deref (S));
|
|
|
|
end Deref;
|
|
|
|
|
|
|
|
-- A helper function to detect null smart pointers.
|
2015-04-03 16:35:24 +03:00
|
|
|
function Is_Null (S : Mal_Handle) return Boolean is
|
2015-03-28 21:44:29 +03:00
|
|
|
use Smart_Pointers;
|
|
|
|
begin
|
2015-04-19 20:08:51 +03:00
|
|
|
return Smart_Pointers."="(S, Null_Smart_Pointer);
|
2015-03-28 21:44:29 +03:00
|
|
|
end Is_Null;
|
|
|
|
|
|
|
|
|
|
|
|
-- To_Str on the abstract type...
|
2015-05-02 00:55:52 +03:00
|
|
|
function To_Str (T : Mal_Type; Print_Readably : Boolean := True)
|
|
|
|
return Mal_String is
|
2015-03-28 21:44:29 +03:00
|
|
|
begin
|
|
|
|
raise Constraint_Error; -- Tha'll teach 'ee
|
|
|
|
return ""; -- Keeps the compiler happy.
|
|
|
|
end To_Str;
|
|
|
|
|
|
|
|
|
2016-03-20 00:09:48 +03:00
|
|
|
function New_Nil_Mal_Type return Mal_Handle is
|
|
|
|
begin
|
|
|
|
return Smart_Pointers.New_Ptr
|
|
|
|
(new Nil_Mal_Type'(Mal_Type with null record));
|
|
|
|
end New_Nil_Mal_Type;
|
|
|
|
|
|
|
|
overriding function Sym_Type (T : Nil_Mal_Type) return Sym_Types is
|
|
|
|
begin
|
|
|
|
return Nil;
|
|
|
|
end Sym_Type;
|
|
|
|
|
|
|
|
overriding function To_Str (T : Nil_Mal_Type; Print_Readably : Boolean := True)
|
|
|
|
return Mal_String is
|
|
|
|
begin
|
|
|
|
return "nil";
|
|
|
|
end To_Str;
|
|
|
|
|
|
|
|
|
2015-04-03 16:35:24 +03:00
|
|
|
function New_Int_Mal_Type (Int : Mal_Integer) return Mal_Handle is
|
2015-03-28 21:44:29 +03:00
|
|
|
begin
|
|
|
|
return Smart_Pointers.New_Ptr
|
|
|
|
(new Int_Mal_Type'(Mal_Type with Int_Val => Int));
|
|
|
|
end New_Int_Mal_Type;
|
|
|
|
|
|
|
|
overriding function Sym_Type (T : Int_Mal_Type) return Sym_Types is
|
|
|
|
begin
|
|
|
|
return Int;
|
|
|
|
end Sym_Type;
|
|
|
|
|
|
|
|
function Get_Int_Val (T : Int_Mal_Type) return Mal_Integer is
|
|
|
|
begin
|
|
|
|
return T.Int_Val;
|
|
|
|
end Get_Int_Val;
|
|
|
|
|
2015-05-02 00:55:52 +03:00
|
|
|
overriding function To_Str
|
|
|
|
(T : Int_Mal_Type; Print_Readably : Boolean := True)
|
|
|
|
return Mal_String is
|
2015-03-28 21:44:29 +03:00
|
|
|
Res : Mal_String := Mal_Integer'Image (T.Int_Val);
|
|
|
|
begin
|
|
|
|
return Ada.Strings.Fixed.Trim (Res, Ada.Strings.Left);
|
|
|
|
end To_Str;
|
|
|
|
|
2015-04-03 16:35:24 +03:00
|
|
|
function Deref_Int (SP : Mal_Handle) return Int_Ptr is
|
2015-04-02 01:36:29 +03:00
|
|
|
begin
|
|
|
|
return Int_Ptr (Deref (SP));
|
|
|
|
end Deref_Int;
|
|
|
|
|
2015-03-28 21:44:29 +03:00
|
|
|
|
2015-04-03 16:35:24 +03:00
|
|
|
function New_Float_Mal_Type (Floating : Mal_Float) return Mal_Handle is
|
2015-03-28 21:44:29 +03:00
|
|
|
begin
|
|
|
|
return Smart_Pointers.New_Ptr
|
|
|
|
(new Float_Mal_Type'(Mal_Type with Float_Val => Floating));
|
|
|
|
end New_Float_Mal_Type;
|
|
|
|
|
|
|
|
overriding function Sym_Type (T : Float_Mal_Type) return Sym_Types is
|
|
|
|
begin
|
|
|
|
return Floating;
|
|
|
|
end Sym_Type;
|
|
|
|
|
|
|
|
function Get_Float_Val (T : Float_Mal_Type) return Mal_Float is
|
|
|
|
begin
|
|
|
|
return T.Float_Val;
|
|
|
|
end Get_Float_Val;
|
|
|
|
|
2015-05-02 00:55:52 +03:00
|
|
|
overriding function To_Str
|
|
|
|
(T : Float_Mal_Type; Print_Readably : Boolean := True)
|
|
|
|
return Mal_String is
|
2015-03-28 21:44:29 +03:00
|
|
|
Res : Mal_String := Mal_Float'Image (T.Float_Val);
|
|
|
|
begin
|
|
|
|
return Ada.Strings.Fixed.Trim (Res, Ada.Strings.Left);
|
|
|
|
end To_Str;
|
|
|
|
|
2015-04-03 16:35:24 +03:00
|
|
|
function Deref_Float (SP : Mal_Handle) return Float_Ptr is
|
2015-04-02 01:36:29 +03:00
|
|
|
begin
|
|
|
|
return Float_Ptr (Deref (SP));
|
|
|
|
end Deref_Float;
|
|
|
|
|
2015-03-28 21:44:29 +03:00
|
|
|
|
2015-04-19 20:08:51 +03:00
|
|
|
function New_Bool_Mal_Type (Bool : Boolean) return Mal_Handle is
|
|
|
|
begin
|
|
|
|
return Smart_Pointers.New_Ptr
|
|
|
|
(new Bool_Mal_Type'(Mal_Type with Bool_Val => Bool));
|
|
|
|
end New_Bool_Mal_Type;
|
|
|
|
|
|
|
|
overriding function Sym_Type (T : Bool_Mal_Type) return Sym_Types is
|
|
|
|
begin
|
|
|
|
return Bool;
|
|
|
|
end Sym_Type;
|
|
|
|
|
|
|
|
function Get_Bool (T : Bool_Mal_Type) return Boolean is
|
|
|
|
begin
|
|
|
|
return T.Bool_Val;
|
|
|
|
end Get_Bool;
|
|
|
|
|
2015-05-02 00:55:52 +03:00
|
|
|
overriding function To_Str
|
|
|
|
(T : Bool_Mal_Type; Print_Readably : Boolean := True)
|
|
|
|
return Mal_String is
|
2015-04-19 20:08:51 +03:00
|
|
|
Res : Mal_String := Boolean'Image (T.Bool_Val);
|
|
|
|
begin
|
|
|
|
return Ada.Strings.Fixed.Translate
|
|
|
|
(Res, Ada.Strings.Maps.Constants.Lower_Case_Map);
|
|
|
|
end To_Str;
|
|
|
|
|
|
|
|
function Deref_Bool (SP : Mal_Handle) return Bool_Ptr is
|
|
|
|
begin
|
|
|
|
return Bool_Ptr (Deref (SP));
|
|
|
|
end Deref_Bool;
|
|
|
|
|
|
|
|
|
2015-04-03 16:35:24 +03:00
|
|
|
function New_String_Mal_Type (Str : Mal_String) return Mal_Handle is
|
2015-03-28 21:44:29 +03:00
|
|
|
begin
|
|
|
|
return Smart_Pointers.New_Ptr
|
|
|
|
(new String_Mal_Type' (Mal_Type with The_String =>
|
2016-03-25 15:55:27 +03:00
|
|
|
Ada.Strings.Unbounded.To_Unbounded_String (Str)));
|
2015-03-28 21:44:29 +03:00
|
|
|
end New_String_Mal_Type;
|
|
|
|
|
|
|
|
overriding function Sym_Type (T : String_Mal_Type) return Sym_Types is
|
|
|
|
begin
|
|
|
|
return Str;
|
|
|
|
end Sym_Type;
|
|
|
|
|
|
|
|
function Get_String (T : String_Mal_Type) return Mal_String is
|
|
|
|
begin
|
2016-03-25 15:55:27 +03:00
|
|
|
return Ada.Strings.Unbounded.To_String (T.The_String);
|
2015-03-28 21:44:29 +03:00
|
|
|
end Get_String;
|
|
|
|
|
2015-04-19 20:08:51 +03:00
|
|
|
function Deref_String (SP : Mal_Handle) return String_Ptr is
|
|
|
|
begin
|
|
|
|
return String_Ptr (Deref (SP));
|
|
|
|
end Deref_String;
|
|
|
|
|
2015-05-02 00:55:52 +03:00
|
|
|
|
|
|
|
overriding function To_Str
|
|
|
|
(T : String_Mal_Type; Print_Readably : Boolean := True)
|
|
|
|
return Mal_String is
|
|
|
|
use Ada.Strings.Unbounded;
|
2016-03-25 15:55:27 +03:00
|
|
|
I : Positive := 1;
|
2015-05-02 00:55:52 +03:00
|
|
|
Str_Len : Natural;
|
|
|
|
Res : Unbounded_String;
|
2016-03-25 15:55:27 +03:00
|
|
|
Ch : Character;
|
2015-05-02 00:55:52 +03:00
|
|
|
begin
|
|
|
|
if Print_Readably then
|
|
|
|
Append (Res, '"');
|
|
|
|
Str_Len := Length (T.The_String);
|
2016-03-25 15:55:27 +03:00
|
|
|
while I <= Str_Len loop
|
|
|
|
Ch := Element (T.The_String, I);
|
|
|
|
if Ch = '"' then
|
2015-05-02 00:55:52 +03:00
|
|
|
Append (Res, "\""");
|
2016-03-25 15:55:27 +03:00
|
|
|
elsif Ch = '\' then
|
2015-05-02 00:55:52 +03:00
|
|
|
Append (Res, "\\");
|
2016-03-25 15:55:27 +03:00
|
|
|
elsif Ch = Ada.Characters.Latin_1.LF then
|
2015-05-02 00:55:52 +03:00
|
|
|
Append (Res, "\n");
|
|
|
|
else
|
2016-03-25 15:55:27 +03:00
|
|
|
Append (Res, Ch);
|
2015-05-02 00:55:52 +03:00
|
|
|
end if;
|
|
|
|
I := I + 1;
|
|
|
|
end loop;
|
|
|
|
Append (Res, '"');
|
2016-03-25 15:55:27 +03:00
|
|
|
return To_String (Res);
|
2015-05-02 00:55:52 +03:00
|
|
|
else
|
2016-03-25 15:55:27 +03:00
|
|
|
return To_String (T.The_String);
|
2015-05-02 00:55:52 +03:00
|
|
|
end if;
|
2015-03-28 21:44:29 +03:00
|
|
|
end To_Str;
|
|
|
|
|
|
|
|
|
2016-02-23 01:22:56 +03:00
|
|
|
function New_Symbol_Mal_Type (Str : Mal_String) return Mal_Handle is
|
2015-03-28 21:44:29 +03:00
|
|
|
begin
|
|
|
|
return Smart_Pointers.New_Ptr
|
2016-02-23 01:22:56 +03:00
|
|
|
(new Symbol_Mal_Type'(Mal_Type with The_Symbol =>
|
2015-03-28 21:44:29 +03:00
|
|
|
Ada.Strings.Unbounded.To_Unbounded_String (Str)));
|
2016-02-23 01:22:56 +03:00
|
|
|
end New_Symbol_Mal_Type;
|
|
|
|
|
|
|
|
overriding function Sym_Type (T : Symbol_Mal_Type) return Sym_Types is
|
|
|
|
begin
|
|
|
|
return Sym;
|
|
|
|
end Sym_Type;
|
|
|
|
|
|
|
|
function Get_Sym (T : Symbol_Mal_Type) return Mal_String is
|
|
|
|
begin
|
|
|
|
return Ada.Strings.Unbounded.To_String (T.The_Symbol);
|
|
|
|
end Get_Sym;
|
|
|
|
|
|
|
|
function Deref_Sym (S : Mal_Handle) return Sym_Ptr is
|
|
|
|
begin
|
|
|
|
return Sym_Ptr (Deref (S));
|
|
|
|
end Deref_Sym;
|
|
|
|
|
|
|
|
overriding function To_Str
|
|
|
|
(T : Symbol_Mal_Type; Print_Readably : Boolean := True)
|
|
|
|
return Mal_String is
|
|
|
|
begin
|
|
|
|
return Ada.Strings.Unbounded.To_String (T.The_Symbol);
|
|
|
|
end To_Str;
|
|
|
|
|
|
|
|
|
|
|
|
function New_Atom_Mal_Type (MH : Mal_Handle) return Mal_Handle is
|
|
|
|
begin
|
|
|
|
return Smart_Pointers.New_Ptr
|
|
|
|
(new Atom_Mal_Type'(Mal_Type with The_Atom => MH));
|
2015-03-28 21:44:29 +03:00
|
|
|
end New_Atom_Mal_Type;
|
2015-03-23 01:37:42 +03:00
|
|
|
|
2015-03-28 21:44:29 +03:00
|
|
|
overriding function Sym_Type (T : Atom_Mal_Type) return Sym_Types is
|
2015-03-23 01:37:42 +03:00
|
|
|
begin
|
2015-03-28 21:44:29 +03:00
|
|
|
return Atom;
|
|
|
|
end Sym_Type;
|
|
|
|
|
2016-02-23 01:22:56 +03:00
|
|
|
function Get_Atom (T : Atom_Mal_Type) return Mal_Handle is
|
2015-03-28 21:44:29 +03:00
|
|
|
begin
|
2016-02-23 01:22:56 +03:00
|
|
|
return T.The_Atom;
|
2015-03-28 21:44:29 +03:00
|
|
|
end Get_Atom;
|
|
|
|
|
2016-02-26 01:33:38 +03:00
|
|
|
procedure Set_Atom (T : in out Atom_Mal_Type; New_Val : Mal_Handle) is
|
|
|
|
begin
|
|
|
|
T.The_Atom := New_Val;
|
|
|
|
end Set_Atom;
|
|
|
|
|
2015-04-03 16:35:24 +03:00
|
|
|
function Deref_Atom (S : Mal_Handle) return Atom_Ptr is
|
2015-04-03 00:34:55 +03:00
|
|
|
begin
|
2015-04-05 22:27:47 +03:00
|
|
|
return Atom_Ptr (Deref (S));
|
2015-04-03 00:34:55 +03:00
|
|
|
end Deref_Atom;
|
|
|
|
|
2015-05-02 00:55:52 +03:00
|
|
|
overriding function To_Str
|
|
|
|
(T : Atom_Mal_Type; Print_Readably : Boolean := True)
|
|
|
|
return Mal_String is
|
2015-03-28 21:44:29 +03:00
|
|
|
begin
|
2016-02-23 01:22:56 +03:00
|
|
|
return "(atom " & To_String (Deref (T.The_Atom).all) & ')';
|
2015-03-28 21:44:29 +03:00
|
|
|
end To_Str;
|
|
|
|
|
|
|
|
|
2015-04-26 19:15:58 +03:00
|
|
|
function New_Func_Mal_Type (Str : Mal_String; F : Builtin_Func)
|
|
|
|
return Mal_Handle is
|
|
|
|
begin
|
|
|
|
return Smart_Pointers.New_Ptr
|
|
|
|
(new Func_Mal_Type'(Mal_Type with
|
|
|
|
Func_Name => Ada.Strings.Unbounded.To_Unbounded_String (Str),
|
|
|
|
Func_P => F));
|
|
|
|
end New_Func_Mal_Type;
|
|
|
|
|
|
|
|
overriding function Sym_Type (T : Func_Mal_Type) return Sym_Types is
|
|
|
|
begin
|
|
|
|
return Func;
|
|
|
|
end Sym_Type;
|
|
|
|
|
|
|
|
function Get_Func_Name (T : Func_Mal_Type) return Mal_String is
|
|
|
|
begin
|
|
|
|
return Ada.Strings.Unbounded.To_String (T.Func_Name);
|
|
|
|
end Get_Func_Name;
|
|
|
|
|
|
|
|
function Call_Func
|
2016-03-21 00:08:28 +03:00
|
|
|
(FMT : Func_Mal_Type; Rest_List : Mal_Handle)
|
2015-04-26 19:15:58 +03:00
|
|
|
return Mal_Handle is
|
|
|
|
begin
|
2016-03-21 00:08:28 +03:00
|
|
|
return FMT.Func_P (Rest_List);
|
2015-04-26 19:15:58 +03:00
|
|
|
end Call_Func;
|
|
|
|
|
|
|
|
function Deref_Func (S : Mal_Handle) return Func_Ptr is
|
|
|
|
begin
|
|
|
|
return Func_Ptr (Deref (S));
|
|
|
|
end Deref_Func;
|
|
|
|
|
2015-05-02 00:55:52 +03:00
|
|
|
overriding function To_Str
|
|
|
|
(T : Func_Mal_Type; Print_Readably : Boolean := True)
|
|
|
|
return Mal_String is
|
2015-04-26 19:15:58 +03:00
|
|
|
begin
|
|
|
|
return Ada.Strings.Unbounded.To_String (T.Func_Name);
|
|
|
|
end To_Str;
|
|
|
|
|
|
|
|
|
2015-04-03 16:35:24 +03:00
|
|
|
function New_Error_Mal_Type (Str : Mal_String) return Mal_Handle is
|
2015-03-28 21:44:29 +03:00
|
|
|
begin
|
|
|
|
return Smart_Pointers.New_Ptr
|
|
|
|
(new Error_Mal_Type'(Mal_Type with Error_Msg =>
|
|
|
|
Ada.Strings.Unbounded.To_Unbounded_String (Str)));
|
|
|
|
end New_Error_Mal_Type;
|
|
|
|
|
|
|
|
overriding function Sym_Type (T : Error_Mal_Type) return Sym_Types is
|
|
|
|
begin
|
|
|
|
return Error;
|
|
|
|
end Sym_Type;
|
|
|
|
|
2015-05-02 00:55:52 +03:00
|
|
|
overriding function To_Str
|
|
|
|
(T : Error_Mal_Type; Print_Readably : Boolean := True)
|
|
|
|
return Mal_String is
|
2015-03-28 21:44:29 +03:00
|
|
|
begin
|
|
|
|
return Ada.Strings.Unbounded.To_String (T.Error_Msg);
|
|
|
|
end To_Str;
|
|
|
|
|
|
|
|
|
2015-04-19 20:08:51 +03:00
|
|
|
function Nodes_Equal (A, B : Mal_Handle) return Boolean is
|
|
|
|
begin
|
|
|
|
if (not Is_Null (A) and not Is_Null (B)) and then
|
|
|
|
Deref (A).Sym_Type = Deref (B).Sym_Type then
|
|
|
|
if Deref (A).Sym_Type = Node then
|
|
|
|
return
|
2015-08-15 00:18:59 +03:00
|
|
|
Nodes_Equal (Deref_Node (A).Data, Deref_Node (B).Data) and then
|
|
|
|
Nodes_Equal (Deref_Node (A).Next, Deref_Node (B).Next);
|
2015-04-19 20:08:51 +03:00
|
|
|
else
|
|
|
|
return A = B;
|
|
|
|
end if;
|
|
|
|
elsif Is_Null (A) and Is_Null (B) then
|
|
|
|
return True;
|
|
|
|
else -- either one of the args is null or the sym_types don't match
|
|
|
|
return False;
|
|
|
|
end if;
|
|
|
|
end Nodes_Equal;
|
|
|
|
|
2015-08-15 00:18:59 +03:00
|
|
|
|
|
|
|
function New_Node_Mal_Type
|
|
|
|
(Data : Mal_Handle;
|
|
|
|
Next : Mal_Handle := Smart_Pointers.Null_Smart_Pointer)
|
2015-04-03 16:35:24 +03:00
|
|
|
return Mal_Handle is
|
2015-03-28 21:44:29 +03:00
|
|
|
begin
|
|
|
|
return Smart_Pointers.New_Ptr
|
2015-08-15 00:18:59 +03:00
|
|
|
(new Node_Mal_Type'
|
|
|
|
(Mal_Type with Data => Data, Next => Next));
|
2015-03-28 21:44:29 +03:00
|
|
|
end New_Node_Mal_Type;
|
|
|
|
|
2015-08-15 00:18:59 +03:00
|
|
|
|
2015-03-28 21:44:29 +03:00
|
|
|
overriding function Sym_Type (T : Node_Mal_Type) return Sym_Types is
|
|
|
|
begin
|
|
|
|
return Node;
|
|
|
|
end Sym_Type;
|
|
|
|
|
2015-07-09 01:18:19 +03:00
|
|
|
|
2015-04-02 01:36:29 +03:00
|
|
|
-- Get the first item in the list:
|
2015-04-03 16:35:24 +03:00
|
|
|
function Car (L : List_Mal_Type) return Mal_Handle is
|
2015-04-02 01:36:29 +03:00
|
|
|
begin
|
|
|
|
if Is_Null (L.The_List) then
|
|
|
|
return Smart_Pointers.Null_Smart_Pointer;
|
|
|
|
else
|
2015-08-15 00:18:59 +03:00
|
|
|
return Deref_Node (L.The_List).Data;
|
2015-04-02 01:36:29 +03:00
|
|
|
end if;
|
|
|
|
end Car;
|
|
|
|
|
|
|
|
|
|
|
|
-- Get the rest of the list (second item onwards)
|
2015-04-05 22:27:47 +03:00
|
|
|
function Cdr (L : List_Mal_Type) return Mal_Handle is
|
2015-08-15 00:18:59 +03:00
|
|
|
Res : Mal_Handle;
|
|
|
|
LP : List_Ptr;
|
2015-04-02 01:36:29 +03:00
|
|
|
begin
|
2015-08-15 00:18:59 +03:00
|
|
|
|
|
|
|
Res := New_List_Mal_Type (L.List_Type);
|
|
|
|
|
2015-04-05 22:27:47 +03:00
|
|
|
if Is_Null (L.The_List) or else
|
2015-08-15 00:18:59 +03:00
|
|
|
Is_Null (Deref_Node (L.The_List).Next) then
|
|
|
|
return Res;
|
|
|
|
else
|
|
|
|
LP := Deref_List (Res);
|
|
|
|
LP.The_List := Deref_Node (L.The_List).Next;
|
|
|
|
LP.Last_Elem := L.Last_Elem;
|
|
|
|
return Res;
|
2015-04-02 01:36:29 +03:00
|
|
|
end if;
|
|
|
|
end Cdr;
|
|
|
|
|
2015-08-15 00:18:59 +03:00
|
|
|
|
2015-04-05 22:27:47 +03:00
|
|
|
function Length (L : List_Mal_Type) return Natural is
|
2015-08-15 00:18:59 +03:00
|
|
|
Res : Natural;
|
|
|
|
NP : Node_Ptr;
|
|
|
|
begin
|
|
|
|
Res := 0;
|
|
|
|
NP := Deref_Node (L.The_List);
|
|
|
|
while NP /= null loop
|
|
|
|
Res := Res + 1;
|
|
|
|
NP := Deref_Node (NP.Next);
|
|
|
|
end loop;
|
|
|
|
return Res;
|
2015-04-05 22:27:47 +03:00
|
|
|
end Length;
|
|
|
|
|
2015-08-15 00:18:59 +03:00
|
|
|
|
2015-04-19 20:08:51 +03:00
|
|
|
function Is_Null (L : List_Mal_Type) return Boolean is
|
|
|
|
use Smart_Pointers;
|
|
|
|
begin
|
|
|
|
return Smart_Pointers."="(L.The_List, Null_Smart_Pointer);
|
|
|
|
end Is_Null;
|
|
|
|
|
2015-08-15 00:18:59 +03:00
|
|
|
|
2015-04-02 01:36:29 +03:00
|
|
|
function Null_List (L : List_Types) return List_Mal_Type is
|
|
|
|
begin
|
|
|
|
return (Mal_Type with List_Type => L,
|
2015-08-15 00:18:59 +03:00
|
|
|
The_List => Smart_Pointers.Null_Smart_Pointer,
|
|
|
|
Last_Elem => Smart_Pointers.Null_Smart_Pointer);
|
2015-04-02 01:36:29 +03:00
|
|
|
end Null_List;
|
|
|
|
|
|
|
|
|
|
|
|
function Map
|
|
|
|
(Func_Ptr : Func_Access;
|
|
|
|
L : List_Mal_Type)
|
2015-04-03 16:35:24 +03:00
|
|
|
return Mal_Handle is
|
2015-08-15 00:18:59 +03:00
|
|
|
|
|
|
|
Res, Old_List, First_New_Node, New_List : Mal_Handle;
|
|
|
|
LP : List_Ptr;
|
|
|
|
|
2015-04-02 01:36:29 +03:00
|
|
|
begin
|
2015-08-15 00:18:59 +03:00
|
|
|
|
|
|
|
Res := New_List_Mal_Type (List_Type => L.Get_List_Type);
|
|
|
|
|
|
|
|
Old_List := L.The_List;
|
|
|
|
|
|
|
|
if Is_Null (Old_List) then
|
|
|
|
return Res;
|
2015-04-02 01:36:29 +03:00
|
|
|
end if;
|
2015-08-15 00:18:59 +03:00
|
|
|
|
|
|
|
First_New_Node := New_Node_Mal_Type (Func_Ptr.all (Deref_Node (Old_List).Data));
|
|
|
|
|
|
|
|
New_List := First_New_Node;
|
|
|
|
|
|
|
|
Old_List := Deref_Node (Old_List).Next;
|
|
|
|
|
|
|
|
while not Is_Null (Old_List) loop
|
|
|
|
|
|
|
|
Deref_Node (New_List).Next :=
|
|
|
|
New_Node_Mal_Type (Func_Ptr.all (Deref_Node (Old_List).Data));
|
|
|
|
|
|
|
|
New_List := Deref_Node (New_List).Next;
|
|
|
|
|
|
|
|
Old_List := Deref_Node (Old_List).Next;
|
|
|
|
|
|
|
|
end loop;
|
|
|
|
|
|
|
|
LP := Deref_List (Res);
|
|
|
|
LP.The_List := First_New_Node;
|
|
|
|
LP.Last_Elem := New_List;
|
|
|
|
|
|
|
|
return Res;
|
|
|
|
|
2015-04-02 01:36:29 +03:00
|
|
|
end Map;
|
|
|
|
|
2015-08-15 00:18:59 +03:00
|
|
|
|
2015-04-02 01:36:29 +03:00
|
|
|
function Reduce
|
|
|
|
(Func_Ptr : Binary_Func_Access;
|
|
|
|
L : List_Mal_Type)
|
2015-04-03 16:35:24 +03:00
|
|
|
return Mal_Handle is
|
2015-08-15 00:18:59 +03:00
|
|
|
|
|
|
|
C_Node : Node_Ptr;
|
|
|
|
Res : Mal_Handle;
|
|
|
|
use Smart_Pointers;
|
|
|
|
|
2015-04-02 01:36:29 +03:00
|
|
|
begin
|
2015-08-15 00:18:59 +03:00
|
|
|
|
|
|
|
C_Node := Deref_Node (L.The_List);
|
|
|
|
|
|
|
|
if C_Node = null then
|
|
|
|
return Smart_Pointers.Null_Smart_Pointer;
|
2015-04-02 01:36:29 +03:00
|
|
|
end if;
|
2015-08-15 00:18:59 +03:00
|
|
|
|
|
|
|
Res := C_Node.Data;
|
|
|
|
while not Is_Null (C_Node.Next) loop
|
|
|
|
C_Node := Deref_Node (C_Node.Next);
|
|
|
|
Res := Func_Ptr (Res, C_Node.Data);
|
|
|
|
end loop;
|
|
|
|
|
|
|
|
return Res;
|
|
|
|
|
2015-04-02 01:36:29 +03:00
|
|
|
end Reduce;
|
|
|
|
|
2015-08-15 00:18:59 +03:00
|
|
|
|
2015-05-02 00:55:52 +03:00
|
|
|
overriding function To_Str
|
|
|
|
(T : Node_Mal_Type; Print_Readably : Boolean := True)
|
|
|
|
return Mal_String is
|
2015-03-28 21:44:29 +03:00
|
|
|
begin
|
2015-08-15 00:18:59 +03:00
|
|
|
if Is_Null (T.Data) then
|
2015-03-28 21:44:29 +03:00
|
|
|
-- Left is null and by implication so is right.
|
|
|
|
return "";
|
2015-08-15 00:18:59 +03:00
|
|
|
elsif Is_Null (T.Next) then
|
2015-03-28 21:44:29 +03:00
|
|
|
-- Left is not null but right is.
|
2015-08-15 00:18:59 +03:00
|
|
|
return To_Str (Deref (T.Data).all, Print_Readably);
|
2015-03-28 21:44:29 +03:00
|
|
|
else
|
|
|
|
-- Left and right are both not null.
|
2015-08-15 00:18:59 +03:00
|
|
|
return To_Str (Deref (T.Data).all, Print_Readably) &
|
2015-03-28 21:44:29 +03:00
|
|
|
" " &
|
2015-08-15 00:18:59 +03:00
|
|
|
To_Str (Deref (T.Next).all, Print_Readably);
|
2015-03-28 21:44:29 +03:00
|
|
|
end if;
|
|
|
|
end To_Str;
|
|
|
|
|
2015-08-15 00:18:59 +03:00
|
|
|
|
|
|
|
function Cat_Str (T : Node_Mal_Type; Print_Readably : Boolean := True)
|
|
|
|
return Mal_String is
|
2015-05-02 00:55:52 +03:00
|
|
|
begin
|
2015-08-15 00:18:59 +03:00
|
|
|
if Is_Null (T.Data) then
|
2015-05-02 00:55:52 +03:00
|
|
|
-- Left is null and by implication so is right.
|
|
|
|
return "";
|
2015-08-15 00:18:59 +03:00
|
|
|
elsif Is_Null (T.Next) then
|
2015-05-02 00:55:52 +03:00
|
|
|
-- Left is not null but right is.
|
2015-08-15 00:18:59 +03:00
|
|
|
return To_Str (Deref (T.Data).all, Print_Readably);
|
2015-05-02 00:55:52 +03:00
|
|
|
|
|
|
|
-- Left and right are both not null.
|
|
|
|
else
|
2015-08-15 00:18:59 +03:00
|
|
|
return To_Str (Deref (T.Data).all, Print_Readably) &
|
|
|
|
Cat_Str (Deref_Node (T.Next).all, Print_Readably);
|
2015-05-02 00:55:52 +03:00
|
|
|
end if;
|
|
|
|
end Cat_Str;
|
|
|
|
|
2015-08-15 00:18:59 +03:00
|
|
|
|
2015-04-03 16:35:24 +03:00
|
|
|
function Deref_Node (SP : Mal_Handle) return Node_Ptr is
|
2015-03-28 21:44:29 +03:00
|
|
|
begin
|
|
|
|
return Node_Ptr (Deref (SP));
|
|
|
|
end Deref_Node;
|
|
|
|
|
2015-03-23 01:37:42 +03:00
|
|
|
|
2015-04-19 20:08:51 +03:00
|
|
|
function "=" (A, B : List_Mal_Type) return Boolean is
|
|
|
|
begin
|
2015-04-22 23:27:43 +03:00
|
|
|
return Nodes_Equal (A.The_List, B.The_List);
|
2015-04-19 20:08:51 +03:00
|
|
|
end "=";
|
|
|
|
|
|
|
|
function New_List_Mal_Type
|
|
|
|
(The_List : List_Mal_Type)
|
|
|
|
return Mal_Handle is
|
|
|
|
begin
|
|
|
|
return Smart_Pointers.New_Ptr
|
|
|
|
(new List_Mal_Type'(Mal_Type with
|
|
|
|
List_Type => The_List.List_Type,
|
2015-08-15 00:18:59 +03:00
|
|
|
The_List => The_List.The_List,
|
|
|
|
Last_Elem => The_List.Last_Elem));
|
2015-04-19 20:08:51 +03:00
|
|
|
end New_List_Mal_Type;
|
|
|
|
|
2015-03-23 01:37:42 +03:00
|
|
|
|
2015-04-02 01:36:29 +03:00
|
|
|
function New_List_Mal_Type
|
|
|
|
(List_Type : List_Types;
|
2015-04-03 16:35:24 +03:00
|
|
|
The_First_Node : Mal_Handle := Smart_Pointers.Null_Smart_Pointer)
|
|
|
|
return Mal_Handle is
|
2015-03-28 21:44:29 +03:00
|
|
|
begin
|
|
|
|
return Smart_Pointers.New_Ptr
|
2015-08-15 00:18:59 +03:00
|
|
|
(new List_Mal_Type'
|
|
|
|
(Mal_Type with
|
|
|
|
List_Type => List_Type,
|
|
|
|
The_List => The_First_Node,
|
|
|
|
Last_Elem => The_First_Node));
|
2015-03-28 21:44:29 +03:00
|
|
|
end New_List_Mal_Type;
|
|
|
|
|
2015-08-15 00:18:59 +03:00
|
|
|
|
2016-03-15 11:05:20 +03:00
|
|
|
function Make_New_List (Handle_List : Handle_Lists) return Mal_Handle is
|
|
|
|
|
|
|
|
List_SP : Mal_Handle;
|
|
|
|
List_P : List_Ptr;
|
|
|
|
|
|
|
|
begin
|
|
|
|
List_SP := New_List_Mal_Type (List_Type => List_List);
|
|
|
|
List_P := Deref_List (List_SP);
|
|
|
|
for I in Handle_List'Range loop
|
|
|
|
Append (List_P.all, Handle_List (I));
|
|
|
|
end loop;
|
|
|
|
return List_SP;
|
|
|
|
end Make_New_List;
|
|
|
|
|
|
|
|
|
2015-03-28 21:44:29 +03:00
|
|
|
overriding function Sym_Type (T : List_Mal_Type) return Sym_Types is
|
2015-03-23 01:37:42 +03:00
|
|
|
begin
|
2015-03-28 21:44:29 +03:00
|
|
|
return List;
|
|
|
|
end Sym_Type;
|
|
|
|
|
2015-08-15 00:18:59 +03:00
|
|
|
|
2015-04-02 01:36:29 +03:00
|
|
|
function Get_List_Type (L : List_Mal_Type) return List_Types is
|
|
|
|
begin
|
|
|
|
return L.List_Type;
|
|
|
|
end Get_List_Type;
|
|
|
|
|
2015-08-15 00:18:59 +03:00
|
|
|
|
2015-04-22 23:27:43 +03:00
|
|
|
function Prepend (Op : Mal_Handle; To_List : List_Mal_Type)
|
|
|
|
return Mal_Handle is
|
|
|
|
begin
|
|
|
|
return New_List_Mal_Type
|
2015-08-08 11:30:32 +03:00
|
|
|
(List_List,
|
2015-04-22 23:27:43 +03:00
|
|
|
New_Node_Mal_Type (Op, To_List.The_List));
|
|
|
|
end Prepend;
|
|
|
|
|
2015-07-09 01:18:19 +03:00
|
|
|
|
2015-04-03 16:35:24 +03:00
|
|
|
procedure Append (To_List : in out List_Mal_Type; Op : Mal_Handle) is
|
2015-03-28 21:44:29 +03:00
|
|
|
begin
|
|
|
|
if Is_Null (Op) then
|
|
|
|
return; -- Say what
|
|
|
|
end if;
|
2015-08-15 00:18:59 +03:00
|
|
|
|
|
|
|
-- If the list is null just insert the new element
|
|
|
|
-- else use the last_elem pointer to insert it and then update it.
|
2015-03-28 21:44:29 +03:00
|
|
|
if Is_Null (To_List.The_List) then
|
2015-08-15 00:18:59 +03:00
|
|
|
To_List.The_List := New_Node_Mal_Type (Op);
|
|
|
|
To_List.Last_Elem := To_List.The_List;
|
|
|
|
else
|
|
|
|
Deref_Node (To_List.Last_Elem).Next := New_Node_Mal_Type (Op);
|
|
|
|
To_List.Last_Elem := Deref_Node (To_List.Last_Elem).Next;
|
2015-03-23 01:37:42 +03:00
|
|
|
end if;
|
2015-03-28 21:44:29 +03:00
|
|
|
end Append;
|
2015-03-23 01:37:42 +03:00
|
|
|
|
2015-07-09 01:18:19 +03:00
|
|
|
|
2015-08-15 00:18:59 +03:00
|
|
|
-- Duplicate copies the list (logically). This is to allow concatenation,
|
2015-08-08 11:30:32 +03:00
|
|
|
-- The result is always a List_List.
|
2015-07-09 01:18:19 +03:00
|
|
|
function Duplicate (The_List : List_Mal_Type) return Mal_Handle is
|
2015-08-15 00:18:59 +03:00
|
|
|
Res, Old_List, First_New_Node, New_List : Mal_Handle;
|
|
|
|
LP : List_Ptr;
|
2015-07-09 01:18:19 +03:00
|
|
|
begin
|
2015-08-15 00:18:59 +03:00
|
|
|
|
|
|
|
Res := New_List_Mal_Type (List_List);
|
|
|
|
|
|
|
|
Old_List := The_List.The_List;
|
|
|
|
|
|
|
|
if Is_Null (Old_List) then
|
|
|
|
return Res;
|
2015-07-09 01:18:19 +03:00
|
|
|
end if;
|
2015-08-15 00:18:59 +03:00
|
|
|
|
|
|
|
First_New_Node := New_Node_Mal_Type (Deref_Node (Old_List).Data);
|
|
|
|
New_List := First_New_Node;
|
|
|
|
Old_List := Deref_Node (Old_List).Next;
|
|
|
|
|
|
|
|
while not Is_Null (Old_List) loop
|
|
|
|
|
|
|
|
Deref_Node (New_List).Next := New_Node_Mal_Type (Deref_Node (Old_List).Data);
|
|
|
|
New_List := Deref_Node (New_List).Next;
|
|
|
|
Old_List := Deref_Node (Old_List).Next;
|
|
|
|
|
|
|
|
end loop;
|
|
|
|
|
|
|
|
LP := Deref_List (Res);
|
|
|
|
LP.The_List := First_New_Node;
|
|
|
|
LP.Last_Elem := New_List;
|
|
|
|
|
|
|
|
return Res;
|
|
|
|
|
2015-07-09 01:18:19 +03:00
|
|
|
end Duplicate;
|
|
|
|
|
|
|
|
|
2015-08-15 00:18:59 +03:00
|
|
|
function Nth (L : List_Mal_Type; N : Natural) return Mal_Handle is
|
|
|
|
|
|
|
|
C : Natural;
|
|
|
|
Next : Mal_Handle;
|
|
|
|
|
2015-07-09 01:18:19 +03:00
|
|
|
begin
|
2015-08-15 00:18:59 +03:00
|
|
|
|
|
|
|
C := 0;
|
|
|
|
|
|
|
|
Next := L.The_List;
|
|
|
|
|
|
|
|
while not Is_Null (Next) loop
|
|
|
|
|
|
|
|
if C >= N then
|
2015-11-27 01:43:11 +03:00
|
|
|
return Deref_Node (Next).Data;
|
2015-08-15 00:18:59 +03:00
|
|
|
end if;
|
|
|
|
|
|
|
|
C := C + 1;
|
|
|
|
|
|
|
|
Next := Deref_Node (Next).Next;
|
|
|
|
|
2015-07-09 01:18:19 +03:00
|
|
|
end loop;
|
2015-08-15 00:18:59 +03:00
|
|
|
|
Test uncaught throw, catchless try* . Fix 46 impls.
Fixes made to: ada, c, chuck, clojure, coffee, common-lisp, cpp,
crystal, d, dart, elm, erlang, es6, factor, fsharp, gnu-smalltalk,
groovy, guile, haxe, hy, js, livescript, matlab, miniMAL, nasm, nim,
objc, objpascal, ocaml, perl, perl6, php, plsql, ps, python, r,
rpython, ruby, scheme, swift3, tcl, ts, vb, vimscript, wasm, yorick.
Catchless try* test is an optional test. Not all implementations
support catchless try* but a number were fixed so they at least don't
crash on catchless try*.
2018-12-03 22:20:44 +03:00
|
|
|
raise Runtime_Exception with "Nth (list): Index out of range";
|
2015-08-15 00:18:59 +03:00
|
|
|
|
|
|
|
end Nth;
|
|
|
|
|
|
|
|
|
2016-03-21 00:08:28 +03:00
|
|
|
function Concat (Rest_Handle : List_Mal_Type)
|
2015-07-09 01:18:19 +03:00
|
|
|
return Types.Mal_Handle is
|
2016-02-12 02:48:10 +03:00
|
|
|
Rest_List : Types.List_Mal_Type;
|
|
|
|
List : Types.List_Class_Ptr;
|
2015-07-09 01:18:19 +03:00
|
|
|
Res_List_Handle, Dup_List : Mal_Handle;
|
2015-08-15 00:18:59 +03:00
|
|
|
Last_Node_P : Mal_Handle := Smart_Pointers.Null_Smart_Pointer;
|
2015-07-09 01:18:19 +03:00
|
|
|
begin
|
|
|
|
Rest_List := Rest_Handle;
|
2015-07-09 20:42:36 +03:00
|
|
|
|
|
|
|
-- Set the result to the null list.
|
|
|
|
Res_List_Handle := New_List_Mal_Type (List_List);
|
|
|
|
|
2015-07-09 01:18:19 +03:00
|
|
|
while not Is_Null (Rest_List) loop
|
2015-07-09 20:42:36 +03:00
|
|
|
|
2015-07-09 01:18:19 +03:00
|
|
|
-- Find the next list in the list...
|
2016-02-12 02:48:10 +03:00
|
|
|
List := Deref_List_Class (Car (Rest_List));
|
2015-08-15 00:18:59 +03:00
|
|
|
|
2015-07-09 01:18:19 +03:00
|
|
|
-- Duplicate nodes to its contents.
|
2016-02-12 02:48:10 +03:00
|
|
|
Dup_List := Duplicate (List.all);
|
2015-07-09 01:18:19 +03:00
|
|
|
|
2016-01-18 02:12:42 +03:00
|
|
|
-- If we haven't inserted a list yet, then take the duplicated list whole.
|
2015-08-15 00:18:59 +03:00
|
|
|
if Is_Null (Last_Node_P) then
|
2015-07-09 01:18:19 +03:00
|
|
|
Res_List_Handle := Dup_List;
|
|
|
|
else
|
2015-08-15 00:18:59 +03:00
|
|
|
-- Note that the first inserted list may have been the null list
|
|
|
|
-- and so may the newly duplicated one...
|
|
|
|
Deref_Node (Last_Node_P).Next := Deref_List (Dup_List).The_List;
|
|
|
|
if Is_Null (Deref_List (Res_List_Handle).The_List) then
|
|
|
|
Deref_List (Res_list_Handle).The_List :=
|
|
|
|
Deref_List (Dup_List).The_List;
|
|
|
|
end if;
|
|
|
|
if not Is_Null (Deref_List (Dup_List).Last_Elem) then
|
|
|
|
Deref_List (Res_List_Handle).Last_Elem :=
|
|
|
|
Deref_List (Dup_List).Last_Elem;
|
|
|
|
end if;
|
2015-07-09 01:18:19 +03:00
|
|
|
end if;
|
|
|
|
|
2015-08-15 00:18:59 +03:00
|
|
|
Last_Node_P := Deref_List (Dup_List).Last_Elem;
|
|
|
|
|
2015-07-09 01:18:19 +03:00
|
|
|
Rest_List := Deref_List (Cdr (Rest_List)).all;
|
2015-08-15 00:18:59 +03:00
|
|
|
|
2015-07-09 01:18:19 +03:00
|
|
|
end loop;
|
2015-08-15 00:18:59 +03:00
|
|
|
|
2015-07-09 01:18:19 +03:00
|
|
|
return Res_List_Handle;
|
2015-08-15 00:18:59 +03:00
|
|
|
|
2015-07-09 01:18:19 +03:00
|
|
|
end Concat;
|
|
|
|
|
|
|
|
|
2016-02-13 01:18:27 +03:00
|
|
|
procedure Add_Defs (Defs : List_Mal_Type; Env : Envs.Env_Handle) is
|
|
|
|
D, L : List_Mal_Type;
|
|
|
|
begin
|
|
|
|
D := Defs;
|
|
|
|
while not Is_Null (D) loop
|
|
|
|
L := Deref_List (Cdr (D)).all;
|
|
|
|
Envs.Set
|
|
|
|
(Env,
|
2016-02-23 01:22:56 +03:00
|
|
|
Deref_Sym (Car (D)).Get_Sym,
|
2016-03-15 11:05:20 +03:00
|
|
|
Eval_Callback.Eval.all (Car (L), Env));
|
2016-02-13 01:18:27 +03:00
|
|
|
D := Deref_List (Cdr(L)).all;
|
|
|
|
end loop;
|
|
|
|
end Add_Defs;
|
|
|
|
|
|
|
|
|
2015-04-03 16:35:24 +03:00
|
|
|
function Deref_List (SP : Mal_Handle) return List_Ptr is
|
2015-03-23 01:37:42 +03:00
|
|
|
begin
|
2015-03-28 21:44:29 +03:00
|
|
|
return List_Ptr (Deref (SP));
|
|
|
|
end Deref_List;
|
2015-03-23 01:37:42 +03:00
|
|
|
|
2015-03-28 21:44:29 +03:00
|
|
|
|
2016-02-12 02:48:10 +03:00
|
|
|
function Deref_List_Class (SP : Mal_Handle) return List_Class_Ptr is
|
|
|
|
begin
|
|
|
|
return List_Class_Ptr (Deref (SP));
|
|
|
|
end Deref_List_Class;
|
|
|
|
|
|
|
|
|
2015-05-02 00:55:52 +03:00
|
|
|
overriding function To_Str
|
|
|
|
(T : List_Mal_Type; Print_Readably : Boolean := True)
|
|
|
|
return Mal_String is
|
2015-03-23 01:37:42 +03:00
|
|
|
begin
|
2015-03-28 21:44:29 +03:00
|
|
|
if Is_Null (T.The_List) then
|
|
|
|
return Opening (T.List_Type) &
|
|
|
|
Closing (T.List_Type);
|
|
|
|
else
|
|
|
|
return Opening (T.List_Type) &
|
2015-05-02 00:55:52 +03:00
|
|
|
To_String (Deref (T.The_List).all, Print_Readably) &
|
2015-03-28 21:44:29 +03:00
|
|
|
Closing (T.List_Type);
|
|
|
|
end if;
|
|
|
|
end To_Str;
|
2015-03-23 01:37:42 +03:00
|
|
|
|
|
|
|
|
2015-05-02 00:55:52 +03:00
|
|
|
function Pr_Str (T : List_Mal_Type; Print_Readably : Boolean := True)
|
|
|
|
return Mal_String is
|
|
|
|
begin
|
|
|
|
if Is_Null (T.The_List) then
|
|
|
|
return "";
|
|
|
|
else
|
|
|
|
return To_String (Deref_Node (T.The_List).all, Print_Readably);
|
|
|
|
end if;
|
|
|
|
end Pr_Str;
|
|
|
|
|
|
|
|
|
|
|
|
function Cat_Str (T : List_Mal_Type; Print_Readably : Boolean := True)
|
|
|
|
return Mal_String is
|
|
|
|
begin
|
|
|
|
if Is_Null (T.The_List) then
|
|
|
|
return "";
|
|
|
|
else
|
|
|
|
return Cat_Str (Deref_Node (T.The_List).all, Print_Readably);
|
|
|
|
end if;
|
|
|
|
end Cat_Str;
|
|
|
|
|
|
|
|
|
2015-03-17 01:48:48 +03:00
|
|
|
function Opening (LT : List_Types) return Character is
|
|
|
|
Res : Character;
|
|
|
|
begin
|
|
|
|
case LT is
|
|
|
|
when List_List =>
|
|
|
|
Res := '(';
|
|
|
|
when Vector_List =>
|
|
|
|
Res := '[';
|
|
|
|
when Hashed_List =>
|
|
|
|
Res := '{';
|
|
|
|
end case;
|
|
|
|
return Res;
|
|
|
|
end Opening;
|
|
|
|
|
|
|
|
|
|
|
|
function Closing (LT : List_Types) return Character is
|
|
|
|
Res : Character;
|
|
|
|
begin
|
|
|
|
case LT is
|
|
|
|
when List_List =>
|
|
|
|
Res := ')';
|
|
|
|
when Vector_List =>
|
|
|
|
Res := ']';
|
|
|
|
when Hashed_List =>
|
|
|
|
Res := '}';
|
|
|
|
end case;
|
|
|
|
return Res;
|
|
|
|
end Closing;
|
|
|
|
|
|
|
|
|
2015-04-19 20:08:51 +03:00
|
|
|
function New_Lambda_Mal_Type
|
2016-03-15 11:05:20 +03:00
|
|
|
(Params : Mal_Handle; Expr : Mal_Handle; Env : Envs.Env_Handle)
|
2015-04-19 20:08:51 +03:00
|
|
|
return Mal_Handle is
|
|
|
|
begin
|
|
|
|
return Smart_Pointers.New_Ptr
|
|
|
|
(new Lambda_Mal_Type'
|
2016-03-15 11:05:20 +03:00
|
|
|
(Mal_Type with
|
|
|
|
Params => Params,
|
|
|
|
Expr => Expr,
|
|
|
|
Env => Env,
|
|
|
|
Is_Macro => False));
|
2015-04-19 20:08:51 +03:00
|
|
|
end New_Lambda_Mal_Type;
|
|
|
|
|
|
|
|
overriding function Sym_Type (T : Lambda_Mal_Type) return Sym_Types is
|
|
|
|
begin
|
|
|
|
return Lambda;
|
|
|
|
end Sym_Type;
|
|
|
|
|
|
|
|
function Get_Env (L : Lambda_Mal_Type) return Envs.Env_Handle is
|
|
|
|
begin
|
|
|
|
return L.Env;
|
|
|
|
end Get_Env;
|
|
|
|
|
|
|
|
procedure Set_Env (L : in out Lambda_Mal_Type; Env : Envs.Env_Handle) is
|
|
|
|
begin
|
|
|
|
L.Env := Env;
|
|
|
|
end Set_Env;
|
|
|
|
|
|
|
|
function Get_Params (L : Lambda_Mal_Type) return Mal_Handle is
|
|
|
|
begin
|
2016-02-12 02:48:10 +03:00
|
|
|
if Deref (L.Params).Sym_Type = List and then
|
|
|
|
Deref_List (L.Params).Get_List_Type = Vector_List then
|
|
|
|
-- Its a vector and we need a list...
|
|
|
|
return Deref_List_Class (L.Params).Duplicate;
|
|
|
|
else
|
|
|
|
return L.Params;
|
|
|
|
end if;
|
2015-04-19 20:08:51 +03:00
|
|
|
end Get_Params;
|
|
|
|
|
|
|
|
function Get_Expr (L : Lambda_Mal_Type) return Mal_Handle is
|
|
|
|
begin
|
|
|
|
return L.Expr;
|
|
|
|
end Get_Expr;
|
|
|
|
|
2015-08-12 00:42:47 +03:00
|
|
|
function Get_Is_Macro (L : Lambda_Mal_Type) return Boolean is
|
|
|
|
begin
|
|
|
|
return L.Is_Macro;
|
|
|
|
end Get_Is_Macro;
|
|
|
|
|
|
|
|
procedure Set_Is_Macro (L : in out Lambda_Mal_Type; B : Boolean) is
|
|
|
|
begin
|
|
|
|
L.Is_Macro := B;
|
|
|
|
end Set_Is_Macro;
|
|
|
|
|
|
|
|
|
2016-02-26 01:33:38 +03:00
|
|
|
function Apply
|
|
|
|
(L : Lambda_Mal_Type;
|
2016-03-15 11:05:20 +03:00
|
|
|
Param_List : Mal_Handle)
|
2016-02-26 01:33:38 +03:00
|
|
|
return Mal_Handle is
|
|
|
|
|
|
|
|
E : Envs.Env_Handle;
|
|
|
|
Param_Names : List_Mal_Type;
|
|
|
|
Res : Mal_Handle;
|
|
|
|
|
|
|
|
begin
|
|
|
|
|
2016-03-15 11:05:20 +03:00
|
|
|
E := Envs.New_Env (L.Env);
|
2016-02-26 01:33:38 +03:00
|
|
|
|
|
|
|
Param_Names := Deref_List (L.Get_Params).all;
|
|
|
|
|
|
|
|
if Envs.Bind (E, Param_Names, Deref_List (Param_List).all) then
|
|
|
|
|
2016-03-15 11:05:20 +03:00
|
|
|
Res := Eval_Callback.Eval.all (L.Get_Expr, E);
|
2016-02-26 01:33:38 +03:00
|
|
|
|
|
|
|
else
|
|
|
|
|
Test uncaught throw, catchless try* . Fix 46 impls.
Fixes made to: ada, c, chuck, clojure, coffee, common-lisp, cpp,
crystal, d, dart, elm, erlang, es6, factor, fsharp, gnu-smalltalk,
groovy, guile, haxe, hy, js, livescript, matlab, miniMAL, nasm, nim,
objc, objpascal, ocaml, perl, perl6, php, plsql, ps, python, r,
rpython, ruby, scheme, swift3, tcl, ts, vb, vimscript, wasm, yorick.
Catchless try* test is an optional test. Not all implementations
support catchless try* but a number were fixed so they at least don't
crash on catchless try*.
2018-12-03 22:20:44 +03:00
|
|
|
raise Runtime_Exception with "Bind failed in Apply";
|
2016-02-26 01:33:38 +03:00
|
|
|
|
|
|
|
end if;
|
|
|
|
|
|
|
|
return Res;
|
|
|
|
|
|
|
|
end Apply;
|
|
|
|
|
|
|
|
|
2015-08-12 00:42:47 +03:00
|
|
|
function Get_Macro (T : Mal_Handle; Env : Envs.Env_Handle) return Lambda_Ptr is
|
|
|
|
L : List_Mal_Type;
|
|
|
|
First_Elem, Func : Mal_Handle;
|
|
|
|
begin
|
|
|
|
|
|
|
|
if Deref (T).Sym_Type /= List then
|
|
|
|
return null;
|
|
|
|
end if;
|
|
|
|
|
|
|
|
L := Deref_List (T).all;
|
|
|
|
|
|
|
|
if Is_Null (L) then
|
|
|
|
return null;
|
|
|
|
end if;
|
|
|
|
|
|
|
|
First_Elem := Car (L);
|
|
|
|
|
2016-02-23 01:22:56 +03:00
|
|
|
if Deref (First_Elem).Sym_Type /= Sym then
|
2015-08-12 00:42:47 +03:00
|
|
|
return null;
|
|
|
|
end if;
|
|
|
|
|
2016-02-23 01:22:56 +03:00
|
|
|
Func := Envs.Get (Env, Deref_Sym (First_Elem).Get_Sym);
|
2015-08-12 00:42:47 +03:00
|
|
|
|
|
|
|
if Deref (Func).Sym_Type /= Lambda then
|
|
|
|
return null;
|
|
|
|
end if;
|
|
|
|
|
|
|
|
return Deref_Lambda (Func);
|
|
|
|
|
|
|
|
exception
|
|
|
|
when Envs.Not_Found => return null;
|
|
|
|
end Get_Macro;
|
|
|
|
|
|
|
|
|
2015-05-02 00:55:52 +03:00
|
|
|
overriding function To_Str
|
|
|
|
(T : Lambda_Mal_Type; Print_Readably : Boolean := True)
|
|
|
|
return Mal_String is
|
2015-04-19 20:08:51 +03:00
|
|
|
begin
|
|
|
|
-- return "(lambda " & Ada.Strings.Unbounded.To_String (T.Rep) & ")";
|
|
|
|
return "#<function>";
|
|
|
|
end To_Str;
|
|
|
|
|
|
|
|
function Deref_Lambda (SP : Mal_Handle) return Lambda_Ptr is
|
|
|
|
begin
|
|
|
|
return Lambda_Ptr (Deref (SP));
|
|
|
|
end Deref_Lambda;
|
|
|
|
|
|
|
|
|
2015-04-26 19:15:58 +03:00
|
|
|
function Arith_Op (A, B : Mal_Handle) return Mal_Handle is
|
2015-04-02 01:36:29 +03:00
|
|
|
use Types;
|
2015-06-09 22:59:05 +03:00
|
|
|
A_Sym_Type : Sym_Types;
|
|
|
|
B_Sym_Type : Sym_Types;
|
|
|
|
begin
|
|
|
|
|
|
|
|
if Is_Null (A) then
|
|
|
|
if Is_Null (B) then
|
|
|
|
-- both null, gotta be zero.
|
|
|
|
return New_Int_Mal_Type (0);
|
|
|
|
else -- A is null but B is not.
|
|
|
|
return Arith_Op (New_Int_Mal_Type (0), B);
|
|
|
|
end if;
|
|
|
|
elsif Is_Null (B) then
|
|
|
|
-- A is not null but B is.
|
|
|
|
return Arith_Op (A, New_Int_Mal_Type (0));
|
|
|
|
end if;
|
|
|
|
|
|
|
|
-- else both A and B and not null.:wq
|
|
|
|
A_Sym_Type := Deref (A).Sym_Type;
|
|
|
|
B_Sym_Type := Deref (B).Sym_Type;
|
2015-04-02 01:36:29 +03:00
|
|
|
if A_Sym_Type = Int and B_Sym_Type = Int then
|
|
|
|
return New_Int_Mal_Type
|
|
|
|
(Int_Op (Deref_Int (A).Get_Int_Val, Deref_Int (B).Get_Int_Val));
|
|
|
|
elsif A_Sym_Type = Int and B_Sym_Type = Floating then
|
|
|
|
return New_Float_Mal_Type
|
|
|
|
(Float_Op (Mal_Float (Deref_Int (A).Get_Int_Val),
|
|
|
|
Deref_Float (B).Get_Float_Val));
|
|
|
|
elsif A_Sym_Type = Floating and B_Sym_Type = Int then
|
|
|
|
return New_Float_Mal_Type
|
|
|
|
(Float_Op (Deref_Float (A).Get_Float_Val,
|
|
|
|
Mal_Float (Deref_Float (B).Get_Float_Val)));
|
2015-04-19 20:08:51 +03:00
|
|
|
elsif A_Sym_Type = Floating and B_Sym_Type = Floating then
|
2015-04-02 01:36:29 +03:00
|
|
|
return New_Float_Mal_Type
|
|
|
|
(Float_Op (Deref_Float (A).Get_Float_Val,
|
|
|
|
Deref_Float (B).Get_Float_Val));
|
2015-04-19 20:08:51 +03:00
|
|
|
else
|
|
|
|
if A_Sym_Type = Error then
|
|
|
|
return A;
|
|
|
|
elsif B_Sym_Type = Error then
|
|
|
|
return B;
|
|
|
|
else
|
|
|
|
return New_Error_Mal_Type ("Invalid operands");
|
|
|
|
end if;
|
2015-04-02 01:36:29 +03:00
|
|
|
end if;
|
2015-04-26 19:15:58 +03:00
|
|
|
end Arith_Op;
|
2015-04-19 20:08:51 +03:00
|
|
|
|
|
|
|
|
|
|
|
function Rel_Op (A, B : Mal_Handle) return Mal_Handle is
|
|
|
|
use Types;
|
|
|
|
A_Sym_Type : Sym_Types := Deref (A).Sym_Type;
|
|
|
|
B_Sym_Type : Sym_Types := Deref (B).Sym_Type;
|
|
|
|
begin
|
|
|
|
if A_Sym_Type = Int and B_Sym_Type = Int then
|
|
|
|
return New_Bool_Mal_Type
|
|
|
|
(Int_Rel_Op (Deref_Int (A).Get_Int_Val, Deref_Int (B).Get_Int_Val));
|
|
|
|
elsif A_Sym_Type = Int and B_Sym_Type = Floating then
|
|
|
|
return New_Bool_Mal_Type
|
|
|
|
(Float_Rel_Op (Mal_Float (Deref_Int (A).Get_Int_Val),
|
|
|
|
Deref_Float (B).Get_Float_Val));
|
|
|
|
elsif A_Sym_Type = Floating and B_Sym_Type = Int then
|
|
|
|
return New_Bool_Mal_Type
|
|
|
|
(Float_Rel_Op (Deref_Float (A).Get_Float_Val,
|
|
|
|
Mal_Float (Deref_Float (B).Get_Float_Val)));
|
|
|
|
else
|
|
|
|
return New_Bool_Mal_Type
|
|
|
|
(Float_Rel_Op (Deref_Float (A).Get_Float_Val,
|
|
|
|
Deref_Float (B).Get_Float_Val));
|
|
|
|
end if;
|
|
|
|
end Rel_Op;
|
|
|
|
|
|
|
|
|
2015-03-15 22:56:09 +03:00
|
|
|
end Types;
|