altos/scheme: Use memory manager mark code to note recursive print
[fw/altos] / src / scheme / ao_scheme_vector.c
1 /*
2  * Copyright © 2017 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program 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  * General Public License for more details.
13  */
14
15 #include "ao_scheme.h"
16
17 #ifdef AO_SCHEME_FEATURE_VECTOR
18
19 static void vector_mark(void *addr)
20 {
21         struct ao_scheme_vector *vector = addr;
22         unsigned int    i;
23
24         for (i = 0; i < vector->length; i++) {
25                 ao_poly v = vector->vals[i];
26
27                 ao_scheme_poly_mark(v, 1);
28         }
29 }
30
31 static int vector_len_size(uint16_t length)
32 {
33         return sizeof (struct ao_scheme_vector) + length * sizeof (ao_poly);
34 }
35
36 static int vector_size(void *addr)
37 {
38         struct ao_scheme_vector *vector = addr;
39
40         return vector_len_size(vector->length);
41 }
42
43 static void vector_move(void *addr)
44 {
45         struct ao_scheme_vector *vector = addr;
46         unsigned int    i;
47
48         for (i = 0; i < vector->length; i++)
49                 (void) ao_scheme_poly_move(&vector->vals[i], 1);
50 }
51
52 const struct ao_scheme_type ao_scheme_vector_type = {
53         .mark = vector_mark,
54         .size = vector_size,
55         .move = vector_move,
56         .name = "vector",
57 };
58
59 struct ao_scheme_vector *
60 ao_scheme_vector_alloc(uint16_t length, ao_poly fill)
61 {
62         struct ao_scheme_vector *vector;
63         unsigned int i;
64
65         vector = ao_scheme_alloc(vector_len_size(length));
66         if (!vector)
67                 return NULL;
68         vector->type = AO_SCHEME_VECTOR;
69         vector->length = length;
70         for (i = 0; i < length; i++)
71                 vector->vals[i] = fill;
72         return vector;
73 }
74
75 void
76 ao_scheme_vector_write(ao_poly v)
77 {
78         struct ao_scheme_vector *vector = ao_scheme_poly_vector(v);
79         unsigned int i;
80
81         ao_scheme_print_start();
82         if (ao_scheme_print_mark_addr(vector))
83                 printf ("...");
84         else {
85                 printf("#(");
86                 for (i = 0; i < vector->length; i++) {
87                         if (i != 0)
88                                 printf(" ");
89                         ao_scheme_poly_write(vector->vals[i]);
90                 }
91                 printf(")");
92         }
93         ao_scheme_print_stop();
94 }
95
96 void
97 ao_scheme_vector_display(ao_poly v)
98 {
99         struct ao_scheme_vector *vector = ao_scheme_poly_vector(v);
100         unsigned int i;
101
102         ao_scheme_print_start();
103         if (ao_scheme_print_mark_addr(vector))
104                 printf ("...");
105         else {
106                 for (i = 0; i < vector->length; i++)
107                         ao_scheme_poly_display(vector->vals[i]);
108         }
109 }
110
111 static int32_t
112 ao_scheme_vector_offset(struct ao_scheme_vector *vector, ao_poly i)
113 {
114         bool    fail;
115         int32_t offset = ao_scheme_poly_integer(i, &fail);
116
117         if (fail)
118                 ao_scheme_error(AO_SCHEME_INVALID, "vector index %v not integer", i);
119         if (offset < 0 || vector->length <= offset) {
120                 ao_scheme_error(AO_SCHEME_INVALID, "vector index %v out of range (max %d)",
121                                 i, vector->length);
122                 offset = -1;
123         }
124         return offset;
125 }
126
127 ao_poly
128 ao_scheme_vector_get(ao_poly v, ao_poly i)
129 {
130         struct ao_scheme_vector *vector = ao_scheme_poly_vector(v);
131         int32_t                 offset = ao_scheme_vector_offset(vector, i);
132
133         if (offset < 0)
134                 return AO_SCHEME_NIL;
135         return vector->vals[offset];
136 }
137
138 ao_poly
139 ao_scheme_vector_set(ao_poly v, ao_poly i, ao_poly p)
140 {
141         struct ao_scheme_vector *vector = ao_scheme_poly_vector(v);
142         int32_t                 offset = ao_scheme_vector_offset(vector, i);
143
144         if (offset < 0)
145                 return AO_SCHEME_NIL;
146         return vector->vals[offset] = p;
147 }
148
149 struct ao_scheme_vector *
150 ao_scheme_list_to_vector(struct ao_scheme_cons *cons)
151 {
152         uint16_t                length;
153         uint16_t                i;
154         struct ao_scheme_vector *vector;
155
156         length = (uint16_t) ao_scheme_cons_length (cons);
157         if (ao_scheme_exception)
158                 return NULL;
159
160         ao_scheme_cons_stash(0, cons);
161         vector = ao_scheme_vector_alloc(length, AO_SCHEME_NIL);
162         cons = ao_scheme_cons_fetch(0);
163         if (!vector)
164                 return NULL;
165         i = 0;
166         while (cons) {
167                 vector->vals[i++] = cons->car;
168                 cons = ao_scheme_cons_cdr(cons);
169         }
170         return vector;
171 }
172
173 struct ao_scheme_cons *
174 ao_scheme_vector_to_list(struct ao_scheme_vector *vector)
175 {
176         unsigned int            i;
177         uint16_t                length = vector->length;
178         struct ao_scheme_cons   *cons = NULL;
179
180         for (i = length; i-- > 0;) {
181                 ao_scheme_poly_stash(2, ao_scheme_vector_poly(vector));
182                 cons = ao_scheme_cons_cons(vector->vals[i], ao_scheme_cons_poly(cons));
183                 vector = ao_scheme_poly_vector(ao_scheme_poly_fetch(2));
184                 if (!cons)
185                         return NULL;
186         }
187         return cons;
188 }
189
190 #endif /* AO_SCHEME_FEATURE_VECTOR */