]> ocean-lang.org Git - ocean/blobdiff - csrc/oceani.mdc
oceani: move prepare_type handling to after the parse.
[ocean] / csrc / oceani.mdc
index 7371535bf7c555ec127028eb89f3113901be0561..34c17b234efaefda84540c2560a045b1b6a5309a 100644 (file)
@@ -242,6 +242,7 @@ structures can be used.
 
                parse_oceani(ss->code, &context.config, dotrace ? stderr : NULL);
 
+               prepare_types(&context);
                if (!context.parse_error && !analyse_funcs(&context)) {
                        fprintf(stderr, "oceani: type error in program - not running.\n");
                        context.parse_error = 1;
@@ -647,6 +648,9 @@ the location of a value, which can be updated, in `lval`.  Others will
 set `lval` to NULL indicating that there is a value of appropriate type
 in `rval`.
 
+###### forward decls
+       static struct value interp_exec(struct parse_context *c, struct exec *e,
+                                       struct type **typeret);
 ###### core functions
 
        struct lrval {
@@ -911,6 +915,15 @@ which might be reported in error messages.
                        fprintf(f, "*Unknown*");                // NOTEST
        }
 
+       static void prepare_types(struct parse_context *c)
+       {
+               struct type *t;
+
+               for (t = c->typelist; t; t = t->next)
+                       if (t->prepare_type)
+                               t->prepare_type(c, t, 1);
+       }
+
 ###### forward decls
 
        static void free_value(struct type *type, struct value *v);
@@ -1845,13 +1858,17 @@ tell if it was set or not later.
        short local_size;
        void *global, *local;
 
+###### forward decls
+       static struct value *global_alloc(struct parse_context *c, struct type *t,
+                                         struct variable *v, struct value *init);
+
 ###### ast functions
 
        static struct value *var_value(struct parse_context *c, struct variable *v)
        {
                if (!v->global) {
                        if (!c->local || !v->type)
-                               return NULL;                    // NOTEST
+                               return NULL;
                        if (v->frame_pos + v->type->size > c->local_size) {
                                printf("INVALID frame_pos\n");  // NOTEST
                                exit(2);                        // NOTEST
@@ -1877,7 +1894,7 @@ tell if it was set or not later.
                        t->prepare_type(c, t, 1);       // NOTEST
 
                if (c->global_size & (t->align - 1))
-                       c->global_size = (c->global_size + t->align) & ~(t->align-1);
+                       c->global_size = (c->global_size + t->align) & ~(t->align-1);   // NOTEST
                if (!v) {
                        v = &scratch;
                        v->type = t;
@@ -2228,16 +2245,22 @@ with a const size by whether they are prepared at parse time or not.
        {
                struct value *vsize;
                mpz_t q;
-               if (!type->array.vsize || type->array.static_size)
+               if (type->array.static_size)
+                       return;
+               if (type->array.unspec && parse_time)
                        return;
 
-               vsize = var_value(c, type->array.vsize);
-               mpz_init(q);
-               mpz_tdiv_q(q, mpq_numref(vsize->num), mpq_denref(vsize->num));
-               type->array.size = mpz_get_si(q);
-               mpz_clear(q);
+               if (type->array.vsize) {
+                       vsize = var_value(c, type->array.vsize);
+                       if (!vsize)
+                               return;
+                       mpz_init(q);
+                       mpz_tdiv_q(q, mpq_numref(vsize->num), mpq_denref(vsize->num));
+                       type->array.size = mpz_get_si(q);
+                       mpz_clear(q);
+               }
 
-               if (parse_time) {
+               if (parse_time && type->array.member->size) {
                        type->array.static_size = 1;
                        type->size = type->array.size * type->array.member->size;
                        type->align = type->array.member->align;
@@ -2356,9 +2379,6 @@ with a const size by whether they are prepared at parse time or not.
                t->array.size = elements;
                t->array.member = $<4;
                t->array.vsize = NULL;
-               t->array.static_size = 1;
-               t->size = t->array.size * t->array.member->size;
-               t->align = t->array.member->align;
        } }$
 
        | [ IDENTIFIER ] Type ${ {
@@ -2512,7 +2532,12 @@ function will be needed.
                        struct type *type;
                        struct value *init;
                        int offset;
-               } *fields;
+               } *fields; // This is created when field_list is analysed.
+               struct fieldlist {
+                       struct fieldlist *prev;
+                       struct field f;
+                       struct exec *init;
+               } *field_list; // This is created during parsing
        } structure;
 
 ###### type functions
@@ -2547,6 +2572,15 @@ function will be needed.
                }
        }
 
+       static void free_fieldlist(struct fieldlist *f)
+       {
+               if (!f)
+                       return;
+               free_fieldlist(f->prev);
+               free_exec(f->init);
+               free(f);
+       }
+
        static void structure_free_type(struct type *t)
        {
                int i;
@@ -2556,6 +2590,56 @@ function will be needed.
                                           t->structure.fields[i].init);
                        }
                free(t->structure.fields);
+               free_fieldlist(t->structure.field_list);
+       }
+
+       static void structure_prepare_type(struct parse_context *c,
+                                          struct type *t, int parse_time)
+       {
+               int cnt = 0;
+               struct fieldlist *f;
+
+               if (!parse_time || t->structure.fields)
+                       return;
+
+               for (f = t->structure.field_list; f; f=f->prev) {
+                       int ok;
+                       cnt += 1;
+
+                       if (f->f.type->prepare_type)
+                               f->f.type->prepare_type(c, f->f.type, 1);
+                       if (f->init == NULL)
+                               continue;
+                       do {
+                               ok = 1;
+                               propagate_types(f->init, c, &ok, f->f.type, 0);
+                       } while (ok == 2);
+                       if (!ok)
+                               c->parse_error = 1;     // NOTEST
+               }
+
+               t->structure.nfields = cnt;
+               t->structure.fields = calloc(cnt, sizeof(struct field));
+               f = t->structure.field_list;
+               while (cnt > 0) {
+                       int a = f->f.type->align;
+                       cnt -= 1;
+                       t->structure.fields[cnt] = f->f;
+                       if (t->size & (a-1))
+                               t->size = (t->size | (a-1)) + 1;
+                       t->structure.fields[cnt].offset = t->size;
+                       t->size += ((f->f.type->size - 1) | (a-1)) + 1;
+                       if (a > t->align)
+                               t->align = a;
+
+                       if (f->init && !c->parse_error) {
+                               struct value vl = interp_exec(c, f->init, NULL);
+                               t->structure.fields[cnt].init =
+                                       global_alloc(c, f->f.type, NULL, &vl);
+                       }
+
+                       f = f->prev;
+               }
        }
 
        static struct type structure_prototype = {
@@ -2563,6 +2647,7 @@ function will be needed.
                .free = structure_free,
                .free_type = structure_free_type,
                .print_type_decl = structure_print_type,
+               .prepare_type = structure_prepare_type,
        };
 
 ###### exec type
@@ -2655,51 +2740,11 @@ function will be needed.
                break;
        }
 
