]> ocean-lang.org Git - ocean/blobdiff - csrc/oceani.mdc
oceani: assignment to a pointer can take an address.
[ocean] / csrc / oceani.mdc
index c80c99262004c6b39f82ca924e7e513fb3fddfaf..1ec640f1b4ed6520b17723d36d00d15c1e3a011d 100644 (file)
@@ -598,7 +598,7 @@ the value can only be assigned once, when the variable is declared.
 
 ###### ast
 
-       enum val_rules {Rboolok = 1<<0,};
+       enum val_rules {Rboolok = 1<<0, Rrefok = 1<<1,};
        enum prop_err {Efail = 1<<0, Eretry = 1<<1, Eruntime = 1<<2,
                       Emaycopy = 1<<3, Erval = 1<<4, Econst = 1<<5};
 
@@ -2917,24 +2917,31 @@ function will be needed.
        }
 
 ###### top level grammar
-       DeclareStruct -> struct IDENTIFIER FieldBlock Newlines ${ {
-               struct type *t;
-               t = find_type(c, $ID.txt);
-               if (!t)
-                       t = add_type(c, $ID.txt, &structure_prototype);
-               else if (t->size >= 0) {
+       $*type
+       StructName -> IDENTIFIER ${ {
+               struct type *t = find_type(c, $ID.txt);
+
+               if (t && 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 = NULL;
                }
-               t->structure.field_list = $<FB;
+               if (!t)
+                       t = add_type(c, $ID.txt, NULL);
                t->first_use = $ID;
+               $0 = t;
+       } }$
+       $void
+       DeclareStruct -> struct StructName FieldBlock Newlines ${ {
+               struct type *t = $<SN;
+               struct type tmp = *t;
+
+               *t = structure_prototype;
+               t->name = tmp.name;
+               t->next = tmp.next;
+               t->first_use = tmp.first_use;
+
+               t->structure.field_list = $<FB;
        } }$
 
        $*fieldlist
@@ -3121,6 +3128,9 @@ anything in the heap or on the stack.  A reference can be assigned
        static int reference_compat(struct type *require, struct type *have,
                                    enum val_rules rules)
        {
+               if (rules & Rrefok)
+                       if (require->reference.referent == have)
+                               return 1;
                if (have->compat != require->compat)
                        return 0;
                if (have->reference.referent != require->reference.referent)
@@ -3148,7 +3158,6 @@ anything in the heap or on the stack.  A reference can be assigned
                return Tnone;
        }
 
-
        static struct type reference_prototype = {
                .print_type = reference_print_type,
                .cmp_eq = reference_cmp,
@@ -4714,8 +4723,8 @@ it is declared, it is assumed to be a global constant which are allowed to
 be declared at any time.
 
 ###### Binode types
-       Assign,
-       Declare,
+       Assign, AssignRef,
+       Declare, DeclareRef,
 
 ###### declare terminals
        $TERM =
@@ -4751,6 +4760,7 @@ be declared at any time.
 ###### print binode cases
 
        case Assign:
+       case AssignRef:
                do_indent(indent, "");
                print_exec(b->left, -1, bracket);
                printf(" = ");
@@ -4760,6 +4770,7 @@ be declared at any time.
                break;
 
        case Declare:
+       case DeclareRef:
                {
                struct variable *v = cast(var, b->left)->var;
                do_indent(indent, "");
@@ -4789,8 +4800,10 @@ be declared at any time.
 ###### propagate binode cases
 
        case Assign:
+       case AssignRef:
        case Declare:
-               /* Both must match and not be labels,
+       case DeclareRef:
+               /* Both must match, or left may be ref and right an lval
                 * Type must support 'dup',
                 * For Assign, left must not be constant.
                 * result is Tnone
@@ -4801,11 +4814,23 @@ be declared at any time.
                        return Tnone;
 
                if (t) {
-                       if (propagate_types(b->right, c, perr_local, t, 0) != t &&
-                           *perr_local & Efail)
-                               if (b->left->type == Xvar)
-                                       type_err(c, "info: variable '%v' was set as %1 here.",
-                                                cast(var, b->left)->var->where_set, t, rules, NULL);
+                       struct type *t2 = propagate_types(b->right, c, perr_local,
+                                                         t, Rrefok);
+                       if (!t2 || t2 == t || (*perr_local & Efail))
+                               ; // No more effort needed
+                       else if (t->free == reference_free &&
+                                t->reference.referent == t2 &&
+                                !(*perr_local & Erval)) {
+                               if (b->op == Assign)
+                                       b->op = AssignRef;
+                               if (b->op == Declare)
+                                       b->op = DeclareRef;
+                       }
+                       else if (t->free == reference_free &&
+                                t->reference.referent == t2 &&
+                                (*perr_local & Erval))
+                               type_err(c, "error: Cannot assign an rval to a reference.",
+                                        b, NULL, 0, NULL);
                } else {
                        t = propagate_types(b->right, c, perr_local, NULL, 0);
                        if (t)
@@ -4814,7 +4839,7 @@ be declared at any time.
                if (*perr & Erval)
                        type_err(c, "error: cannot assign to an rval", b,
                                 NULL, 0, NULL);
-               else if (b->op == Assign && (*perr & Econst)) {
+               else if ((b->op == Assign || b->op == AssignRef) && (*perr & Econst)) {
                        type_err(c, "error: Cannot assign to a constant: %v",
                                 b->left, NULL, 0, NULL);
                        if (b->left->type == Xvar) {
@@ -4826,6 +4851,9 @@ be declared at any time.
                }
                if (t && t->dup == NULL && !(*perr_local & Emaycopy))
                        type_err(c, "error: cannot assign value of type %1", b, t, 0, NULL);
+               if (b->left->type == Xvar && (*perr_local & Efail))
+                       type_err(c, "info: variable '%v' was set as %1 here.",
+                                cast(var, b->left)->var->where_set, t, rules, NULL);
                return Tnone;
 
                break;
@@ -4833,13 +4861,21 @@ be declared at any time.
 ###### interp binode cases
 
        case Assign:
+       case AssignRef:
                lleft = linterp_exec(c, b->left, &ltype);
-               if (lleft)
+               if (!lleft)
+                       // FIXME lleft==NULL probably means illegal array ref
+                       // should that cause a runtime error
+                       ;
+               else if (b->op == AssignRef)
+                       lleft->ref = linterp_exec(c, b->right, &rtype);
+               else
                        dinterp_exec(c, b->right, lleft, ltype, 1);
                ltype = Tnone;
                break;
 
        case Declare:
+       case DeclareRef:
        {
                struct variable *v = cast(var, b->left)->var;
                struct value *val;
@@ -4847,10 +4883,12 @@ be declared at any time.
                val = var_value(c, v);
                if (v->type->prepare_type)
                        v->type->prepare_type(c, v->type, 0);
-               if (b->right)
-                       dinterp_exec(c, b->right, val, v->type, 0);
-               else
+               if (!b->right)
                        val_init(v->type, val);
+               else if (b->op == DeclareRef)
+                       val->ref = linterp_exec(c, b->right, &rtype);
+               else
+                       dinterp_exec(c, b->right, val, v->type, 0);
                break;
        }