]> ocean-lang.org Git - ocean/blobdiff - csrc/oceani.mdc
oceani: remove the HACK concerning type names starting with space
[ocean] / csrc / oceani.mdc
index 725719e2558a19c5f1c2f5c4456b97c002a20c4f..e7976cf086ef03b338527549a4d3d069af7afd45 100644 (file)
@@ -367,6 +367,7 @@ context so indicate that parsing failed.
        static void type_err(struct parse_context *c,
                             char *fmt, struct exec *loc,
                             struct type *t1, int rules, struct type *t2);
+       static void tok_err(struct parse_context *c, char *fmt, struct token *t);
 
 ###### core functions
 
@@ -586,13 +587,17 @@ pointer together with some `val_rules` flags) that the `exec` is
 expected to return, and returns the type that it does return, either of
 which can be `NULL` signifying "unknown".  A `prop_err` flag set is
 passed by reference.  It has `Efail` set when an error is found, and
-`Eretry` when the type for some element is set via propagation.  If it
-remains unchanged at `0`, then no more propagation is needed.
+`Eretry` when the type for some element is set via propagation.  If
+any expression cannot be evaluated immediately, `Enoconst` is set.
+If the expression can be copied, `Emaycopy` is set.
+
+If it remains unchanged at `0`, then no more propagation is needed.
 
 ###### ast
 
        enum val_rules {Rnolabel = 1<<0, Rboolok = 1<<1, Rnoconstant = 1<<2};
-       enum prop_err {Efail = 1<<0, Eretry = 1<<1};
+       enum prop_err {Efail = 1<<0, Eretry = 1<<1, Enoconst = 1<<2,
+                      Emaycopy = 1<<3};
 
 ###### format cases
        case 'r':
@@ -787,10 +792,11 @@ which might be reported in error messages.
        struct type {
                struct text name;
                struct type *next;
+               struct token first_use;
                int size, align;
                int anon;
                void (*init)(struct type *type, struct value *val);
-               void (*prepare_type)(struct parse_context *c, struct type *type, int parse_time);
+               int (*prepare_type)(struct parse_context *c, struct type *type, int parse_time);
                void (*print)(struct type *type, struct value *val, FILE *f);
                void (*print_type)(struct type *type, FILE *f);
                int (*cmp_order)(struct type *t1, struct type *t2,
@@ -834,7 +840,10 @@ which might be reported in error messages.
                struct type *n;
 
                n = calloc(1, sizeof(*n));
-               *n = *proto;
+               if (proto)
+                       *n = *proto;
+               else
+                       n->size = -1;
                n->name = s;
                n->anon = anon;
                n->next = c->typelist;
@@ -922,10 +931,35 @@ which might be reported in error messages.
        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);
+               int retry = 1;
+               enum { none, some, cannot } progress = none;
+
+               while (retry) {
+                       retry = 0;
+
+                       for (t = c->typelist; t; t = t->next) {
+                               if (t->size < 0)
+                                       tok_err(c, "error: type used but not declared",
+                                                &t->first_use);
+                               if (t->size == 0 && t->prepare_type) {
+                                       if (t->prepare_type(c, t, 1))
+                                               progress = some;
+                                       else if (progress == cannot)
+                                               tok_err(c, "error: type has recursive definition",
+                                                       &t->first_use);
+                                       else
+                                               retry = 1;
+                               }
+                       }
+                       switch (progress) {
+                       case cannot:
+                               retry = 0; break;
+                       case none:
+                               progress = cannot; break;
+                       case some:
+                               progress = none; break;
+                       }
+               }
        }
 
 ###### forward decls
@@ -964,12 +998,10 @@ symbol for those.
 
        $*type
        Type -> IDENTIFIER ${
-               $0 = find_type(c, $1.txt);
+               $0 = find_type(c, $ID.txt);
                if (!$0) {
-                       tok_err(c,
-                               "error: undefined type", &$1);
-
-                       $0 = Tnone;
+                       $0 = add_type(c, $ID.txt, NULL);
+                       $0->first_use = $ID;
                }
        }$
        ## type grammar