-###### ast
-       struct fieldlist {
-               struct fieldlist *prev;
-               struct field f;
-       };
-
-###### ast functions
-       static void free_fieldlist(struct fieldlist *f)
-       {
-               if (!f)
-                       return;
-               free_fieldlist(f->prev);
-               if (f->f.init) {
-                       free_value(f->f.type, f->f.init);       // UNTESTED
-                       free(f->f.init);        // UNTESTED
-               }
-               free(f);
-       }
-
 ###### top level grammar
        DeclareStruct -> struct IDENTIFIER FieldBlock Newlines ${ {
                struct type *t =
                        add_type(c, $2.txt, &structure_prototype);
-               int cnt = 0;
-               struct fieldlist *f;
-
-               for (f = $3; f; f=f->prev)
-                       cnt += 1;
-
-               t->structure.nfields = cnt;
-               t->structure.fields = calloc(cnt, sizeof(struct field));
-               f = $3;
-               while (cnt > 0) {
-                       int a = f->f.type->align;
-                       cnt -= 1;
-                       t->structure.fields[cnt] = f->f;
-                       if (t->size & (a-1))
-                               t->size = (t->size | (a-1)) + 1;
-                       t->structure.fields[cnt].offset = t->size;
-                       t->size += ((f->f.type->size - 1) | (a-1)) + 1;
-                       if (a > t->align)
-                               t->align = a;
-                       f->f.init = NULL;
-                       f = f->prev;
-               }
+               t->structure.field_list = $<FB;
        } }$
 
        $*fieldlist
@@ -2725,29 +2770,16 @@ function will be needed.
        | ERROR ${ tok_err(c, "Syntax error in struct field", &$1); }$
 
        Field -> IDENTIFIER : Type = Expression ${ {
-               int ok;
-
                $0 = calloc(1, sizeof(struct fieldlist));
-               $0->f.name = $1.txt;
-               $0->f.type = $<3;
+               $0->f.name = $ID.txt;
+               $0->f.type = $<Type;
                $0->f.init = NULL;
-               do {
-                       ok = 1;
-                       propagate_types($<5, c, &ok, $3, 0);
-               } while (ok == 2);
-               if (!ok)
-                       c->parse_error = 1;     // UNTESTED
-               else {
-                       struct value vl = interp_exec(c, $5, NULL);
-                       $0->f.init = global_alloc(c, $0->f.type, NULL, &vl);
-               }
+               $0->init = $<Expr;
        } }$
        | IDENTIFIER : Type ${
                $0 = calloc(1, sizeof(struct fieldlist));
-               $0->f.name = $1.txt;
-               $0->f.type = $<3;
-               if ($0->f.type->prepare_type)
-                       $0->f.type->prepare_type(c, $0->f.type, 1);
+               $0->f.name = $ID.txt;
+               $0->f.type = $<Type;
        }$
 
 ###### forward decls