Commit | Line | Data |
---|---|---|
daffc668 NB |
1 | with Ada.Unchecked_Deallocation; |
2 | ||
11932a6c | 3 | with Printer; |
daffc668 NB |
4 | with Types.Mal; |
5 | ||
6 | package 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 | 92 | end Types.Atoms; |