ada.2: add to .travis.yml
[jackhill/mal.git] / ada.2 / types-atoms.adb
CommitLineData
daffc668
NB
1with Ada.Unchecked_Deallocation;
2
11932a6c 3with Printer;
daffc668
NB
4with Types.Mal;
5
6package body Types.Atoms is
7
8 type Rec is limited record
9 Refs : Natural;
10 Data : Mal.T;
11 end record;
12
13 procedure Free is new Ada.Unchecked_Deallocation (Rec, Acc);
14
15 ----------------------------------------------------------------------
16
17 procedure Adjust (Object : in out Ptr) is
18 begin
19 Object.Ref.all.Refs := Object.Ref.all.Refs + 1;
20 end Adjust;
21
22 function Atom (Args : in Mal.T_Array) return Mal.T
23 is (if Args'Length /= 1 then
24 raise Argument_Error with "atom: expects 1 argument"
11932a6c
NB
25 else
26 (Kind_Atom, (Ada.Finalization.Controlled with new Rec'
27 (Refs => 1,
28 Data => Args (Args'First)))));
daffc668
NB
29
30 function Deref (Args : in Mal.T_Array) return Mal.T
31 is (if Args'Length /= 1 then
32 raise Argument_Error with "deref: expects 1 argument"
33 elsif Args (Args'First).Kind /= Kind_Atom then
34 raise Argument_Error with "deref: expects an atom"
35 else
11932a6c
NB
36 Args (Args'First).Atom.Ref.all.Data);
37
38 function Deref (Item : in Ptr) return Mal.T
39 is (Item.Ref.all.Data);
daffc668
NB
40
41 procedure Finalize (Object : in out Ptr) is
42 begin
43 if Object.Ref /= null and then 0 < Object.Ref.all.Refs then
44 Object.Ref.all.Refs := Object.Ref.all.Refs - 1;
45 if 0 < Object.Ref.all.Refs then
46 Object.Ref := null;
47 else
48 Free (Object.Ref);
49 end if;
50 end if;
51 end Finalize;
52
53 function Reset (Args : in Mal.T_Array) return Mal.T is
54 begin
55 if Args'Length /= 2 then
56 raise Argument_Error with "reset: expects 2 arguments";
57 elsif Args (Args'First).Kind /= Kind_Atom then
58 raise Argument_Error with "reset: first argument must be an atom";
daffc668 59 end if;
11932a6c
NB
60 Args (Args'First).Atom.Ref.all.Data := Args (Args'Last);
61 return Args (Args'Last);
daffc668
NB
62 end Reset;
63
11932a6c
NB
64 function Swap (Args : in Mal.T_Array) return Mal.T is
65 begin
66 if Args'Length < 2 then
67 raise Argument_Error with "swap!: expects at least 2 arguments";
68 elsif Args (Args'First).Kind /= Kind_Atom then
69 raise Argument_Error with "swap!: first argument must be an atom";
70 end if;
71 declare
72 use type Mal.T_Array;
73 X : Mal.T renames Args (Args'First).Atom.Ref.all.Data;
74 F : Mal.T renames Args (Args'First + 1);
75 A : constant Mal.T_Array := X & Args (Args'First + 2 .. Args'Last);
76 begin
77 case F.Kind is
78 when Kind_Builtin =>
79 X := F.Builtin.all (A);
80 when Kind_Builtin_With_Meta =>
81 X := F.Builtin_With_Meta.Builtin.all (A);
82 when Kind_Function =>
83 X := F.Fn.Apply (A);
84 when others =>
85 raise Argument_Error
86 with "swap!: cannot call " & Printer.Img (F);
87 end case;
88 return X;
89 end;
90 end Swap;
91
daffc668 92end Types.Atoms;