diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
| commit | 37da2899f40661e3e9631e497da8dc59b971cbd0 (patch) | |
| tree | cbc6d4680e347d906f5fa7fca73214418741df72 /limbo/nodes.c | |
| parent | 54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff) | |
20060303a
Diffstat (limited to 'limbo/nodes.c')
| -rw-r--r-- | limbo/nodes.c | 1538 |
1 files changed, 1538 insertions, 0 deletions
diff --git a/limbo/nodes.c b/limbo/nodes.c new file mode 100644 index 00000000..920458d3 --- /dev/null +++ b/limbo/nodes.c @@ -0,0 +1,1538 @@ +#include "limbo.h" + +static vlong +ipow(vlong x, int n) +{ + int inv; + vlong r; + + inv = 0; + if(n < 0){ + n = -n; + inv = 1; + } + r = 1; + for(;;){ + if(n&1) + r *= x; + if((n >>= 1) == 0) + break; + x *= x; + } + if(inv) + r = 1/r; + return r; +} + +double +rpow(double x, int n) +{ + int inv; + double r; + + inv = 0; + if(n < 0){ + n = -n; + inv = 1; + } + r = 1; + for(;;){ + if(n&1) + r *= x; + if((n >>= 1) == 0) + break; + x *= x; + } + if(inv) + r = 1/r; + return r; +} + +Long +real2fix(double v, Type *t) +{ + v /= scale(t); + v = v < 0 ? v-0.5: v+0.5; + return v; +} + +Long +fix2fix(Long v, Type *f, Type *t) +{ + double r; + + r = (double)v * (scale(f)/scale(t)); + r = r < 0 ? r-0.5: r+0.5; + return r; +} + +double +fix2real(Long v, Type *f) +{ + return (double)v * scale(f); +} + +int +istuple(Node *n) +{ + Decl *d; + + switch(n->op){ + case Otuple: + return 1; + case Oname: + d = n->decl; + if(d->importid != nil) + d = d->importid; + return d->store == Dconst && (n->ty->kind == Ttuple || n->ty->kind == Tadt); + case Odot: + return 0; /* istuple(n->left); */ + } + return 0; +} + +static Node* +tuplemem(Node *n, Decl *d) +{ + Type *ty; + Decl *ids; + + ty = n->ty; + n = n->left; + for(ids = ty->ids; ids != nil; ids = ids->next){ + if(ids->sym == d->sym) + break; + else + n = n->right; + } + if(n == nil) + fatal("tuplemem cannot cope !\n"); + return n->left; +} + +int +varcom(Decl *v) +{ + Node *n, tn; + + n = v->init; + n = fold(n); + v->init = n; + if(debug['v']) + print("variable '%D' val %V\n", v, n); + if(n == nil) + return 1; + + tn = znode; + tn.op = Oname; + tn.decl = v; + tn.src = v->src; + tn.ty = v->ty; + return initable(&tn, n, 0); +} + +int +initable(Node *v, Node *n, int allocdep) +{ + Node *e; + + switch(n->ty->kind){ + case Tiface: + case Tgoto: + case Tcase: + case Tcasel: + case Tcasec: + case Talt: + case Texcept: + return 1; + case Tint: + case Tbig: + case Tbyte: + case Treal: + case Tstring: + case Tfix: + if(n->op != Oconst) + break; + return 1; + case Tadt: + case Tadtpick: + case Ttuple: + if(n->op == Otuple) + n = n->left; + else if(n->op == Ocall) + n = n->right; + else + break; + for(; n != nil; n = n->right) + if(!initable(v, n->left, allocdep)) + return 0; + return 1; + case Tarray: + if(n->op != Oarray) + break; + if(allocdep >= DADEPTH){ + nerror(v, "%Vs initializer has arrays nested more than %d deep", v, allocdep); + return 0; + } + allocdep++; + usedesc(mktdesc(n->ty->tof)); + if(n->left->op != Oconst){ + nerror(v, "%Vs size is not a constant", v); + return 0; + } + for(e = n->right; e != nil; e = e->right) + if(!initable(v, e->left->right, allocdep)) + return 0; + return 1; + case Tany: + return 1; + case Tref: + case Tlist: + case Tpoly: + default: + nerror(v, "can't initialize %Q", v); + return 0; + } + nerror(v, "%Vs initializer, %V, is not a constant expression", v, n); + return 0; +} + +/* + * merge together two sorted lists, yielding a sorted list + */ +static Node* +elemmerge(Node *e, Node *f) +{ + Node rock, *r; + + r = &rock; + while(e != nil && f != nil){ + if(e->left->left->val <= f->left->left->val){ + r->right = e; + e = e->right; + }else{ + r->right = f; + f = f->right; + } + r = r->right; + } + if(e != nil) + r->right = e; + else + r->right = f; + return rock.right; +} + +/* + * recursively split lists and remerge them after they are sorted + */ +static Node* +recelemsort(Node *e, int n) +{ + Node *r, *ee; + int i, m; + + if(n <= 1) + return e; + m = n / 2 - 1; + ee = e; + for(i = 0; i < m; i++) + ee = ee->right; + r = ee->right; + ee->right = nil; + return elemmerge(recelemsort(e, n / 2), + recelemsort(r, (n + 1) / 2)); +} + +/* + * sort the elems by index; wild card is first + */ +Node* +elemsort(Node *e) +{ + Node *ee; + int n; + + n = 0; + for(ee = e; ee != nil; ee = ee->right){ + if(ee->left->left->op == Owild) + ee->left->left->val = -1; + n++; + } + return recelemsort(e, n); +} + +int +sametree(Node *n1, Node *n2) +{ + if(n1 == n2) + return 1; + if(n1 == nil || n2 == nil) + return 0; + if(n1->op != n2->op || n1->ty != n2->ty) + return 0; + if(n1->op == Oconst){ + switch(n1->ty->kind){ + case Tbig: + case Tbyte: + case Tint: + return n1->val == n2->val; + case Treal: + return n1->rval == n2->rval; + case Tfix: + return n1->val == n2->val && tequal(n1->ty, n2->ty); + case Tstring: + return n1->decl->sym == n2->decl->sym; + } + return 0; + } + return n1->decl == n2->decl && sametree(n1->left, n2->left) && sametree(n1->right, n2->right); +} + +int +occurs(Decl *d, Node *n) +{ + if(n == nil) + return 0; + if(n->op == Oname){ + if(d == n->decl) + return 1; + return 0; + } + return occurs(d, n->left) + occurs(d, n->right); +} + +/* + * left and right subtrees the same + */ +Node* +folds(Node *n) +{ + if(hasside(n, 1)) + return n; + switch(n->op){ + case Oeq: + case Oleq: + case Ogeq: + n->val = 1; + break; + case Osub: + n->val = 0; + n->rval = 0.0; + break; + case Oxor: + case Oneq: + case Olt: + case Ogt: + n->val = 0; + break; + case Oand: + case Oor: + case Oandand: + case Ooror: + return n->left; + default: + return n; + } + n->op = Oconst; + n->left = n->right = nil; + n->decl = nil; + return n; +} + +/* + * constant folding for typechecked expressions, + */ +Node* +fold(Node *n) +{ + if(n == nil) + return nil; + if(debug['F']) + print("fold %n\n", n); + n = efold(n); + if(debug['F']) + print("folded %n\n", n); + return n; +} + +Node* +efold(Node *n) +{ + Decl *d; + Node *left, *right; + + if(n == nil) + return nil; + + left = n->left; + right = n->right; + switch(n->op){ + case Oname: + d = n->decl; + if(d->importid != nil) + d = d->importid; + if(d->store != Dconst){ + if(d->store == Dtag){ + n->op = Oconst; + n->ty = tint; + n->val = d->tag; + } + break; + } + switch(n->ty->kind){ + case Tbig: + n->op = Oconst; + n->val = d->init->val; + break; + case Tbyte: + n->op = Oconst; + n->val = d->init->val & 0xff; + break; + case Tint: + case Tfix: + n->op = Oconst; + n->val = d->init->val; + break; + case Treal: + n->op = Oconst; + n->rval = d->init->rval; + break; + case Tstring: + n->op = Oconst; + n->decl = d->init->decl; + break; + case Ttuple: + *n = *d->init; + break; + case Tadt: + *n = *d->init; + n = rewrite(n); /* was call */ + break; + case Texception: + if(!n->ty->cons) + fatal("non-const exception type in efold"); + n->op = Oconst; + break; + default: + fatal("unknown const type %T in efold", n->ty); + break; + } + break; + case Oadd: + left = efold(left); + right = efold(right); + n->left = left; + n->right = right; + if(n->ty == tstring && right->op == Oconst){ + if(left->op == Oconst) + n = mksconst(&n->src, stringcat(left->decl->sym, right->decl->sym)); + else if(left->op == Oadd && left->ty == tstring && left->right->op == Oconst){ + left->right = mksconst(&n->src, stringcat(left->right->decl->sym, right->decl->sym)); + n = left; + } + } + break; + case Olen: + left = efold(left); + n->left = left; + if(left->ty == tstring && left->op == Oconst) + n = mkconst(&n->src, utflen(left->decl->sym->name)); + break; + case Oslice: + if(right->left->op == Onothing) + right->left = mkconst(&right->left->src, 0); + n->left = efold(left); + n->right = efold(right); + break; + case Oinds: + n->left = left = efold(left); + n->right = right = efold(right); + if(right->op == Oconst && left->op == Oconst){ + ; + } + break; + case Ocast: + n->op = Ocast; + left = efold(left); + n->left = left; + if(n->ty == left->ty || n->ty->kind == Tfix && tequal(n->ty, left->ty)) + return left; + if(left->op == Oconst) + return foldcast(n, left); + break; + case Odot: + case Omdot: + /* + * what about side effects from left? + */ + d = right->decl; + switch(d->store){ + case Dconst: + case Dtag: + case Dtype: + /* + * set it up as a name and let that case do the hard work + */ + n->op = Oname; + n->decl = d; + n->left = nil; + n->right = nil; + return efold(n); + } + n->left = efold(left); + if(n->left->op == Otuple) + n = tuplemem(n->left, d); + else + n->right = efold(right); + break; + case Otagof: + if(n->decl != nil){ + n->op = Oconst; + n->left = nil; + n->right = nil; + n->val = n->decl->tag; + return efold(n); + } + n->left = efold(left); + break; + case Oif: + n->left = left = efold(left); + n->right = right = efold(right); + if(left->op == Oconst){ + if(left->val) + return right->left; + else + return right->right; + } + break; + default: + n->left = efold(left); + n->right = efold(right); + break; + } + + left = n->left; + right = n->right; + if(left == nil) + return n; + + if(right == nil){ + if(left->op == Oconst){ + if(left->ty == tint || left->ty == tbyte || left->ty == tbig) + return foldc(n); + if(left->ty == treal) + return foldr(n); + } + return n; + } + + if(left->op == Oconst){ + switch(n->op){ + case Olsh: + case Orsh: + if(left->val == 0 && !hasside(right, 1)) + return left; + break; + case Ooror: + if(left->ty == tint || left->ty == tbyte || left->ty == tbig){ + if(left->val == 0){ + n = mkbin(Oneq, right, mkconst(&right->src, 0)); + n->ty = right->ty; + n->left->ty = right->ty; + return efold(n); + } + left->val = 1; + return left; + } + break; + case Oandand: + if(left->ty == tint || left->ty == tbyte || left->ty == tbig){ + if(left->val == 0) + return left; + n = mkbin(Oneq, right, mkconst(&right->src, 0)); + n->ty = right->ty; + n->left->ty = right->ty; + return efold(n); + } + break; + } + } + if(left->op == Oconst && right->op != Oconst + && opcommute[n->op] + && n->ty != tstring){ + n->op = opcommute[n->op]; + n->left = right; + n->right = left; + left = right; + right = n->right; + } + if(right->op == Oconst && left->op == n->op && left->right->op == Oconst + && (n->op == Oadd || n->op == Omul || n->op == Oor || n->op == Oxor || n->op == Oand) + && n->ty != tstring){ + n->left = left->left; + left->left = right; + right = efold(left); + n->right = right; + left = n->left; + } + if(right->op == Oconst){ + if(n->op == Oexp && left->ty == treal){ + if(left->op == Oconst) + return foldr(n); + return n; + } + if(right->ty == tint || right->ty == tbyte || left->ty == tbig){ + if(left->op == Oconst) + return foldc(n); + return foldvc(n); + } + if(right->ty == treal && left->op == Oconst) + return foldr(n); + } + if(sametree(left, right)) + return folds(n); + return n; +} + +/* + * does evaluating the node have any side effects? + */ +int +hasside(Node *n, int strict) +{ + for(; n != nil; n = n->right){ + if(sideeffect[n->op] && (strict || n->op != Oadr && n->op != Oind)) + return 1; + if(hasside(n->left, strict)) + return 1; + } + return 0; +} + +int +hascall(Node *n) +{ + for(; n != nil; n = n->right){ + if(n->op == Ocall || n->op == Ospawn) + return 1; + if(hascall(n->left)) + return 1; + } + return 0; +} + +int +hasasgns(Node *n) +{ + if(n == nil) + return 0; + if(n->op != Ocall && isused[n->op] && n->op != Onothing) + return 1; + return hasasgns(n->left) || hasasgns(n->right); +} + +int +nodes(Node *n) +{ + if(n == nil) + return 0; + return 1+nodes(n->left)+nodes(n->right); +} + +Node* +foldcast(Node *n, Node *left) +{ + Real r; + char *buf, *e; + + switch(left->ty->kind){ + case Tint: + left->val &= 0xffffffff; + if(left->val & 0x80000000) + left->val |= (Long)0xffffffff << 32; + return foldcasti(n, left); + case Tbyte: + left->val &= 0xff; + return foldcasti(n, left); + case Tbig: + return foldcasti(n, left); + case Treal: + switch(n->ty->kind){ + case Tint: + case Tbyte: + case Tbig: + r = left->rval; + left->val = r < 0 ? r - .5 : r + .5; + break; + case Tfix: + left->val = real2fix(left->rval, n->ty); + break; + case Tstring: + buf = allocmem(NumSize); + e = seprint(buf, buf+NumSize, "%g", left->rval); + return mksconst(&n->src, enterstring(buf, e-buf)); + default: + return n; + } + break; + case Tfix: + switch(n->ty->kind){ + case Tint: + case Tbyte: + case Tbig: + left->val = fix2real(left->val, left->ty); + break; + case Treal: + left->rval = fix2real(left->val, left->ty); + break; + case Tfix: + if(tequal(left->ty, n->ty)) + return left; + left->val = fix2fix(left->val, left->ty, n->ty); + break; + case Tstring: + buf = allocmem(NumSize); + e = seprint(buf, buf+NumSize, "%g", fix2real(left->val, left->ty)); + return mksconst(&n->src, enterstring(buf, e-buf)); + default: + return n; + } + break; + case Tstring: + switch(n->ty->kind){ + case Tint: + case Tbyte: + case Tbig: + left->val = strtoi(left->decl->sym->name, 10); + break; + case Treal: + left->rval = strtod(left->decl->sym->name, nil); + break; + case Tfix: + left->val = real2fix(strtod(left->decl->sym->name, nil), n->ty); + break; + default: + return n; + } + break; + default: + return n; + } + left->ty = n->ty; + left->src = n->src; + return left; +} + +/* + * left is some kind of int type + */ +Node* +foldcasti(Node *n, Node *left) +{ + char *buf, *e; + + switch(n->ty->kind){ + case Tint: + left->val &= 0xffffffff; + if(left->val & 0x80000000) + left->val |= (Long)0xffffffff << 32; + break; + case Tbyte: + left->val &= 0xff; + break; + case Tbig: + break; + case Treal: + left->rval = left->val; + break; + case Tfix: + left->val = real2fix(left->val, n->ty); + break; + case Tstring: + buf = allocmem(NumSize); + e = seprint(buf, buf+NumSize, "%lld", left->val); + return mksconst(&n->src, enterstring(buf, e-buf)); + default: + return n; + } + left->ty = n->ty; + left->src = n->src; + return left; +} + +/* + * right is a const int + */ +Node* +foldvc(Node *n) +{ + Node *left, *right; + + left = n->left; + right = n->right; + switch(n->op){ + case Oadd: + case Osub: + case Oor: + case Oxor: + case Olsh: + case Orsh: + case Ooror: + if(right->val == 0) + return left; + if(n->op == Ooror && !hasside(left, 1)) + return right; + break; + case Oand: + if(right->val == 0 && !hasside(left, 1)) + return right; + break; + case Omul: + if(right->val == 1) + return left; + if(right->val == 0 && !hasside(left, 1)) + return right; + break; + case Odiv: + if(right->val == 1) + return left; + break; + case Omod: + if(right->val == 1 && !hasside(left, 1)){ + right->val = 0; + return right; + } + break; + case Oexp: + if(right->val == 0){ + right->val = 1; + return right; + } + if(right->val == 1) + return left; + break; + case Oandand: + if(right->val != 0) + return left; + if(!hasside(left, 1)) + return right; + break; + case Oneq: + if(!isrelop[left->op]) + return n; + if(right->val == 0) + return left; + n->op = Onot; + n->right = nil; + break; + case Oeq: + if(!isrelop[left->op]) + return n; + if(right->val != 0) + return left; + n->op = Onot; + n->right = nil; + break; + } + return n; +} + +/* + * left and right are const ints + */ +Node* +foldc(Node *n) +{ + Node *left, *right; + Long lv, v; + int rv, nb; + + left = n->left; + right = n->right; + switch(n->op){ + case Oadd: + v = left->val + right->val; + break; + case Osub: + v = left->val - right->val; + break; + case Omul: + v = left->val * right->val; + break; + case Odiv: + if(right->val == 0){ + nerror(n, "divide by 0 in constant expression"); + return n; + } + v = left->val / right->val; + break; + case Omod: + if(right->val == 0){ + nerror(n, "mod by 0 in constant expression"); + return n; + } + v = left->val % right->val; + break; + case Oexp: + if(left->val == 0 && right->val < 0){ + nerror(n, "0 to negative power in constant expression"); + return n; + } + v = ipow(left->val, right->val); + break; + case Oand: + v = left->val & right->val; + break; + case Oor: + v = left->val | right->val; + break; + case Oxor: + v = left->val ^ right->val; + break; + case Olsh: + lv = left->val; + rv = right->val; + if(rv < 0 || rv >= n->ty->size * 8){ + nwarn(n, "shift amount %d out of range", rv); + rv = 0; + } + if(rv == 0){ + v = lv; + break; + } + v = lv << rv; + break; + case Orsh: + lv = left->val; + rv = right->val; + nb = n->ty->size * 8; + if(rv < 0 || rv >= nb){ + nwarn(n, "shift amount %d out of range", rv); + rv = 0; + } + if(rv == 0){ + v = lv; + break; + } + v = lv >> rv; + + /* + * properly sign extend c right shifts + */ + if((n->ty == tint || n->ty == tbig) + && rv != 0 + && (lv & (1<<(nb-1)))){ + lv = 0; + lv = ~lv; + v |= lv << (nb - rv); + } + break; + case Oneg: + v = -left->val; + break; + case Ocomp: + v = ~left->val; + break; + case Oeq: + v = left->val == right->val; + break; + case Oneq: + v = left->val != right->val; + break; + case Ogt: + v = left->val > right->val; + break; + case Ogeq: + v = left->val >= right->val; + break; + case Olt: + v = left->val < right->val; + break; + case Oleq: + v = left->val <= right->val; + break; + case Oandand: + v = left->val && right->val; + break; + case Ooror: + v = left->val || right->val; + break; + case Onot: + v = !left->val; + break; + default: + return n; + } + if(n->ty == tint){ + v &= 0xffffffff; + if(v & 0x80000000) + v |= (Long)0xffffffff << 32; + }else if(n->ty == tbyte) + v &= 0xff; + n->left = nil; + n->right = nil; + n->decl = nil; + n->op = Oconst; + n->val = v; + return n; +} + +/* + * left and right are const reals + */ +Node* +foldr(Node *n) +{ + Node *left, *right; + double rv; + Long v; + + rv = 0.; + v = 0; + + left = n->left; + right = n->right; + switch(n->op){ + case Ocast: + return n; + case Oadd: + rv = left->rval + right->rval; + break; + case Osub: + rv = left->rval - right->rval; + break; + case Omul: + rv = left->rval * right->rval; + break; + case Odiv: + rv = left->rval / right->rval; + break; + case Oexp: + rv = rpow(left->rval, right->val); + break; + case Oneg: + rv = -left->rval; + break; + case Oinv: + if(left->rval == 0.0){ + error(n->src.start, "divide by 0 in fixed point type"); + return n; + } + rv = 1/left->rval; + break; + case Oeq: + v = left->rval == right->rval; + break; + case Oneq: + v = left->rval != right->rval; + break; + case Ogt: + v = left->rval > right->rval; + break; + case Ogeq: + v = left->rval >= right->rval; + break; + case Olt: + v = left->rval < right->rval; + break; + case Oleq: + v = left->rval <= right->rval; + break; + default: + return n; + } + n->left = nil; + n->right = nil; + + if(isnan(rv)) + rv = canonnan; + + n->rval = rv; + n->val = v; + + n->op = Oconst; + return n; +} + +Node* +varinit(Decl *d, Node *e) +{ + Node *n; + + n = mkdeclname(&e->src, d); + if(d->next == nil) + return mkbin(Oas, n, e); + return mkbin(Oas, n, varinit(d->next, e)); +} + +/* + * given: an Oseq list with left == next or the last child + * make a list with the right == next + * ie: Oseq(Oseq(a, b),c) ==> Oseq(a, Oseq(b, Oseq(c, nil)))) + */ +Node* +rotater(Node *e) +{ + Node *left; + + if(e == nil) + return e; + if(e->op != Oseq) + return mkunary(Oseq, e); + e->right = mkunary(Oseq, e->right); + while(e->left->op == Oseq){ + left = e->left; + e->left = left->right; + left->right = e; + e = left; + } + return e; +} + +/* + * reverse the case labels list + */ +Node* +caselist(Node *s, Node *nr) +{ + Node *r; + + r = s->right; + s->right = nr; + if(r == nil) + return s; + return caselist(r, s); +} + +/* + * e is a seq of expressions; make into cons's to build a list + */ +Node* +etolist(Node *e) +{ + Node *left, *n; + + if(e == nil) + return nil; + n = mknil(&e->src); + n->src.start = n->src.stop; + if(e->op != Oseq) + return mkbin(Ocons, e, n); + e->right = mkbin(Ocons, e->right, n); + while(e->left->op == Oseq){ + e->op = Ocons; + left = e->left; + e->left = left->right; + left->right = e; + e = left; + } + e->op = Ocons; + return e; +} + +Node* +dupn(int resrc, Src *src, Node *n) +{ + Node *nn; + + nn = allocmem(sizeof *nn); + *nn = *n; + if(resrc) + nn->src = *src; + if(nn->left != nil) + nn->left = dupn(resrc, src, nn->left); + if(nn->right != nil) + nn->right = dupn(resrc, src, nn->right); + return nn; +} + +Node* +mkn(int op, Node *left, Node *right) +{ + Node *n; + + n = allocmem(sizeof *n); + *n = znode; + n->op = op; + n->left = left; + n->right = right; + return n; +} + +Node* +mkunary(int op, Node *left) +{ + Node *n; + + n = mkn(op, left, nil); + n->src = left->src; + return n; +} + +Node* +mkbin(int op, Node *left, Node *right) +{ + Node *n; + + n = mkn(op, left, right); + n->src.start = left->src.start; + n->src.stop = right->src.stop; + return n; +} + +Node* +mkdeclname(Src *src, Decl *d) +{ + Node *n; + + n = mkn(Oname, nil, nil); + n->src = *src; + n->decl = d; + n->ty = d->ty; + d->refs++; + return n; +} + +Node* +mknil(Src *src) +{ + return mkdeclname(src, nildecl); +} + +Node* +mkname(Src *src, Sym *s) +{ + Node *n; + + n = mkn(Oname, nil, nil); + n->src = *src; + if(s->unbound == nil){ + s->unbound = mkdecl(src, Dunbound, nil); + s->unbound->sym = s; + } + n->decl = s->unbound; + return n; +} + +Node* +mkconst(Src *src, Long v) +{ + Node *n; + + n = mkn(Oconst, nil, nil); + n->ty = tint; + n->val = v; + n->src = *src; + return n; +} + +Node* +mkrconst(Src *src, Real v) +{ + Node *n; + + n = mkn(Oconst, nil, nil); + n->ty = treal; + n->rval = v; + n->src = *src; + return n; +} + +Node* +mksconst(Src *src, Sym *s) +{ + Node *n; + + n = mkn(Oconst, nil, nil); + n->ty = tstring; + n->decl = mkdecl(src, Dconst, tstring); + n->decl->sym = s; + n->src = *src; + return n; +} + +int +opconv(Fmt *f) +{ + int op; + char buf[32]; + + op = va_arg(f->args, int); + if(op < 0 || op > Oend) { + seprint(buf, buf+sizeof(buf), "op %d", op); + return fmtstrcpy(f, buf); + } + return fmtstrcpy(f, opname[op]); +} + +int +etconv(Fmt *f) +{ + Node *n; + char buf[1024]; + + n = va_arg(f->args, Node*); + if(n->ty == tany || n->ty == tnone || n->ty == terror) + seprint(buf, buf+sizeof(buf), "%V", n); + else + seprint(buf, buf+sizeof(buf), "%V of type %T", n, n->ty); + return fmtstrcpy(f, buf); +} + +int +expconv(Fmt *f) +{ + Node *n; + char buf[4096], *p; + + n = va_arg(f->args, Node*); + p = buf; + *p = 0; + if(f->r == 'V') + *p++ = '\''; + p = eprint(p, buf+sizeof(buf)-1, n); + if(f->r == 'V') + *p++ = '\''; + *p = 0; + return fmtstrcpy(f, buf); +} + +char* +eprint(char *buf, char *end, Node *n) +{ + if(n == nil) + return buf; + if(n->flags & PARENS) + buf = secpy(buf, end, "("); + switch(n->op){ + case Obreak: + case Ocont: + buf = secpy(buf, end, opname[n->op]); + if(n->decl != nil){ + buf = seprint(buf, end, " %s", n->decl->sym->name); + } + break; + case Oexit: + case Owild: + buf = secpy(buf, end, opname[n->op]); + break; + case Onothing: + break; + case Oadr: + case Oused: + buf = eprint(buf, end, n->left); + break; + case Oseq: + buf = eprintlist(buf, end, n, ", "); + break; + case Oname: + if(n->decl == nil) + buf = secpy(buf, end, "<nil>"); + else + buf = seprint(buf, end, "%s", n->decl->sym->name); + break; + case Oconst: + if(n->ty->kind == Tstring){ + buf = stringpr(buf, end, n->decl->sym); + break; + } + if(n->decl != nil && n->decl->sym != nil){ + buf = seprint(buf, end, "%s", n->decl->sym->name); + break; + } + switch(n->ty->kind){ + case Tint: + case Tbyte: + buf = seprint(buf, end, "%ld", (long)n->val); + break; + case Tbig: + buf = seprint(buf, end, "%lld", n->val); + break; + case Treal: + buf = seprint(buf, end, "%g", n->rval); + break; + case Tfix: + buf = seprint(buf, end, "%ld(%g)", (long)n->val, n->ty->val->rval); + break; + default: + buf = secpy(buf, end, opname[n->op]); + break; + } + break; + case Ocast: + buf = seprint(buf, end, "%T ", n->ty); + buf = eprint(buf, end, n->left); + break; + case Otuple: + if(n->ty != nil && n->ty->kind == Tadt) + buf = seprint(buf, end, "%s", n->ty->decl->sym->name); + buf = seprint(buf, end, "("); + buf = eprintlist(buf, end, n->left, ", "); + buf = secpy(buf, end, ")"); + break; + case Ochan: + if(n->left){ + buf = secpy(buf, end, "chan ["); + buf = eprint(buf, end, n->left); + buf = secpy(buf, end, "] of "); + buf = seprint(buf, end, "%T", n->ty->tof); + }else + buf = seprint(buf, end, "chan of %T", n->ty->tof); + break; + case Oarray: + buf = secpy(buf, end, "array ["); + if(n->left != nil) + buf = eprint(buf, end, n->left); + buf = secpy(buf, end, "] of "); + if(n->right != nil){ + buf = secpy(buf, end, "{"); + buf = eprintlist(buf, end, n->right, ", "); + buf = secpy(buf, end, "}"); + }else{ + buf = seprint(buf, end, "%T", n->ty->tof); + } + break; + case Oelem: + case Olabel: + if(n->left != nil){ + buf = eprintlist(buf, end, n->left, " or "); + buf = secpy(buf, end, " =>"); + } + buf = eprint(buf, end, n->right); + break; + case Orange: + buf = eprint(buf, end, n->left); + buf = secpy(buf, end, " to "); + buf = eprint(buf, end, n->right); + break; + case Ospawn: + buf = secpy(buf, end, "spawn "); + buf = eprint(buf, end, n->left); + break; + case Oraise: + buf = secpy(buf, end, "raise "); + buf = eprint(buf, end, n->left); + break; + case Ocall: + buf = eprint(buf, end, n->left); + buf = secpy(buf, end, "("); + buf = eprintlist(buf, end, n->right, ", "); + buf = secpy(buf, end, ")"); + break; + case Oinc: + case Odec: + buf = eprint(buf, end, n->left); + buf = secpy(buf, end, opname[n->op]); + break; + case Oindex: + case Oindx: + case Oinds: + buf = eprint(buf, end, n->left); + buf = secpy(buf, end, "["); + buf = eprint(buf, end, n->right); + buf = secpy(buf, end, "]"); + break; + case Oslice: + buf = eprint(buf, end, n->left); + buf = secpy(buf, end, "["); + buf = eprint(buf, end, n->right->left); + buf = secpy(buf, end, ":"); + buf = eprint(buf, end, n->right->right); + buf = secpy(buf, end, "]"); + break; + case Oload: + buf = seprint(buf, end, "load %T ", n->ty); + buf = eprint(buf, end, n->left); + break; + case Oref: + case Olen: + case Ohd: + case Otl: + case Otagof: + buf = secpy(buf, end, opname[n->op]); + buf = secpy(buf, end, " "); + buf = eprint(buf, end, n->left); + break; + default: + if(n->right == nil){ + buf = secpy(buf, end, opname[n->op]); + buf = eprint(buf, end, n->left); + }else{ + buf = eprint(buf, end, n->left); + buf = secpy(buf, end, opname[n->op]); + buf = eprint(buf, end, n->right); + } + break; + } + if(n->flags & PARENS) + buf = secpy(buf, end, ")"); + return buf; +} + +char* +eprintlist(char *buf, char *end, Node *elist, char *sep) +{ + if(elist == nil) + return buf; + for(; elist->right != nil; elist = elist->right){ + if(elist->op == Onothing) + continue; + if(elist->left->op == Ofnptr) + return buf; + buf = eprint(buf, end, elist->left); + if(elist->right->left->op != Ofnptr) + buf = secpy(buf, end, sep); + } + buf = eprint(buf, end, elist->left); + return buf; +} + +int +nodeconv(Fmt *f) +{ + Node *n; + char buf[4096]; + + n = va_arg(f->args, Node*); + buf[0] = 0; + nprint(buf, buf+sizeof(buf), n, 0); + return fmtstrcpy(f, buf); +} + +char* +nprint(char *buf, char *end, Node *n, int indent) +{ + int i; + + if(n == nil) + return buf; + buf = seprint(buf, end, "\n"); + for(i = 0; i < indent; i++) + if(buf < end-1) + *buf++ = ' '; + switch(n->op){ + case Oname: + if(n->decl == nil) + buf = secpy(buf, end, "name <nil>"); + else + buf = seprint(buf, end, "name %s", n->decl->sym->name); + break; + case Oconst: + if(n->decl != nil && n->decl->sym != nil) + buf = seprint(buf, end, "const %s", n->decl->sym->name); + else + buf = seprint(buf, end, "%O", n->op); + if(n->ty == tint || n->ty == tbyte || n->ty == tbig) + buf = seprint(buf, end, " (%ld)", (long)n->val); + break; + default: + buf = seprint(buf, end, "%O", n->op); + break; + } + buf = seprint(buf, end, " %T %d %d", n->ty, n->addable, n->temps); + indent += 2; + buf = nprint(buf, end, n->left, indent); + buf = nprint(buf, end, n->right, indent); + return buf; +} |
