struct type *next;
int size, align;
void (*init)(struct type *type, struct value *val);
- void (*prepare_type)(struct type *type);
+ void (*prepare_type)(struct type *type, int parse_time);
void (*print)(struct type *type, struct value *val);
void (*print_type)(struct type *type, FILE *f);
int (*cmp_order)(struct type *t1, struct type *t2,
struct value *ret;
if (t->prepare_type)
- t->prepare_type(t);
+ t->prepare_type(t, 0);
ret = calloc(1, t->size);
if (init)
a "`copy`" primitive will eventually be define which can be used to
make a copy of an array with controllable recursive depth.
+For now we have two sorts of array, those with fixed size either because
+it is given as a literal number or because it is a struct member (which
+cannot have a runtime-changing size), and those with a size that is
+determined at runtime - local variables with a const size. The former
+have their size calculated at parse time, the latter at run time.
+
+For the latter type, the `size` field of the type is the size of a
+pointer, and the array is reallocated every time it comes into scope.
+
+We differentiate struct fields with a const size from local variables
+with a const size by whether they are prepared at parse time or not.
+
###### type union fields
struct {
- int size;
+ short size;
+ short static_size;
struct variable *vsize;
struct type *member;
} array;
+###### value union fields
+ void *array; // used if not static_size
+
###### value functions
- static void array_prepare_type(struct type *type)
+ static void array_prepare_type(struct type *type, int parse_time)
{
mpz_t q;
- if (!type->array.vsize)
+ if (!type->array.vsize || type->array.static_size)
return;
mpz_init(q);
type->array.size = mpz_get_si(q);
mpz_clear(q);
- type->size = type->array.size * type->array.member->size;
- type->align = type->array.member->align;
+ if (parse_time) {
+ type->array.static_size = 1;
+ type->size = type->array.size * type->array.member->size;
+ type->align = type->array.member->align;
+ }
}
static void array_init(struct type *type, struct value *val)
{
int i;
+ void *ptr = val->ptr;
if (!val)
- return;
+ return;
+ if (!type->array.static_size) {
+ val->array = calloc(type->array.size,
+ type->array.member->size);
+ ptr = val->array;
+ }
for (i = 0; i < type->array.size; i++) {
struct value *v;
- v = (void*)val->ptr + i * type->array.member->size;
+ v = (void*)ptr + i * type->array.member->size;
val_init(type->array.member, v);
}
}
static void array_free(struct type *type, struct value *val)
{
int i;
+ void *ptr = val->ptr;
+ if (!type->array.static_size)
+ ptr = val->array;
for (i = 0; i < type->array.size; i++) {
struct value *v;
- v = (void*)val->ptr + i * type->array.member->size;
+ v = (void*)ptr + i * type->array.member->size;
free_value(type->array.member, v);
}
+ if (!type->array.static_size)
+ free(ptr);
}
static int array_compat(struct type *require, struct type *have)
.print_type = array_print_type,
.compat = array_compat,
.free = array_free,
+ .size = sizeof(void*),
+ .align = sizeof(void*),
};
###### declare terminals
&$2);
mpq_clear(num);
}
+ t->array.static_size = 1;
t->size = t->array.size * t->array.member->size;
t->align = t->array.member->align;
} }$
case Index: {
mpz_t q;
long i;
+ void *ptr;
lleft = linterp_exec(b->left, <ype);
right = interp_exec(b->right, &rtype);
i = mpz_get_si(q);
mpz_clear(q);
+ if (ltype->array.static_size)
+ ptr = lleft;
+ else
+ ptr = *(void**)lleft;
rvtype = ltype->array.member;
if (i >= 0 && i < ltype->array.size)
- lrv = (void*)lleft + i * rvtype->size;
+ lrv = ptr + i * rvtype->size;
else
val_init(ltype->array.member, &rv);
ltype = NULL;
$0->f.name = $1.txt;
$0->f.type = $<3;
if ($0->f.type->prepare_type)
- $0->f.type->prepare_type($0->f.type);
+ $0->f.type->prepare_type($0->f.type, 1);
}$
###### forward decls