]> ocean-lang.org Git - ocean/blobdiff - csrc/oceani.mdc
oceani: differentiate static-sized arrays from others.
[ocean] / csrc / oceani.mdc
index bc8880e72ccaf11343c1782ff6d7670db537f114..0de2988dbc689dd0b1970c16e48bdd20b1403c84 100644 (file)
@@ -429,6 +429,7 @@ Named type are stored in a simple linked list.  Objects of each type are
                struct type *next;
                int size, align;
                void (*init)(struct type *type, struct value *val);
+               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,
@@ -536,8 +537,9 @@ Named type are stored in a simple linked list.  Objects of each type are
        {
                struct value *ret;
 
-               if (!t->size)
-                       val_init(t, NULL);
+               if (t->prepare_type)
+                       t->prepare_type(t, 0);
+
                ret = calloc(1, t->size);
                if (init)
                        memcpy(ret, init, t->size);
@@ -1437,8 +1439,10 @@ in `rval`.
        {
                struct lrval ret = _interp_exec(e);
 
-               if (typeret)
+               if (ret.lval)
                        *typeret = ret.type;
+               else
+                       free_value(ret.type, &ret.rval);
                return ret.lval;
        }
 
@@ -1499,36 +1503,66 @@ ever be referenced by the name it is declared with.  It is likely that
 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_init(struct type *type, struct value *val)
+       static void array_prepare_type(struct type *type, int parse_time)
        {
-               int i;
+               mpz_t q;
+               if (!type->array.vsize || type->array.static_size)
+                       return;
 
-               if (type->array.vsize) {
-                       mpz_t q;
-                       mpz_init(q);
-                       mpz_tdiv_q(q, mpq_numref(type->array.vsize->val->num),
-                                  mpq_denref(type->array.vsize->val->num));
-                       type->array.size = mpz_get_si(q);
-                       mpz_clear(q);
+               mpz_init(q);
+               mpz_tdiv_q(q, mpq_numref(type->array.vsize->val->num),
+                          mpq_denref(type->array.vsize->val->num));
+               type->array.size = mpz_get_si(q);
+               mpz_clear(q);
+
+               if (parse_time) {
+                       type->array.static_size = 1;
+                       type->size = type->array.size * type->array.member->size;
+                       type->align = type->array.member->align;
                }
-               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);
                }
        }
@@ -1536,12 +1570,17 @@ make a copy of an array with controllable recursive depth.
        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)
@@ -1570,9 +1609,12 @@ make a copy of an array with controllable recursive depth.
 
        static struct type array_prototype = {
                .init = array_init,
+               .prepare_type = array_prepare_type,
                .print_type = array_print_type,
                .compat = array_compat,
                .free = array_free,
+               .size = sizeof(void*),
+               .align = sizeof(void*),
        };
 
 ###### declare terminals
@@ -1584,16 +1626,17 @@ make a copy of an array with controllable recursive depth.
                char tail[3];
                mpq_t num;
                struct text noname = { "", 0 };
+               struct type *t;
 
-               $0 = add_type(c, noname, &array_prototype);
-               $0->array.member = $<4;
-               $0->array.vsize = NULL;
+               $0 = t = add_type(c, noname, &array_prototype);
+               t->array.member = $<4;
+               t->array.vsize = NULL;
                if (number_parse(num, tail, $2.txt) == 0)
                        tok_err(c, "error: unrecognised number", &$2);
                else if (tail[0])
                        tok_err(c, "error: unsupported number suffix", &$2);
                else {
-                       $0->array.size = mpz_get_ui(mpq_numref(num));
+                       t->array.size = mpz_get_ui(mpq_numref(num));
                        if (mpz_cmp_ui(mpq_denref(num), 1) != 0) {
                                tok_err(c, "error: array size must be an integer",
                                        &$2);
@@ -1602,6 +1645,9 @@ make a copy of an array with controllable recursive depth.
                                        &$2);
                        mpq_clear(num);
                }
+               t->array.static_size = 1;
+               t->size = t->array.size * t->array.member->size;
+               t->align = t->array.member->align;
        } }$
 
        | [ IDENTIFIER ] Type ${ {
@@ -1663,6 +1709,7 @@ make a copy of an array with controllable recursive depth.
        case Index: {
                mpz_t q;
                long i;
+               void *ptr;
 
                lleft = linterp_exec(b->left, &ltype);
                right = interp_exec(b->right, &rtype);
@@ -1671,9 +1718,13 @@ make a copy of an array with controllable recursive depth.
                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;
@@ -1745,7 +1796,12 @@ function will be needed.
                for (i = 0; i < type->structure.nfields; i++) {
                        struct value *v;
                        v = (void*) val->ptr + type->structure.fields[i].offset;
-                       val_init(type->structure.fields[i].type, v);
+                       if (type->structure.fields[i].init)
+                               dup_value(type->structure.fields[i].type, 
+                                         type->structure.fields[i].init,
+                                         v);
+                       else
+                               val_init(type->structure.fields[i].type, v);
                }
        }
 
@@ -1960,7 +2016,8 @@ function will be needed.
                        $0 = calloc(1, sizeof(struct fieldlist));
                        $0->f.name = $1.txt;
                        $0->f.type = $<3;
-                       $0->f.init = val_alloc($0->f.type, NULL);
+                       if ($0->f.type->prepare_type)
+                               $0->f.type->prepare_type($0->f.type, 1);
                }$
 
 ###### forward decls
@@ -3354,14 +3411,13 @@ it is declared, and error will be raised as the name is created as
                struct variable *v = cast(var, b->left)->var;
                if (v->merged)
                        v = v->merged;
+               free_value(v->type, v->val);
+               free(v->val);
                if (b->right) {
                        right = interp_exec(b->right, &rtype);
-                       free_value(v->type, v->val);
-                       free(v->val);
                        v->val = val_alloc(v->type, &right);
                        rtype = Tnone;
                } else {
-                       free_value(v->type, v->val);
                        v->val = val_alloc(v->type, NULL);
                }
                break;