diff options
author | Russ Cox <rsc@golang.org> | 2009-08-05 02:33:30 -0700 |
---|---|---|
committer | Russ Cox <rsc@golang.org> | 2009-08-05 02:33:30 -0700 |
commit | bb051efcc9f09eb62059ba3894f842cd6ec4c1a0 (patch) | |
tree | 9e87d95f08204d73f05aec930dd4728c4d0e4d25 | |
parent | 522168aad55bd4a03563605c213a0a9c35afc26e (diff) | |
download | golang-bb051efcc9f09eb62059ba3894f842cd6ec4c1a0.tar.gz |
delay range processing. old2new is gone
R=ken
OCL=32780
CL=32780
-rw-r--r-- | src/cmd/gc/Makefile | 1 | ||||
-rw-r--r-- | src/cmd/gc/dcl.c | 61 | ||||
-rw-r--r-- | src/cmd/gc/go.h | 9 | ||||
-rw-r--r-- | src/cmd/gc/go.y | 39 | ||||
-rw-r--r-- | src/cmd/gc/range.c | 216 | ||||
-rw-r--r-- | src/cmd/gc/select.c | 26 | ||||
-rw-r--r-- | src/cmd/gc/subr.c | 18 | ||||
-rw-r--r-- | src/cmd/gc/typecheck.c | 12 | ||||
-rw-r--r-- | src/cmd/gc/walk.c | 267 |
9 files changed, 286 insertions, 363 deletions
diff --git a/src/cmd/gc/Makefile b/src/cmd/gc/Makefile index 55b61ce8b..217c5c45f 100644 --- a/src/cmd/gc/Makefile +++ b/src/cmd/gc/Makefile @@ -30,6 +30,7 @@ OFILES=\ mparith3.$O\ obj.$O\ print.$O\ + range.$O\ reflect.$O\ select.$O\ sinit.$O\ diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c index fadf7fa23..4bbbae14c 100644 --- a/src/cmd/gc/dcl.c +++ b/src/cmd/gc/dcl.c @@ -594,39 +594,12 @@ colasname(Node *n) return 0; } -Node* -old2new(Node *n, Type *t, NodeList **init) -{ - Node *l; - - if(!colasname(n)) { - yyerror("left side of := must be a name"); - return n; - } - if(t != T && t->funarg) { - yyerror("use of multi func value as single value in :="); - return n; - } - l = newname(n->sym); - dodclvar(l, t, init); - return l; -} - -Node* -colas(NodeList *left, NodeList *right) +void +colasdefn(NodeList *left, Node *defn) { int nnew; - Node *n, *as; NodeList *l; - - if(count(left) == 1 && count(right) == 1) - as = nod(OAS, left->n, right->n); - else { - as = nod(OAS2, N, N); - as->list = left; - as->rlist = right; - } - as->colas = 1; + Node *n; nnew = 0; for(l=left; l; l=l->next) { @@ -640,14 +613,34 @@ colas(NodeList *left, NodeList *right) nnew++; n = newname(n->sym); declare(n, dclcontext); - if(as->op == OAS) - as->left = n; - n->defn = as; - as->ninit = list(as->ninit, nod(ODCL, n, N)); + n->defn = defn; + defn->ninit = list(defn->ninit, nod(ODCL, n, N)); l->n = n; } if(nnew == 0) yyerror("no new variables on left side of :="); +} + +Node* +colas(NodeList *left, NodeList *right) +{ + Node *as; + + as = nod(OAS2, N, N); + as->list = left; + as->rlist = right; + as->colas = 1; + colasdefn(left, as); + + // make the tree prettier; not necessary + if(count(left) == 1 && count(right) == 1) { + as->left = as->list->n; + as->right = as->rlist->n; + as->list = nil; + as->rlist = nil; + as->op = OAS; + } + return as; } diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h index c55e94f5f..d77b11f84 100644 --- a/src/cmd/gc/go.h +++ b/src/cmd/gc/go.h @@ -332,7 +332,7 @@ enum OCOMPSLICE, OCOMPMAP, OCONV, OCONVNOP, OCONVA2S, OCONVIFACE, OCONVSLICE, ODCL, ODCLFUNC, ODCLFIELD, ODCLARG, - ODOT, ODOTPTR, ODOTMETH, ODOTINTER, + ODOT, ODOTPTR, ODOTMETH, ODOTINTER, OXDOT, ODOTTYPE, OEQ, ONE, OLT, OLE, OGE, OGT, OFUNC, @@ -948,6 +948,7 @@ void walkconv(Node**, NodeList**); void walkdottype(Node*, NodeList**); void walkas(Node*); void walkswitch(Node*); +void walkrange(Node*); void walkselect(Node*); void walkdot(Node*, NodeList**); void walkexpr(Node**, NodeList**); @@ -967,22 +968,22 @@ void ifacecheck(Type*, Type*, int, int); void runifacechecks(void); Node* convas(Node*, NodeList**); Node* colas(NodeList*, NodeList*); -Node* dorange(Node*); +void colasdefn(NodeList*, Node*); NodeList* reorder1(NodeList*); NodeList* reorder3(NodeList*); NodeList* reorder4(NodeList*); Node* structlit(Node*, Node*, NodeList**); Node* arraylit(Node*, Node*, NodeList**); Node* maplit(Node*, Node*, NodeList**); -Node* selectas(Node*, Node*, NodeList**); -Node* old2new(Node*, Type*, NodeList**); void heapmoves(void); void walkdeflist(NodeList*); void walkdef(Node*); void typechecklist(NodeList*, int); void typecheckswitch(Node*); void typecheckselect(Node*); +void typecheckrange(Node*); Node* typecheckconv(Node*, Node*, Type*, int); +int checkconv(Type*, Type*, int, int*, int*); Node* typecheck(Node**, int); /* diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y index 0525cf8f2..bdb45f404 100644 --- a/src/cmd/gc/go.y +++ b/src/cmd/gc/go.y @@ -464,8 +464,7 @@ simple_stmt: case: LCASE expr_or_type_list ':' { - int e; - Node *n; + Node *n, *ntype; // will be converted to OCASE // right will point to next case @@ -474,29 +473,18 @@ case: $$ = nod(OXCASE, N, N); if(typeswvar != N && typeswvar->right != N) { // type switch - n = $2->n; + ntype = $2->n; if($2->next != nil) yyerror("type switch case cannot be list"); - if(n->op == OLITERAL && n->val.ctype == CTNIL) { + if(ntype->op == OLITERAL && ntype->val.ctype == CTNIL) { // case nil $$->list = list1(nod(OTYPECASE, N, N)); break; } - - // TODO: move - e = nerrors; - typecheck(&n, Etype | Erv); - if(n->op == OTYPE) { - n = old2new(typeswvar->right, n->type, &$$->ninit); - $$->list = list1(nod(OTYPECASE, n, N)); - break; - } - // maybe typecheck found problems that keep - // e from being valid even outside a type switch. - // only complain if typecheck didn't print new errors. - if(nerrors == e) - yyerror("non-type case in type switch"); - $$->diag = 1; + n = newname(typeswvar->right->sym); + declare(n, dclcontext); + n->ntype = ntype; + $$->list = list1(nod(OTYPECASE, n, N)); } else { // expr switch $$->list = $2; @@ -519,7 +507,6 @@ case: // done in casebody() poptodcl(); $$ = nod(OXCASE, N, N); -// $$->list = list1(nod(OAS, selectas($2, $4, &$$->ninit), $4)); $$->list = list1(colas(list1($2), list1($4))); } | LDEFAULT ':' @@ -590,7 +577,8 @@ range_stmt: { $$ = nod(ORANGE, N, $4); $$->list = $1; - $$->etype = 1; + $$->colas = 1; + colasdefn($1, $$); } for_header: @@ -612,9 +600,6 @@ for_header: $$->ntest = $1; } | range_stmt - { - $$ = dorange($1); - } for_body: for_header loop_body @@ -850,8 +835,7 @@ pexpr: $$ = oldname(s); break; } - $$ = nod(ODOT, $1, newname($3)); - $$ = adddot($$); + $$ = nod(OXDOT, $1, newname($3)); } | '(' expr_or_type ')' { @@ -1041,8 +1025,7 @@ dotname: $$ = oldname(s); break; } - $$ = nod(ODOT, $1, newname($3)); - $$ = adddot($$); + $$ = nod(OXDOT, $1, newname($3)); } othertype: diff --git a/src/cmd/gc/range.c b/src/cmd/gc/range.c new file mode 100644 index 000000000..bc51ee6ac --- /dev/null +++ b/src/cmd/gc/range.c @@ -0,0 +1,216 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* + * range + */ + +#include "go.h" + +void +typecheckrange(Node *n) +{ + int op, et; + Type *t, *t1, *t2; + Node *v1, *v2; + NodeList *ll; + + // delicate little dance. see typecheckas2 + for(ll=n->list; ll; ll=ll->next) + if(ll->n->defn != n) + typecheck(&ll->n, Erv); + + typecheck(&n->right, Erv); + if((t = n->right->type) == T) + goto out; + n->type = t; + + switch(t->etype) { + default: + yyerror("cannot range over %+N", n->right); + goto out; + + case TARRAY: + t1 = types[TINT]; + t2 = t->type; + break; + + case TMAP: + t1 = t->down; + t2 = t->type; + break; + + case TCHAN: + t1 = t->type; + t2 = nil; + if(count(n->list) == 2) + goto toomany; + break; + + case TSTRING: + t1 = types[TINT]; + t2 = types[TINT]; + break; + } + + if(count(n->list) > 2) { + toomany: + yyerror("too many variables in range"); + } + + v1 = n->list->n; + v2 = N; + if(n->list->next) + v2 = n->list->next->n; + + if(v1->defn == n) + v1->type = t1; + else if(v1->type != T && checkconv(t1, v1->type, 0, &op, &et) < 0) + yyerror("cannot assign type %T to %+N", t1, v1); + if(v2) { + if(v2->defn == n) + v2->type = t2; + else if(v2->type != T && checkconv(t2, v2->type, 0, &op, &et) < 0) + yyerror("cannot assign type %T to %+N", t1, v1); + } + +out: + typechecklist(n->nbody, Etop); + + // second half of dance + n->typecheck = 1; + for(ll=n->list; ll; ll=ll->next) + if(ll->n->typecheck == 0) + typecheck(&ll->n, Erv); +} + +void +walkrange(Node *n) +{ + Node *ohv1, *hv1, *hv2; // hidden (old) val 1, 2 + Node *ha, *hit; // hidden aggregate, iterator + Node *a, *v1, *v2; // not hidden aggregate, val 1, 2 + Node *fn; + NodeList *body, *init; + Type *th, *t; + + t = n->type; + init = nil; + + a = n->right; + if(t->etype == TSTRING && !eqtype(t, types[TSTRING])) { + a = nod(OCONV, n->right, N); + a->type = types[TSTRING]; + } + ha = nod(OXXX, N, N); + tempname(ha, a->type); + init = list(init, nod(OAS, ha, a)); + + v1 = n->list->n; + hv1 = N; + + v2 = N; + if(n->list->next) + v2 = n->list->next->n; + hv2 = N; + + switch(t->etype) { + default: + fatal("walkrange"); + + case TARRAY: + hv1 = nod(OXXX, N, n); + tempname(hv1, v1->type); + + init = list(init, nod(OAS, hv1, N)); + n->ntest = nod(OLT, hv1, nod(OLEN, ha, N)); + n->nincr = nod(OASOP, hv1, nodintconst(1)); + n->nincr->etype = OADD; + body = list1(nod(OAS, v1, hv1)); + if(v2) + body = list(body, nod(OAS, v2, nod(OINDEX, ha, hv1))); + break; + + case TMAP: + th = typ(TARRAY); + th->type = ptrto(types[TUINT8]); + th->bound = (sizeof(struct Hiter) + widthptr - 1) / widthptr; + hit = nod(OXXX, N, N); + tempname(hit, th); + + fn = syslook("mapiterinit", 1); + argtype(fn, t->down); + argtype(fn, t->type); + argtype(fn, th); + init = list(init, mkcall1(fn, T, nil, ha, nod(OADDR, hit, N))); + n->ntest = nod(ONE, nod(OINDEX, hit, nodintconst(0)), nodnil()); + + fn = syslook("mapiternext", 1); + argtype(fn, th); + n->nincr = mkcall1(fn, T, nil, nod(OADDR, hit, N)); + + if(v2 == N) { + fn = syslook("mapiter1", 1); + argtype(fn, th); + argtype(fn, t->down); + a = nod(OAS, v1, mkcall1(fn, t->down, nil, nod(OADDR, hit, N))); + } else { + fn = syslook("mapiter2", 1); + argtype(fn, th); + argtype(fn, t->down); + argtype(fn, t->type); + a = nod(OAS2, N, N); + a->list = list(list1(v1), v2); + a->rlist = list1(mkcall1(fn, getoutargx(fn->type), nil, nod(OADDR, hit, N))); + } + body = list1(a); + break; + + case TCHAN: + hv1 = nod(OXXX, N, n); + tempname(hv1, v1->type); + + n->ntest = nod(ONOT, nod(OCLOSED, ha, N), N); + n->ntest->ninit = list1(nod(OAS, hv1, nod(ORECV, ha, N))); + body = list1(nod(OAS, v1, hv1)); + break; + + case TSTRING: + ohv1 = nod(OXXX, N, N); + tempname(ohv1, types[TINT]); + + hv1 = nod(OXXX, N, N); + tempname(hv1, types[TINT]); + init = list(init, nod(OAS, hv1, N)); + + if(v2 == N) + a = nod(OAS, hv1, mkcall("stringiter", types[TINT], nil, ha, hv1)); + else { + hv2 = nod(OXXX, N, N); + tempname(hv2, types[TINT]); + a = nod(OAS2, N, N); + a->list = list(list1(hv1), hv2); + fn = syslook("stringiter2", 0); + a->rlist = list1(mkcall1(fn, getoutargx(fn->type), nil, ha, hv1)); + } + n->ntest = nod(ONE, hv1, nodintconst(0)); + n->ntest->ninit = list(list1(nod(OAS, ohv1, hv1)), a); + + body = list1(nod(OAS, v1, ohv1)); + if(v2 != N) + body = list(body, nod(OAS, v2, hv2)); + break; + } + + n->op = OFOR; + typechecklist(init, Etop); + n->ninit = concat(n->ninit, init); + typechecklist(n->ntest->ninit, Etop); + typecheck(&n->ntest, Erv); + typecheck(&n->nincr, Etop); + typechecklist(body, Etop); + n->nbody = concat(body, n->nbody); + walkstmt(&n); +} + diff --git a/src/cmd/gc/select.c b/src/cmd/gc/select.c index 7a90ae2c9..3f28b1c56 100644 --- a/src/cmd/gc/select.c +++ b/src/cmd/gc/select.c @@ -8,32 +8,6 @@ #include "go.h" -/* - * declare v in - * case v := <-chan // select and switch - * called during parse - */ -Node* -selectas(Node *name, Node *expr, NodeList **init) -{ - Type *t; - - if(expr == N || expr->op != ORECV) - goto bad; - - walkexpr(&expr->left, init); - t = expr->left->type; - if(t == T) - goto bad; - if(t->etype != TCHAN) - goto bad; - t = t->type; - return old2new(name, t, init); - -bad: - return name; -} - void typecheckselect(Node *sel) { diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c index 71217d8af..cf0811901 100644 --- a/src/cmd/gc/subr.c +++ b/src/cmd/gc/subr.c @@ -582,11 +582,6 @@ dodump(Node *n, int dep) print("%O-ntype\n", n->op); dodump(n->ntype, dep+1); } - if(n->defn != nil && n->defn->op != OAS && n->defn->op != OAS2) { - indent(dep); - print("%O-defn\n", n->op); - dodump(n->defn, dep+1); - } if(n->list != nil) { indent(dep); print("%O-list\n", n->op); @@ -597,6 +592,11 @@ dodump(Node *n, int dep) print("%O-rlist\n", n->op); dodumplist(n->rlist, dep+1); } + if(n->nbody != nil) { + indent(dep); + print("%O-nbody\n", n->op); + dodumplist(n->nbody, dep+1); + } } void @@ -2466,10 +2466,8 @@ out: yyerror("ambiguous DOT reference %T.%S", t, s); // rebuild elided dots - for(c=d-1; c>=0; c--) { - n = nod(ODOT, n, n->right); - n->left->right = newname(dotlist[c].field->sym); - } + for(c=d-1; c>=0; c--) + n->left = nod(ODOT, n->left, newname(dotlist[c].field->sym)); ret: return n; } @@ -2705,7 +2703,7 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam) args = list(args, l->n->left); // generate call - call = nod(OCALL, adddot(nod(ODOT, this->left, newname(method->sym))), N); + call = nod(OCALL, adddot(nod(OXDOT, this->left, newname(method->sym))), N); call->list = args; fn->nbody = list1(call); if(method->type->outtuple > 0) { diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c index 177c2b589..1deb60582 100644 --- a/src/cmd/gc/typecheck.c +++ b/src/cmd/gc/typecheck.c @@ -12,7 +12,6 @@ * * TODO: * trailing ... section of function calls - * range */ #include "go.h" @@ -376,6 +375,10 @@ reswitch: goto error; goto ret; + case OXDOT: + n = adddot(n); + n->op = ODOT; + // fall through case ODOT: l = typecheck(&n->left, Erv); if((t = l->type) == T) @@ -882,6 +885,11 @@ reswitch: typecheckswitch(n); goto ret; + case ORANGE: + ok |= Etop; + typecheckrange(n); + goto ret; + case OTYPECASE: ok |= Etop | Erv; typecheck(&n->left, Erv); @@ -1069,7 +1077,7 @@ nokeys(NodeList *l) return 1; } -static int +int checkconv(Type *nt, Type *t, int explicit, int *op, int *et) { *op = OCONV; diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index e1f2d1bf8..1121915b5 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -285,7 +285,10 @@ walkstmt(Node **np) case OFOR: walkstmtlist(n->ninit); - walkexpr(&n->ntest, &n->ntest->ninit); + if(n->ntest != N) { + walkstmtlist(n->ntest->ninit); + walkexpr(&n->ntest, &n->ntest->ninit); + } walkstmt(&n->nincr); walkstmtlist(n->nbody); break; @@ -319,6 +322,10 @@ walkstmt(Node **np) walkswitch(n); break; + case ORANGE: + walkrange(n); + break; + case OXFALL: yyerror("fallthrough statement out of place"); n->op = OFALL; @@ -1703,264 +1710,6 @@ out: } /* - * rewrite a range statement - * k and v are names/new_names - * m is an array or map - * local is 0 (meaning =) or 1 (meaning :=) - */ -Node* -dorange(Node *nn) -{ - Node *k, *v, *m; - Node *n, *hv, *hc, *ha, *hk, *ohk, *on, *r, *a, *as; - NodeList *init, *args; - Type *t, *th; - int local; - NodeList *nl; - - if(nn->op != ORANGE) - fatal("dorange not ORANGE"); - - nl = nn->list; - k = nl->n; - if((nl = nl->next) != nil) { - v = nl->n; - nl = nl->next; - } else - v = N; - if(nl != nil) - yyerror("too many variables in range"); - - n = nod(OFOR, N, N); - init = nil; - - typecheck(&nn->right, Erv); - m = nn->right; - local = nn->etype; - - t = m->type; - if(t == T) - goto out; - if(t->etype == TARRAY) - goto ary; - if(t->etype == TMAP) - goto map; - if(t->etype == TCHAN) - goto chan; - if(t->etype == TSTRING) - goto strng; - - yyerror("range must be over map/array/chan/string"); - goto out; - -ary: - hk = nod(OXXX, N, N); // hidden key - tempname(hk, types[TINT]); - - ha = nod(OXXX, N, N); // hidden array - tempname(ha, t); - - a = nod(OAS, hk, nodintconst(0)); - init = list(init, a); - - a = nod(OAS, ha, m); - init = list(init, a); - - n->ntest = nod(OLT, hk, nod(OLEN, ha, N)); - n->nincr = nod(OASOP, hk, nodintconst(1)); - n->nincr->etype = OADD; - - if(local) - k = old2new(k, hk->type, &init); - n->nbody = list1(nod(OAS, k, hk)); - - if(v != N) { - if(local) - v = old2new(v, t->type, &init); - n->nbody = list(n->nbody, - nod(OAS, v, nod(OINDEX, ha, hk)) ); - } - goto out; - -map: - th = typ(TARRAY); - th->type = ptrto(types[TUINT8]); - th->bound = (sizeof(struct Hiter) + types[tptr]->width - 1) / - types[tptr]->width; - hk = nod(OXXX, N, N); // hidden iterator - tempname(hk, th); // hashmap hash_iter - - on = syslook("mapiterinit", 1); - argtype(on, t->down); - argtype(on, t->type); - argtype(on, th); - a = nod(OADDR, hk, N); - r = nod(OCALL, on, N); - r->list = list(list1(m), a); - - init = list(init, r); - - r = nod(OINDEX, hk, nodintconst(0)); - a = nod(OLITERAL, N, N); - a->val.ctype = CTNIL; - a->type = types[TNIL]; - r = nod(ONE, r, a); - n->ntest = r; - - on = syslook("mapiternext", 1); - argtype(on, th); - r = nod(OADDR, hk, N); - args = list1(r); - r = nod(OCALL, on, N); - r->list = args; - n->nincr = r; - - if(local) - k = old2new(k, t->down, &init); - if(v == N) { - on = syslook("mapiter1", 1); - argtype(on, th); - argtype(on, t->down); - r = nod(OADDR, hk, N); - args = list1(r); - r = nod(OCALL, on, N); - r->list = args; - n->nbody = list1(nod(OAS, k, r)); - goto out; - } - if(local) - v = old2new(v, t->type, &init); - on = syslook("mapiter2", 1); - argtype(on, th); - argtype(on, t->down); - argtype(on, t->type); - r = nod(OADDR, hk, N); - args = list1(r); - r = nod(OCALL, on, N); - r->list = args; - as = nod(OAS2, N, N); - as->list = list(list1(k), v); - as->rlist = list1(r); - n->nbody = list1(as); - goto out; - -chan: - if(v != N) - yyerror("chan range can only have one variable"); - - hc = nod(OXXX, N, N); // hidden chan - tempname(hc, t); - - hv = nod(OXXX, N, N); // hidden value - tempname(hv, t->type); - - a = nod(OAS, hc, m); - init = list(init, a); - - a = nod(ORECV, hc, N); - a = nod(OAS, hv, a); - init = list(init, a); - - a = nod(OCLOSED, N, N); - a->list = list1(hc); - n->ntest = nod(ONOT, a, N); - n->nincr = nod(OAS, hv, nod(ORECV, hc, N)); - - if(local) - k = old2new(k, hv->type, &init); - n->nbody = list1(nod(OAS, k, hv)); - - goto out; - -strng: - hk = nod(OXXX, N, N); // hidden key - tempname(hk, types[TINT]); - - ohk = nod(OXXX, N, N); // old hidden key - tempname(ohk, types[TINT]); - - ha = nod(OXXX, N, N); // hidden string - tempname(ha, types[TSTRING]); - - hv = N; - if(v != N) { - hv = nod(OXXX, N, N); // hidden value - tempname(hv, types[TINT]); - } - - if(local) { - k = old2new(k, types[TINT], &init); - if(v != N) - v = old2new(v, types[TINT], &init); - } - - // ha = s - a = nod(OCONV, m, N); - a->type = ha->type; - a = nod(OAS, ha, a); - init = list(init, a); - - // ohk = 0 - a = nod(OAS, ohk, nodintconst(0)); - init = list(init, a); - - // hk[,hv] = stringiter(ha,hk) - if(v != N) { - // hk,v = stringiter2(ha, hk) - on = syslook("stringiter2", 0); - a = nod(OCALL, on, N); - a->list = list(list1(ha), nodintconst(0)); - as = nod(OAS2, N, N); - as->list = list(list1(hk), hv); - as->rlist = list1(a); - a = as; - } else { - // hk = stringiter(ha, hk) - on = syslook("stringiter", 0); - a = nod(OCALL, on, N); - a->list = list(list1(ha), nodintconst(0)); - a = nod(OAS, hk, a); - } - init = list(init, a); - - // while(hk != 0) - n->ntest = nod(ONE, hk, nodintconst(0)); - - // hk[,hv] = stringiter(ha,hk) - if(v != N) { - // hk,hv = stringiter2(ha, hk) - on = syslook("stringiter2", 0); - a = nod(OCALL, on, N); - a->list = list(list1(ha), hk); - as = nod(OAS2, N, N); - as->list = list(list1(hk), hv); - as->rlist = list1(a); - a = as; - } else { - // hk = stringiter(ha, hk) - on = syslook("stringiter", 0); - a = nod(OCALL, on, N); - a->list = list(list1(ha), hk); - a = nod(OAS, hk, a); - } - n->nincr = a; - - // k,ohk[,v] = ohk,hk,[,hv] - a = nod(OAS, k, ohk); - n->nbody = list1(a); - a = nod(OAS, ohk, hk); - n->nbody = list(n->nbody, a); - if(v != N) { - a = nod(OAS, v, hv); - n->nbody = list(n->nbody, a); - } - -out: - n->ninit = concat(n->ninit, init); - return n; -} - -/* * from ascompat[te] * evaluating actual function arguments. * f(a,b) |