@@ -1873,7 +1905,7 @@ tell if it was set or not later.
        {
                if (!v->global) {
                        if (!c->local || !v->type)
-                               return NULL;
+                               return NULL;    // UNTESTED
                        if (v->frame_pos + v->type->size > c->local_size) {
                                printf("INVALID frame_pos\n");  // NOTEST
                                exit(2);                        // NOTEST
@@ -2074,7 +2106,11 @@ correctly.
                struct variable *v = var_ref(c, $1.txt);
                $0 = new_pos(var, $1);
                if (v == NULL) {
-                       /* This might be a label - allocate a var just in case */
+                       /* This might be a global const or a label
+                        * Allocate a var with impossible type Tnone,
+                        * which will be adjusted when we find out what it is,
+                        * or will trigger an error.
+                        */
                        v = var_decl(c, $1.txt);
                        if (v) {
                                v->type = Tnone;
@@ -2136,14 +2172,14 @@ correctly.
                                v->where_set = prog;
                                *perr |= Eretry;
                        }
-                       return type;
-               }
-               if (!type_compat(type, v->type, rules)) {
+               } else if (!type_compat(type, v->type, rules)) {
                        type_err(c, "error: expected %1%r but variable '%v' is %2", prog,
                                 type, rules, v->type);
                        type_err(c, "info: this is where '%v' was set to %1", v->where_set,
                                 v->type, rules, NULL);
                }
+               if (!v->global || v->frame_pos < 0)
+                       *perr |= Enoconst;
                if (!type)
                        return v->type;
                return type;
@@ -2245,31 +2281,37 @@ with a const size by whether they are prepared at parse time or not.
 
 ###### value functions
 
-       static void array_prepare_type(struct parse_context *c, struct type *type,
+       static int array_prepare_type(struct parse_context *c, struct type *type,
                                       int parse_time)
        {
                struct value *vsize;
                mpz_t q;
                if (type->array.static_size)
-                       return;
+                       return 1;       // UNTESTED
                if (type->array.unspec && parse_time)
-                       return;
+                       return 1;       // UNTESTED
+               if (parse_time && type->array.vsize && !type->array.vsize->global)
+                       return 1;       // UNTESTED
 
                if (type->array.vsize) {
                        vsize = var_value(c, type->array.vsize);
                        if (!vsize)
-                               return;
+                               return 1;       // UNTESTED
                        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)
+                       return 1;
+               if (type->array.member->size <= 0)
+                       return 0;
 
-               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;
-               }
+               type->array.static_size = 1;
+               type->size = type->array.size * type->array.member->size;
+               type->align = type->array.member->align;
+
+               return 1;
        }
 
        static void array_init(struct type *type, struct value *val)
@@ -2598,21 +2640,24 @@ function will be needed.
                free_fieldlist(t->structure.field_list);
        }
 
-       static void structure_prepare_type(struct parse_context *c,
-                                          struct type *t, int parse_time)
+       static int 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;
+                       return 1;
 
                for (f = t->structure.field_list; f; f=f->prev) {
                        enum prop_err perr;
                        cnt += 1;
 
+                       if (f->f.type->size <= 0)
+                               return 0;
                        if (f->f.type->prepare_type)
-                               f->f.type->prepare_type(c, f->f.type, 1);
+                               f->f.type->prepare_type(c, f->f.type, parse_time);
+
                        if (f->init == NULL)
                                continue;
                        do {
@@ -2645,6 +2690,7 @@ function will be needed.
 
                        f = f->prev;
                }
+               return 1;
        }
 
        static struct type structure_prototype = {
@@ -2747,9 +2793,23 @@ function will be needed.
 
 ###### top level grammar
        DeclareStruct -> struct IDENTIFIER FieldBlock Newlines ${ {
-               struct type *t =
-                       add_type(c, $2.txt, &structure_prototype);
+               struct type *t;
+               t = find_type(c, $ID.txt);
+               if (!t)
+                       t = add_type(c, $ID.txt, &structure_prototype);
+               else if (t->size >= 0) {
+                       tok_err(c, "error: type already declared", &$ID);
+                       tok_err(c, "info: this is location of declartion", &t->first_use);
+                       /* Create a new one - duplicate */
+                       t = add_type(c, $ID.txt, &structure_prototype);
+               } else {
+                       struct type tmp = *t;
+                       *t = structure_prototype;
+                       t->name = tmp.name;
+                       t->next = tmp.next;
+               }
                t->structure.field_list = $<FB;
+               t->first_use = $ID;
        } }$
 
        $*fieldlist
@@ -3149,7 +3209,10 @@ it in the "SimpleStatement Grammar" which will be described later.
                                 prog, NULL, 0, NULL);
                        return NULL;
                }
+               *perr |= Enoconst;
                v->var->type->check_args(c, perr, v->var->type, args);
+               if (v->var->type->function.inline_result)
+                       *perr |= Emaycopy;
                return v->var->type->function.return_type;
        }
 
