###### 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
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
.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
###### 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};
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)
return Tnone;
}
-
static struct type reference_prototype = {
.print_type = reference_print_type,
.cmp_eq = reference_cmp,
| @ 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);
be declared at any time.
###### Binode types
- Assign,
- Declare,
+ Assign, AssignRef,
+ Declare, DeclareRef,
###### declare terminals
$TERM =
###### print binode cases
case Assign:
+ case AssignRef:
do_indent(indent, "");
print_exec(b->left, -1, bracket);
printf(" = ");
break;
case Declare:
+ case DeclareRef:
{
struct variable *v = cast(var, b->left)->var;
do_indent(indent, "");
###### 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
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)
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) {
###### 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;
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;
}