beginnings of REPL
[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
57   EVALTYPE_VECTOR = TYPEPRIM_VECTOR,
58
59   EVALTYPE_SUBR = TYPEPRIM_SUBR,
60
61   EVALTYPE_TUPLE = TYPEPRIM_TUPLE,
62 };
63
64 static inline uint32_t
65 TYPEPRIM (evaltype x)
66 {
67   return x & TYPEPRIM_MASK;
68 }
69
70 static inline bool
71 TYPEPRIM_EQ (evaltype a, evaltype b)
72 {
73   return !((a ^ b) & TYPEPRIM_MASK);
74 }
75
76 typedef struct
77 {
78   uint32_t _dummy;
79 } opaque32;
80 typedef struct
81 {
82   uint64_t _dummy;
83 } opaque64;
84
85 /**
86 Object types.
87
88 An Object's value is accessed through a concrete `foo_object`
89 type.
90
91 `object` can be used to refer to Objects of unspecified type, which
92 are opaque except for their `type` field. Checked downcasts can be
93 performed via the `as_foo` functions; unchecked downcasts via
94 `object.foo` (use only when type information is locally
95 obvious). Some objects can be upcast to more specific supertypes,
96 such as `pool_object` for objects that are known to be storeable in
97 the pool.
98
99 The generic `object` type should not be used to accept parameters
100 that have constraints on their type, and should not be used to
101 return objects that are of a statically-known type. Encoding type
102 information in function signatures allows strictly local reasoning
103 about types.
104 */
105
106 typedef union object object;
107
108 typedef struct
109 {
110   alignas (16) evaltype type;
111   pool_ptr rest;
112   uint32_t _pad;
113   uint32_t val;
114 } fix32_object;
115
116 typedef struct
117 {
118   alignas (16) evaltype type;
119   pool_ptr rest;
120   uint64_t val;
121 } fix64_object;
122
123 typedef struct
124 {
125   alignas (16) evaltype type;
126   pool_ptr rest;
127   uint32_t _pad;
128   pool_ptr head;
129 } list_object;
130
131 typedef struct
132 {
133   alignas (16) evaltype type;
134   pool_ptr rest;
135   uint32_t len;
136   heap_ptr body;
137 } vector_object;
138
139 typedef struct
140 {
141   alignas (16) evaltype type;
142   pool_ptr rest;
143   void (*fn) ();
144 } subr_object;
145
146 typedef struct
147 {
148   alignas (16)
149     /// no rest; is a NOPOOL type
150   evaltype type;
151   uint32_t len;
152   /// allocation can be anywhere
153   object *body;
154   // uniq_id uid ??
155 } tuple_object;
156
157 /// Object of a type that can be stored in the pool.
158 /// NB. a pool_object* can point outside the pool; contrast with pool_ptr.
159 typedef union pool_object
160 {
161   /// any pool object has a type and a rest
162   struct
163   {
164     alignas (16) evaltype type;
165     pool_ptr rest;
166     opaque64 val;
167   };
168   /// objects of statically known type
169   fix32_object fix32;
170   fix64_object fix64;
171   list_object list;
172   vector_object vector;
173 } pool_object;
174
175 union object
176 {
177   /// any object has a type
178   struct
179   {
180     alignas (16) evaltype type;
181     opaque32 _unknown0;
182     opaque64 _unknown1;
183   };
184   /// objects of statically known type
185   /// use as_X() for checked downcast
186   pool_object pool;
187   fix32_object fix32;
188   fix64_object fix64;
189   list_object list;
190   vector_object vector;
191   tuple_object tuple;
192 };
193
194 /**
195 Initialization helpers.
196 */
197
198 static inline fix64_object
199 new_fix64 (uint64_t n)
200 {
201   return (fix64_object)
202   {
203   .type = EVALTYPE_FIX64,.rest = 0,.val = n,};
204 }
205
206 static inline list_object
207 new_list (pool_ptr head)
208 {
209   return (list_object)
210   {
211   .type = EVALTYPE_LIST,.rest = 0,.head = head,};
212 }
213
214 static inline vector_object
215 new_vector (heap_ptr body, uint32_t length)
216 {
217   return (vector_object)
218   {
219   .type = EVALTYPE_VECTOR,.rest = 0,.len = length,.body = body,};
220 }
221
222 static inline tuple_object
223 new_tuple (object * body, uint32_t length)
224 {
225   return (tuple_object)
226   {
227   .type = EVALTYPE_TUPLE,.len = length,.body = body,};
228 }
229
230 static inline subr_object
231 new_subr (void (*fn) ())
232 {
233   return (subr_object)
234   {
235   .type = EVALTYPE_SUBR,.rest = 0,.fn = fn,};
236 }
237
238 /**
239 Common object operations.
240 */
241
242 uint32_t list_length (const list_object * o);
243
244 /**
245 Checked downcasts.
246 */
247
248 static inline list_object *
249 as_list (object * o)
250 {
251   assert (TYPEPRIM_EQ (o->type, EVALTYPE_LIST));
252   return &o->list;
253 }
254
255 static inline vector_object *
256 as_vector (object * o)
257 {
258   assert (TYPEPRIM_EQ (o->type, EVALTYPE_VECTOR));
259   return &o->vector;
260 }
261
262 static inline pool_object *
263 as_pool (object * p)
264 {
265   if (TYPEPRIM (p->type) & TYPEPRIM_NOPOOL_MASK)
266     return 0;
267   return (pool_object *) p;
268 }
269
270 #endif // OBJECT_H