Implement EVAL for LISTs
[muddle-interpreter.git] / src / object.h
1 /*
2 Copyright (C) 2017 Keziah Wesley
3
4 You can redistribute and/or modify this file under the terms of the
5 GNU Affero General Public License as published by the Free Software
6 Foundation, either version 3 of the License, or (at your option) any
7 later version.
8
9 This file is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Affero General Public License for more details.
13
14 You should have received a copy of the GNU Affero General Public
15 License along with this file. If not, see
16 <http://www.gnu.org/licenses/>.
17 */
18
19 #ifndef OBJECT_H
20 #define OBJECT_H
21
22 #include "alloc.h"
23
24 #include <assert.h>
25 #include <stdalign.h>
26 #include <stdbool.h>
27 #include <stdint.h>
28
29 typedef uint32_t evaltype;
30
31 enum
32 {
33 // pool OK
34   TYPEPRIM_FIX32 = 0x00010000,
35   TYPEPRIM_FIX64 = 0x00020000,
36   TYPEPRIM_LIST = 0x00030000,
37   TYPEPRIM_VECTOR = 0x00040000,
38   TYPEPRIM_SUBR = 0x00050000,
39
40 // can't be in pool
41   TYPEPRIM_NOPOOL_MASK = 0x70000000,
42   TYPEPRIM_TUPLE = 0x70010000,
43
44 // TYPEPRIM is half of EVALTYPE
45   TYPEPRIM_MASK = 0x7fff0000
46 };
47
48 enum
49 {
50   EVALTYPE_FIX32 = TYPEPRIM_FIX32,
51
52   EVALTYPE_FIX64 = TYPEPRIM_FIX64,
53
54   EVALTYPE_LIST = TYPEPRIM_LIST,
55   EVALTYPE_FORM,
56   EVALTYPE_FALSE,
57
58   EVALTYPE_VECTOR = TYPEPRIM_VECTOR,
59
60   EVALTYPE_SUBR = TYPEPRIM_SUBR,
61
62   EVALTYPE_TUPLE = TYPEPRIM_TUPLE,
63 };
64
65 static inline uint32_t
66 TYPEPRIM (evaltype x)
67 {
68   return x & TYPEPRIM_MASK;
69 }
70
71 static inline bool
72 TYPEPRIM_EQ (evaltype a, evaltype b)
73 {
74   return !((a ^ b) & TYPEPRIM_MASK);
75 }
76
77 typedef struct
78 {
79   uint32_t _dummy;
80 } opaque32;
81 typedef struct
82 {
83   uint64_t _dummy;
84 } opaque64;
85
86 /**
87 Object types.
88
89 An Object's value is accessed through a concrete `foo_object`
90 type.
91
92 `object` can be used to refer to Objects of unspecified type, which
93 are opaque except for their `type` field. Checked downcasts can be
94 performed via the `as_foo` functions; unchecked downcasts via
95 `object.foo` (use only when type information is locally
96 obvious). Some objects can be upcast to more specific supertypes,
97 such as `pool_object` for objects that are known to be storeable in
98 the pool.
99
100 The generic `object` type should not be used to accept parameters
101 that have constraints on their type, and should not be used to
102 return objects that are of a statically-known type. Encoding type
103 information in function signatures allows strictly local reasoning
104 about types.
105 */
106
107 typedef union object object;
108
109 typedef struct
110 {
111   alignas (16) evaltype type;
112   pool_ptr rest;
113   uint32_t _pad;
114   uint32_t val;
115 } fix32_object;
116
117 typedef struct
118 {
119   alignas (16) evaltype type;
120   pool_ptr rest;
121   uint64_t val;
122 } fix64_object;
123
124 typedef struct
125 {
126   alignas (16) evaltype type;
127   pool_ptr rest;
128   uint32_t _pad;
129   pool_ptr head;
130 } list_object;
131
132 typedef struct
133 {
134   alignas (16) evaltype type;
135   pool_ptr rest;
136   uint32_t len;
137   heap_ptr body;
138 } vector_object;
139
140 typedef struct
141 {
142   alignas (16) evaltype type;
143   pool_ptr rest;
144   void (*fn) ();
145 } subr_object;
146
147 typedef struct
148 {
149   alignas (16)
150     /// no rest; is a NOPOOL type
151   evaltype type;
152   uint32_t len;
153   /// allocation can be anywhere
154   object *body;
155   // uniq_id uid ??
156 } tuple_object;
157
158 /// Object of a type that can be stored in the pool.
159 /// NB. a pool_object* can point outside the pool; contrast with pool_ptr.
160 typedef union pool_object
161 {
162   /// any pool object has a type and a rest
163   struct
164   {
165     alignas (16) evaltype type;
166     pool_ptr rest;
167     opaque64 val;
168   };
169   /// objects of statically known type
170   fix32_object fix32;
171   fix64_object fix64;
172   list_object list;
173   vector_object vector;
174 } pool_object;
175
176 union object
177 {
178   /// any object has a type
179   struct
180   {
181     alignas (16) evaltype type;
182     opaque32 _unknown0;
183     opaque64 _unknown1;
184   };
185   /// objects of statically known type
186   /// use as_X() for checked downcast
187   pool_object pool;
188   fix32_object fix32;
189   fix64_object fix64;
190   list_object list;
191   vector_object vector;
192   tuple_object tuple;
193 };
194
195 /**
196 Initialization helpers.
197 */
198
199 static inline fix64_object
200 new_fix64 (uint64_t n)
201 {
202   return (fix64_object)
203   {
204   .type = EVALTYPE_FIX64,.rest = 0,.val = n,};
205 }
206
207 static inline list_object
208 new_list (pool_ptr head)
209 {
210   return (list_object)
211   {
212   .type = EVALTYPE_LIST,.rest = 0,.head = head,};
213 }
214
215 static inline vector_object
216 new_vector (heap_ptr body, uint32_t length)
217 {
218   return (vector_object)
219   {
220   .type = EVALTYPE_VECTOR,.rest = 0,.len = length,.body = body,};
221 }
222
223 static inline tuple_object
224 new_tuple (object * body, uint32_t length)
225 {
226   return (tuple_object)
227   {
228   .type = EVALTYPE_TUPLE,.len = length,.body = body,};
229 }
230
231 static inline subr_object
232 new_subr (void (*fn) ())
233 {
234   return (subr_object)
235   {
236   .type = EVALTYPE_SUBR,.rest = 0,.fn = fn,};
237 }
238
239 /**
240 Common object operations.
241 */
242
243 uint32_t list_length (const list_object * o);
244
245 /**
246 Checked downcasts.
247 */
248
249 static inline list_object *
250 as_list (object * o)
251 {
252   assert (TYPEPRIM_EQ (o->type, EVALTYPE_LIST));
253   return &o->list;
254 }
255
256 static inline vector_object *
257 as_vector (object * o)
258 {
259   assert (TYPEPRIM_EQ (o->type, EVALTYPE_VECTOR));
260   return &o->vector;
261 }
262
263 static inline pool_object *
264 as_pool (object * p)
265 {
266   assert (!(TYPEPRIM (p->type) & TYPEPRIM_NOPOOL_MASK));
267   return (pool_object *) p;
268 }
269
270 #endif // OBJECT_H