From 5c455fe9ef93d88b349bb25733d5ea20a8984050 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Fri, 17 Dec 2021 16:04:01 +1100 Subject: [PATCH] oceani: assignment to a pointer can take an address. 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 --- csrc/oceani-tests.mdc | 63 ++++++++++++++++++++++--------------------- csrc/oceani.mdc | 58 ++++++++++++++++++++++++++++++--------- 2 files changed, 77 insertions(+), 44 deletions(-) diff --git a/csrc/oceani-tests.mdc b/csrc/oceani-tests.mdc index 3be36db..c990bad 100644 --- a/csrc/oceani-tests.mdc +++ b/csrc/oceani-tests.mdc @@ -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 diff --git a/csrc/oceani.mdc b/csrc/oceani.mdc index e032a7d..1ec640f 100644 --- a/csrc/oceani.mdc +++ b/csrc/oceani.mdc @@ -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, <ype); - 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; } -- 2.43.0