mirror of
https://github.com/kanaka/mal.git
synced 2024-09-21 02:27:10 +03:00
fbfe6784d2
- Add a `vec` built-in function in step7 so that `quasiquote` does not require `apply` from step9. - Introduce quasiquoteexpand special in order to help debugging step7. This may also prepare newcomers to understand step8. - Add soft tests. - Do not quote numbers, strings and so on. Should ideally have been in separate commits: - elisp: simplify and fix (keyword :k) - factor: fix copy/paste error in let*/step7, simplify eval-ast. - guile: improve list/vector types - haskell: revert evaluation during quasiquote - logo, make: cosmetic issues
228 lines
7.4 KiB
Ada
228 lines
7.4 KiB
Ada
with Err;
|
|
with Types.Fns;
|
|
with Types.Builtins;
|
|
|
|
package body Types.Sequences is
|
|
|
|
function "=" (Left, Right : in Instance) return Boolean is
|
|
-- Should become Left.all.Data = Right.all.Data when
|
|
-- https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89178 is fixed.
|
|
begin
|
|
return Left.Length = Right.Length
|
|
and then
|
|
(for all I in 1 .. Left.Data'Length => Left.Data (I) = Right.Data (I));
|
|
end "=";
|
|
|
|
function Concat (Args : in T_Array) return T is
|
|
Sum : Natural := 0;
|
|
First : Positive := 1;
|
|
Last : Natural;
|
|
begin
|
|
Err.Check ((for all A of Args => A.Kind in Kind_Sequence),
|
|
"expected sequences");
|
|
for Arg of Args loop
|
|
Sum := Sum + Arg.Sequence.all.Data'Length;
|
|
end loop;
|
|
declare
|
|
Ref : constant Sequence_Ptr := Constructor (Sum);
|
|
begin
|
|
for Arg of Args loop
|
|
Last := First - 1 + Arg.Sequence.all.Data'Last;
|
|
Ref.all.Data (First .. Last) := Arg.Sequence.all.Data;
|
|
First := Last + 1;
|
|
end loop;
|
|
return (Kind_List, Ref);
|
|
end;
|
|
end Concat;
|
|
|
|
function Conj (Args : in T_Array) return T is
|
|
begin
|
|
Err.Check (0 < Args'Length, "expected at least 1 parameter");
|
|
case Args (Args'First).Kind is
|
|
when Kind_Sequence =>
|
|
declare
|
|
Data : T_Array renames Args (Args'First).Sequence.all.Data;
|
|
Last : constant Natural := Args'Length - 1 + Data'Length;
|
|
-- Avoid exceptions until Ref is controlled.
|
|
Ref : constant Sequence_Ptr := Constructor (Last);
|
|
begin
|
|
if Args (Args'First).Kind = Kind_List then
|
|
for I in 1 .. Args'Length - 1 loop
|
|
Ref.all.Data (I) := Args (Args'Last - I + 1);
|
|
end loop;
|
|
Ref.all.Data (Args'Length .. Last) := Data;
|
|
return (Kind_List, Ref);
|
|
else
|
|
Ref.all.Data := Data & Args (Args'First + 1 .. Args'Last);
|
|
return (Kind_Vector, Ref);
|
|
end if;
|
|
end;
|
|
when others =>
|
|
Err.Raise_With ("parameter 1 must be a sequence");
|
|
end case;
|
|
end Conj;
|
|
|
|
function Cons (Args : in T_Array) return T is
|
|
begin
|
|
Err.Check (Args'Length = 2
|
|
and then Args (Args'Last).Kind in Kind_Sequence,
|
|
"expected a value then a sequence");
|
|
declare
|
|
Head : T renames Args (Args'First);
|
|
Tail : T_Array renames Args (Args'Last).Sequence.all.Data;
|
|
Ref : constant Sequence_Ptr := Constructor (1 + Tail'Length);
|
|
begin
|
|
Ref.all.Data := Head & Tail;
|
|
return (Kind_List, Ref);
|
|
end;
|
|
end Cons;
|
|
|
|
function Constructor (Length : in Natural) return Sequence_Ptr is
|
|
Ref : constant Sequence_Ptr := new Instance (Length);
|
|
begin
|
|
Garbage_Collected.Register (Garbage_Collected.Pointer (Ref));
|
|
return Ref;
|
|
end Constructor;
|
|
|
|
function Count (Args : in T_Array) return T is
|
|
begin
|
|
Err.Check (Args'Length = 1, "expected 1 parameter");
|
|
case Args (Args'First).Kind is
|
|
when Kind_Nil =>
|
|
return (Kind_Number, 0);
|
|
when Kind_Sequence =>
|
|
return (Kind_Number, Args (Args'First).Sequence.all.Data'Length);
|
|
when others =>
|
|
Err.Raise_With ("parameter must be nil or a sequence");
|
|
end case;
|
|
end Count;
|
|
|
|
function First (Args : in T_Array) return T is
|
|
begin
|
|
Err.Check (Args'Length = 1, "expected 1 parameter");
|
|
case Args (Args'First).Kind is
|
|
when Kind_Nil =>
|
|
return Nil;
|
|
when Kind_Sequence =>
|
|
declare
|
|
Data : T_Array renames Args (Args'First).Sequence.all.Data;
|
|
begin
|
|
if Data'Length = 0 then
|
|
return Nil;
|
|
else
|
|
return Data (Data'First);
|
|
end if;
|
|
end;
|
|
when others =>
|
|
Err.Raise_With ("parameter must be nil or a sequence");
|
|
end case;
|
|
end First;
|
|
|
|
function Is_Empty (Args : in T_Array) return T is
|
|
begin
|
|
Err.Check (Args'Length = 1
|
|
and then Args (Args'First).Kind in Kind_Sequence,
|
|
"expected a sequence");
|
|
return (Kind_Boolean, Args (Args'First).Sequence.all.Data'Length = 0);
|
|
end Is_Empty;
|
|
|
|
procedure Keep_References (Object : in out Instance) is
|
|
begin
|
|
Keep (Object.Meta);
|
|
for M of Object.Data loop
|
|
Keep (M);
|
|
end loop;
|
|
end Keep_References;
|
|
|
|
function List (Args : in T_Array) return T
|
|
is
|
|
Ref : constant Sequence_Ptr := Constructor (Args'Length);
|
|
begin
|
|
Ref.all.Data := Args;
|
|
return (Kind_List, Ref);
|
|
end List;
|
|
|
|
function Map (Args : in T_Array) return T is
|
|
begin
|
|
Err.Check (Args'Length = 2
|
|
and then Args (Args'Last).Kind in Kind_Sequence,
|
|
"expected a function then a sequence");
|
|
declare
|
|
F : T renames Args (Args'First);
|
|
Src : T_Array renames Args (Args'Last).Sequence.all.Data;
|
|
Ref : constant Sequence_Ptr := Constructor (Src'Length);
|
|
begin
|
|
case F.Kind is
|
|
when Kind_Builtin =>
|
|
for I in Src'Range loop
|
|
Ref.all.Data (I) := F.Builtin.all (Src (I .. I));
|
|
end loop;
|
|
when Kind_Builtin_With_Meta =>
|
|
for I in Src'Range loop
|
|
Ref.all.Data (I)
|
|
:= F.Builtin_With_Meta.all.Builtin.all (Src (I .. I));
|
|
end loop;
|
|
when Kind_Fn =>
|
|
for I in Src'Range loop
|
|
Ref.all.Data (I) := F.Fn.all.Apply (Src (I .. I));
|
|
end loop;
|
|
when others =>
|
|
Err.Raise_With ("parameter 1 must be a function");
|
|
end case;
|
|
return (Kind_List, Ref);
|
|
end;
|
|
end Map;
|
|
|
|
function Nth (Args : in T_Array) return T is
|
|
begin
|
|
Err.Check (Args'Length = 2
|
|
and then Args (Args'First).Kind in Kind_Sequence
|
|
and then Args (Args'Last).Kind = Kind_Number,
|
|
"expected a sequence then a number");
|
|
declare
|
|
L : T_Array renames Args (Args'First).Sequence.all.Data;
|
|
I : constant Integer := Args (Args'Last).Number + 1;
|
|
begin
|
|
Err.Check (I in L'Range, "index out of bounds");
|
|
return L (I);
|
|
end;
|
|
end Nth;
|
|
|
|
function Rest (Args : in T_Array) return T is
|
|
begin
|
|
Err.Check (Args'Length = 1, "expected 1 parameter");
|
|
case Args (Args'First).Kind is
|
|
when Kind_Nil =>
|
|
return (Kind_List, Constructor (0));
|
|
when Kind_Sequence =>
|
|
declare
|
|
A1 : T_Array renames Args (Args'First).Sequence.all.Data;
|
|
Ref : constant Sequence_Ptr
|
|
:= Constructor (Integer'Max (0, A1'Length - 1));
|
|
begin
|
|
Ref.all.Data := A1 (A1'First + 1 .. A1'Last);
|
|
return (Kind_List, Ref);
|
|
end;
|
|
when others =>
|
|
Err.Raise_With ("parameter must be nil or a sequence");
|
|
end case;
|
|
end Rest;
|
|
|
|
function Vec (Args : in T_Array) return T is
|
|
begin
|
|
Err.Check (Args'Length = 1
|
|
and then Args (Args'First).Kind in Kind_Sequence,
|
|
"expects a sequence");
|
|
return (Kind_Vector, Args (Args'First).Sequence);
|
|
end Vec;
|
|
|
|
function Vector (Args : in T_Array) return T
|
|
is
|
|
Ref : constant Sequence_Ptr := Constructor (Args'Length);
|
|
begin
|
|
Ref.all.Data := Args;
|
|
return (Kind_Vector, Ref);
|
|
end Vector;
|
|
|
|
end Types.Sequences;
|