]> ocean-lang.org Git - ocean/commitdiff
oceani: assignment to a pointer can take an address.
authorNeilBrown <neil@brown.name>
Fri, 17 Dec 2021 05:04:01 +0000 (16:04 +1100)
committerNeilBrown <neil@brown.name>
Fri, 17 Dec 2021 05:25:30 +0000 (16:25 +1100)
If the non-pointer is assigned to a pointer, and the non-pointer is
provided as an lval, the address is now assigned - rather than causing
an error.

Signed-off-by: NeilBrown <neil@brown.name>
csrc/oceani-tests.mdc
csrc/oceani.mdc

index 3be36db0734c49836117f3957c40e317d3184cac..c990bad78a101383f5aa942537b5bbbecf96f4d0 100644 (file)
@@ -723,44 +723,43 @@ A simple linked list example
 
 ###### test: linked_list
 
-       struct node
+       struct linkage
                next: @node
+       struct node
+               list: linkage
                this: string
 
-       func insert(list:@node; new:string):@node
+       func insert(list:@linkage; new:string)
                p:=list
-               prev := @nil
-               while ?p and then p.this < new:
-                       prev = p
-                       p = p.next
-               if ?prev:
-                       prev.next = @new()
-                       prev.next.next = p
-                       prev.next.this = new
-               else
-                       list = @new()
-                       list.next = p
-                       list.this = new
-               use list
-
-       func printlist(list:@node)
-               while ?list:
-                       print list@.this
-                       list = list@.next
-
-       func freelist(list:@node)
-               if list != @nil:
-                       freelist(list.next)
-                       @free = list
+               while ?p.next and then p.next.this < new:
+                       p = p.next.list
+               t:@node = @new()
+               t.list.next = p.next
+               t.this = new
+               p.next = t;
+
+       func printlist(list:@linkage)
+               while ?list.next:
+                       print list@.next.this
+                       list = list@.next.list
+
+       func freelist(list:@linkage)
+               if list.next != @nil:
+                       lp:@linkage = list.next.list
+                       freelist(lp)
+                       @free = list.next
 
        func main(argv:[ac::]string)
-               list := insert(@nil, "@start")
-               list = insert(list, "~end")
+               list : linkage
+               lp:@linkage = list
+
+               insert(lp, "@start");
+               insert(lp, "~end")
                for i:=1; then i=i+1; while i < ac:
-                       list = insert(list, argv[i])
-               list = insert(list, "Hello!")
-               printlist(list)
-               freelist(list)
+                       insert(lp, argv[i])
+               insert(lp, "Hello!")
+               printlist(lp)
+               freelist(lp)
 
 ###### output: linked_list,one,two,three,four
        @start
@@ -1203,6 +1202,7 @@ Test for errors with references
                print num@
                if num == @nil or ref == ref2 or ref == 2 or ref.foo:
                        @free = num
+               ref = 1
 
 ###### output: ref_err2
        .tmp.code:5:22: error: @new() can only be used with references, not number
@@ -1216,6 +1216,7 @@ Test for errors with references
        .tmp.code:7:56: error: have none but need Boolean
        .tmp.code:8:17: error: @free can only be assigned a reference, not number
        .tmp.code:8:17: error: @free can only be assigned a reference, not number
+       .tmp.code:9:8: error: Cannot assign an rval to a reference.
        oceani: type error in program - not running.
 
 ## Test erroneous command line args
index e032a7d5a268e76c5f6e459e666859640fbcab22..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};
 
@@ -3128,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)
@@ -3155,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,
@@ -3173,8 +3175,8 @@ anything in the heap or on the stack.  A reference can be assigned
        | @ IDENTIFIER ${ {
                struct type *t = find_type(c, $ID.txt);
                if (!t) {
-                       t = add_type(c, $ID.txt, NULL); // UNTESTED
-                       t->first_use = $ID;     // UNTESTED
+                       t = add_type(c, $ID.txt, NULL);
+                       t->first_use = $ID;
                }
                $0 = find_anon_type(c, &reference_prototype, "@%.*s",
                                    $ID.txt.len, $ID.txt.txt);
@@ -4721,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 =
@@ -4758,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(" = ");
@@ -4767,6 +4770,7 @@ be declared at any time.
                break;
 
        case Declare:
+       case DeclareRef:
                {
                struct variable *v = cast(var, b->left)->var;
                do_indent(indent, "");
@@ -4796,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
@@ -4808,7 +4814,23 @@ be declared at any time.
                        return Tnone;
 
                if (t) {
-                       propagate_types(b->right, c, perr_local, t, 0);
+                       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)
@@ -4817,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) {
@@ -4839,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;
@@ -4853,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;
        }