@@ -4231,7 +4294,7 @@ it is declared, and error will be raised as the name is created as
                                propagate_types(b->left, c, perr, t,
                                                (b->op == Assign ? Rnoconstant : 0));
                }
-               if (t && t->dup == NULL && t->name.txt[0] != ' ') // HACK
+               if (t && t->dup == NULL && !(*perr & Emaycopy))
                        type_err(c, "error: cannot assign value of type %1", b, t, 0, NULL);
                return Tnone;
 
@@ -4920,9 +4983,17 @@ constants.
                        v->global = 1;
                } else {
                        v = var_ref(c, $1.txt);
-                       tok_err(c, "error: name already declared", &$1);
-                       type_err(c, "info: this is where '%v' was first declared",
-                                v->where_decl, NULL, 0, NULL);
+                       if (v->type == Tnone) {
+                               v->where_decl = var;
+                               v->where_set = var;
+                               v->type = $<CT;
+                               v->constant = 1;
+                               v->global = 1;
+                       } else {
+                               tok_err(c, "error: name already declared", &$1);
+                               type_err(c, "info: this is where '%v' was first declared",
+                                        v->where_decl, NULL, 0, NULL);
+                       }
                }
                var->var = v;
 
@@ -4942,23 +5013,46 @@ constants.
        static void resolve_consts(struct parse_context *c)
        {
                struct binode *b;
+               int retry = 1;
+               enum { none, some, cannot } progress = none;
+
                c->constlist = reorder_bilist(c->constlist);
-               for (b = cast(binode, c->constlist); b;
-                    b = cast(binode, b->right)) {
-                       enum prop_err perr;
-                       struct binode *vb = cast(binode, b->left);
-                       struct var *v = cast(var, vb->left);
-                       do {
-                               perr = 0;
-                               propagate_types(vb->right, c, &perr,
-                                               v->var->type, 0);
-                       } while (perr & Eretry);
-                       if (perr & Efail)
-                               c->parse_error += 1;
-                       else {
-                               struct value res = interp_exec(
-                                       c, vb->right, &v->var->type);
-                               global_alloc(c, v->var->type, v->var, &res);
+               while (retry) {
+                       retry = 0;
+                       for (b = cast(binode, c->constlist); b;
+                            b = cast(binode, b->right)) {
+                               enum prop_err perr;
+                               struct binode *vb = cast(binode, b->left);
+                               struct var *v = cast(var, vb->left);
+                               if (v->var->frame_pos >= 0)
+                                       continue;
+                               do {
+                                       perr = 0;
+                                       propagate_types(vb->right, c, &perr,
+                                                       v->var->type, 0);
+                               } while (perr & Eretry);
+                               if (perr & Efail)
+                                       c->parse_error += 1;
+                               else if (!(perr & Enoconst)) {
+                                       progress = some;
+                                       struct value res = interp_exec(
+                                               c, vb->right, &v->var->type);
+                                       global_alloc(c, v->var->type, v->var, &res);
+                               } else {
+                                       if (progress == cannot)
+                                               type_err(c, "error: const %v cannot be resolved.",
+                                                        v, NULL, 0, NULL);
+                                       else
+                                               retry = 1;
+                               }
+                       }
+                       switch (progress) {
+                       case cannot:
+                               retry = 0; break;
+                       case none:
+                               progress = cannot; break;
+                       case some:
+                               progress = none; break;
                        }
                }
        }
@@ -5009,7 +5103,7 @@ is a bit more interesting at this level.
                 * is a list for 'struct var'
                 */
                struct type *t = add_anon_type(c, &structure_prototype,
-                                              " function result");
+                                              "function result");
                int cnt = 0;
                struct binode *b;