2008-06-04 15:37:38 -06:00
|
|
|
// 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.
|
|
|
|
|
|
|
|
#include "go.h"
|
|
|
|
|
2010-01-27 16:37:08 -07:00
|
|
|
static Node* walkprint(Node*, NodeList**, int);
|
2009-07-31 10:29:28 -06:00
|
|
|
static Node* conv(Node*, Type*);
|
|
|
|
static Node* mapfn(char*, Type*);
|
2009-08-03 12:58:52 -06:00
|
|
|
static Node* makenewvar(Type*, NodeList**, Node**);
|
2010-06-14 12:24:51 -06:00
|
|
|
static Node* ascompatee1(int, Node*, Node*, NodeList**);
|
|
|
|
static NodeList* ascompatee(int, NodeList*, NodeList*, NodeList**);
|
|
|
|
static NodeList* ascompatet(int, NodeList*, Type**, int, NodeList**);
|
|
|
|
static NodeList* ascompatte(int, Type**, NodeList*, int, NodeList**);
|
|
|
|
static Node* convas(Node*, NodeList**);
|
|
|
|
static void heapmoves(void);
|
|
|
|
static NodeList* paramstoheap(Type **argin, int out);
|
|
|
|
static NodeList* reorder1(NodeList*);
|
|
|
|
static NodeList* reorder3(NodeList*);
|
2010-09-11 22:53:04 -06:00
|
|
|
static Node* addstr(Node*, NodeList**);
|
2010-02-25 16:11:07 -07:00
|
|
|
|
2010-06-12 12:17:24 -06:00
|
|
|
static NodeList* walkdefstack;
|
|
|
|
|
2008-09-11 16:23:01 -06:00
|
|
|
// can this code branch reach the end
|
|
|
|
// without an undcontitional RETURN
|
|
|
|
// this is hard, so it is conservative
|
2010-06-14 12:24:51 -06:00
|
|
|
static int
|
2009-07-17 02:00:44 -06:00
|
|
|
walkret(NodeList *l)
|
2008-09-11 16:23:01 -06:00
|
|
|
{
|
2009-07-17 02:00:44 -06:00
|
|
|
Node *n;
|
2008-09-11 16:23:01 -06:00
|
|
|
|
|
|
|
loop:
|
2009-07-17 02:00:44 -06:00
|
|
|
while(l && l->next)
|
|
|
|
l = l->next;
|
|
|
|
if(l == nil)
|
|
|
|
return 1;
|
2008-09-11 16:23:01 -06:00
|
|
|
|
|
|
|
// at this point, we have the last
|
|
|
|
// statement of the function
|
2009-07-17 02:00:44 -06:00
|
|
|
n = l->n;
|
|
|
|
switch(n->op) {
|
|
|
|
case OBLOCK:
|
|
|
|
l = n->list;
|
|
|
|
goto loop;
|
2008-09-11 16:23:01 -06:00
|
|
|
|
|
|
|
case OGOTO:
|
|
|
|
case ORETURN:
|
2009-08-07 13:50:26 -06:00
|
|
|
case OPANIC:
|
2008-09-11 16:23:01 -06:00
|
|
|
return 0;
|
2009-07-14 00:38:39 -06:00
|
|
|
break;
|
2008-09-11 16:23:01 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// all other statements
|
|
|
|
// will flow to the end
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
void
|
|
|
|
walk(Node *fn)
|
|
|
|
{
|
2008-09-09 16:47:31 -06:00
|
|
|
char s[50];
|
2009-09-15 15:11:43 -06:00
|
|
|
NodeList *l;
|
|
|
|
Node *n;
|
|
|
|
int lno;
|
2008-09-09 16:47:31 -06:00
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
curfn = fn;
|
2008-09-09 16:47:31 -06:00
|
|
|
if(debug['W']) {
|
|
|
|
snprint(s, sizeof(s), "\nbefore %S", curfn->nname->sym);
|
2009-07-17 02:00:44 -06:00
|
|
|
dumplist(s, curfn->nbody);
|
2008-09-09 16:47:31 -06:00
|
|
|
}
|
2008-09-11 16:23:01 -06:00
|
|
|
if(curfn->type->outtuple)
|
|
|
|
if(walkret(curfn->nbody))
|
2008-09-11 16:44:45 -06:00
|
|
|
yyerror("function ends without a return statement");
|
2009-07-30 17:53:08 -06:00
|
|
|
typechecklist(curfn->nbody, Etop);
|
2009-09-15 15:11:43 -06:00
|
|
|
lno = lineno;
|
|
|
|
for(l=fn->dcl; l; l=l->next) {
|
|
|
|
n = l->n;
|
|
|
|
if(n->op != ONAME || n->class != PAUTO)
|
|
|
|
continue;
|
|
|
|
lineno = n->lineno;
|
|
|
|
typecheck(&n, Erv | Easgn); // only needed for unused variables
|
2009-10-12 12:03:48 -06:00
|
|
|
if(!n->used && n->sym->name[0] != '&' && !nsyntaxerrors)
|
2009-09-15 15:11:43 -06:00
|
|
|
yyerror("%S declared and not used", n->sym);
|
|
|
|
}
|
|
|
|
lineno = lno;
|
2009-08-03 12:58:52 -06:00
|
|
|
if(nerrors != 0)
|
2009-07-31 10:29:28 -06:00
|
|
|
return;
|
2009-07-17 02:00:44 -06:00
|
|
|
walkstmtlist(curfn->nbody);
|
2008-09-09 16:47:31 -06:00
|
|
|
if(debug['W']) {
|
2009-01-29 18:38:58 -07:00
|
|
|
snprint(s, sizeof(s), "after walk %S", curfn->nname->sym);
|
2009-07-17 02:00:44 -06:00
|
|
|
dumplist(s, curfn->nbody);
|
2008-09-09 16:47:31 -06:00
|
|
|
}
|
2009-01-29 18:38:58 -07:00
|
|
|
heapmoves();
|
2009-07-17 02:00:44 -06:00
|
|
|
if(debug['W'] && curfn->enter != nil) {
|
2009-01-29 18:38:58 -07:00
|
|
|
snprint(s, sizeof(s), "enter %S", curfn->nname->sym);
|
2009-07-17 02:00:44 -06:00
|
|
|
dumplist(s, curfn->enter);
|
2009-01-29 18:38:58 -07:00
|
|
|
}
|
2008-09-09 16:47:31 -06:00
|
|
|
}
|
|
|
|
|
2010-02-18 12:15:36 -07:00
|
|
|
static int nwalkdeftype;
|
|
|
|
static NodeList *methodqueue;
|
|
|
|
|
|
|
|
static void
|
|
|
|
domethod(Node *n)
|
2009-07-17 14:38:16 -06:00
|
|
|
{
|
2010-02-18 12:15:36 -07:00
|
|
|
Node *nt;
|
2010-02-25 16:11:07 -07:00
|
|
|
|
2010-02-18 19:31:13 -07:00
|
|
|
nt = n->type->nname;
|
2010-02-18 12:15:36 -07:00
|
|
|
typecheck(&nt, Etype);
|
|
|
|
if(nt->type == T) {
|
|
|
|
// type check failed; leave empty func
|
|
|
|
n->type->etype = TFUNC;
|
|
|
|
n->type->nod = N;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
*n->type = *nt->type;
|
|
|
|
n->type->nod = N;
|
|
|
|
checkwidth(n->type);
|
2009-07-17 14:38:16 -06:00
|
|
|
}
|
|
|
|
|
2010-02-02 00:58:49 -07:00
|
|
|
static void
|
|
|
|
walkdeftype(Node *n)
|
|
|
|
{
|
|
|
|
int maplineno, embedlineno, lno;
|
|
|
|
Type *t;
|
2010-02-18 12:15:36 -07:00
|
|
|
NodeList *l;
|
2010-02-25 16:11:07 -07:00
|
|
|
|
2010-02-18 12:15:36 -07:00
|
|
|
nwalkdeftype++;
|
2010-02-02 00:58:49 -07:00
|
|
|
lno = lineno;
|
|
|
|
setlineno(n);
|
|
|
|
n->type->sym = n->sym;
|
|
|
|
n->typecheck = 1;
|
|
|
|
typecheck(&n->ntype, Etype);
|
|
|
|
if((t = n->ntype->type) == T) {
|
|
|
|
n->diag = 1;
|
|
|
|
goto ret;
|
|
|
|
}
|
2010-07-21 00:45:33 -06:00
|
|
|
if(n->type == T) {
|
|
|
|
n->diag = 1;
|
|
|
|
goto ret;
|
|
|
|
}
|
2010-02-02 00:58:49 -07:00
|
|
|
|
|
|
|
// copy new type and clear fields
|
|
|
|
// that don't come along
|
|
|
|
maplineno = n->type->maplineno;
|
|
|
|
embedlineno = n->type->embedlineno;
|
|
|
|
*n->type = *t;
|
|
|
|
t = n->type;
|
|
|
|
t->sym = n->sym;
|
|
|
|
t->local = n->local;
|
|
|
|
t->vargen = n->vargen;
|
|
|
|
t->siggen = 0;
|
|
|
|
t->method = nil;
|
|
|
|
t->nod = N;
|
|
|
|
t->printed = 0;
|
|
|
|
t->deferwidth = 0;
|
|
|
|
|
2010-06-08 19:50:02 -06:00
|
|
|
// double-check use of type as map key.
|
2010-02-02 00:58:49 -07:00
|
|
|
if(maplineno) {
|
|
|
|
lineno = maplineno;
|
|
|
|
maptype(n->type, types[TBOOL]);
|
|
|
|
}
|
|
|
|
if(embedlineno) {
|
|
|
|
lineno = embedlineno;
|
|
|
|
if(isptr[t->etype])
|
|
|
|
yyerror("embedded type cannot be a pointer");
|
|
|
|
}
|
|
|
|
|
|
|
|
ret:
|
|
|
|
lineno = lno;
|
2010-02-25 16:11:07 -07:00
|
|
|
|
2010-02-18 12:15:36 -07:00
|
|
|
// if there are no type definitions going on, it's safe to
|
|
|
|
// try to resolve the method types for the interfaces
|
|
|
|
// we just read.
|
|
|
|
if(nwalkdeftype == 1) {
|
|
|
|
while((l = methodqueue) != nil) {
|
|
|
|
methodqueue = nil;
|
|
|
|
for(; l; l=l->next)
|
|
|
|
domethod(l->n);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nwalkdeftype--;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
queuemethod(Node *n)
|
|
|
|
{
|
|
|
|
if(nwalkdeftype == 0) {
|
|
|
|
domethod(n);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
methodqueue = list(methodqueue, n);
|
2010-02-02 00:58:49 -07:00
|
|
|
}
|
|
|
|
|
2010-06-12 12:17:24 -06:00
|
|
|
Node*
|
2009-07-17 14:38:16 -06:00
|
|
|
walkdef(Node *n)
|
|
|
|
{
|
2010-02-02 00:58:49 -07:00
|
|
|
int lno;
|
2009-07-17 14:38:16 -06:00
|
|
|
NodeList *init;
|
|
|
|
Node *e;
|
|
|
|
Type *t;
|
2010-06-12 12:17:24 -06:00
|
|
|
NodeList *l;
|
2009-07-17 14:38:16 -06:00
|
|
|
|
|
|
|
lno = lineno;
|
|
|
|
setlineno(n);
|
|
|
|
|
|
|
|
if(n->op == ONONAME) {
|
|
|
|
if(!n->diag) {
|
|
|
|
n->diag = 1;
|
2010-05-20 23:57:08 -06:00
|
|
|
if(n->lineno != 0)
|
|
|
|
lineno = n->lineno;
|
|
|
|
yyerror("undefined: %S", n->sym);
|
2009-07-17 14:38:16 -06:00
|
|
|
}
|
2010-06-12 12:17:24 -06:00
|
|
|
return n;
|
2009-07-17 14:38:16 -06:00
|
|
|
}
|
|
|
|
|
2009-07-29 13:00:34 -06:00
|
|
|
if(n->walkdef == 1)
|
2010-06-12 12:17:24 -06:00
|
|
|
return n;
|
|
|
|
|
|
|
|
l = mal(sizeof *l);
|
|
|
|
l->n = n;
|
|
|
|
l->next = walkdefstack;
|
|
|
|
walkdefstack = l;
|
|
|
|
|
2009-07-29 13:00:34 -06:00
|
|
|
if(n->walkdef == 2) {
|
2010-06-12 12:17:24 -06:00
|
|
|
flusherrors();
|
|
|
|
print("walkdef loop:");
|
|
|
|
for(l=walkdefstack; l; l=l->next)
|
|
|
|
print(" %S", l->n->sym);
|
|
|
|
print("\n");
|
|
|
|
fatal("walkdef loop");
|
2009-07-17 14:38:16 -06:00
|
|
|
}
|
2009-07-29 13:00:34 -06:00
|
|
|
n->walkdef = 2;
|
2009-07-17 14:38:16 -06:00
|
|
|
|
2009-07-29 13:47:51 -06:00
|
|
|
if(n->type != T || n->sym == S) // builtin or no name
|
|
|
|
goto ret;
|
|
|
|
|
2009-07-17 14:38:16 -06:00
|
|
|
init = nil;
|
|
|
|
switch(n->op) {
|
2009-08-07 13:50:26 -06:00
|
|
|
default:
|
|
|
|
fatal("walkdef %O", n->op);
|
|
|
|
|
2009-07-17 14:38:16 -06:00
|
|
|
case OLITERAL:
|
|
|
|
if(n->ntype != N) {
|
2009-07-30 17:53:08 -06:00
|
|
|
typecheck(&n->ntype, Etype);
|
2009-07-17 14:38:16 -06:00
|
|
|
n->type = n->ntype->type;
|
|
|
|
n->ntype = N;
|
|
|
|
if(n->type == T) {
|
|
|
|
n->diag = 1;
|
|
|
|
goto ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
e = n->defn;
|
2009-07-29 13:00:34 -06:00
|
|
|
n->defn = N;
|
2009-07-29 13:47:51 -06:00
|
|
|
if(e == N) {
|
|
|
|
lineno = n->lineno;
|
|
|
|
dump("walkdef nil defn", n);
|
|
|
|
yyerror("xxx");
|
|
|
|
}
|
2009-08-11 18:05:22 -06:00
|
|
|
typecheck(&e, Erv | Eiota);
|
2009-09-09 02:01:39 -06:00
|
|
|
if(e->type != T && e->op != OLITERAL) {
|
2009-07-17 14:38:16 -06:00
|
|
|
yyerror("const initializer must be constant");
|
|
|
|
goto ret;
|
|
|
|
}
|
2010-09-11 13:47:56 -06:00
|
|
|
if(isconst(e, CTNIL)) {
|
|
|
|
yyerror("const initializer cannot be nil");
|
|
|
|
goto ret;
|
|
|
|
}
|
2009-07-17 14:38:16 -06:00
|
|
|
t = n->type;
|
2010-01-08 01:01:03 -07:00
|
|
|
if(t != T) {
|
2009-07-17 14:38:16 -06:00
|
|
|
convlit(&e, t);
|
2010-02-02 00:05:15 -07:00
|
|
|
if(!okforconst[t->etype])
|
2010-01-08 01:01:03 -07:00
|
|
|
yyerror("invalid constant type %T", t);
|
|
|
|
}
|
2009-07-17 14:38:16 -06:00
|
|
|
n->val = e->val;
|
|
|
|
n->type = e->type;
|
|
|
|
break;
|
2009-08-04 17:53:06 -06:00
|
|
|
|
|
|
|
case ONAME:
|
|
|
|
if(n->ntype != N) {
|
|
|
|
typecheck(&n->ntype, Etype);
|
|
|
|
n->type = n->ntype->type;
|
|
|
|
if(n->type == T) {
|
|
|
|
n->diag = 1;
|
|
|
|
goto ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(n->type != T)
|
|
|
|
break;
|
2010-06-12 12:17:24 -06:00
|
|
|
if(n->defn == N) {
|
|
|
|
if(n->etype != 0) // like OPRINTN
|
|
|
|
break;
|
2010-07-15 16:22:51 -06:00
|
|
|
if(nerrors > 0) {
|
|
|
|
// Can have undefined variables in x := foo
|
|
|
|
// that make x have an n->ndefn == nil.
|
|
|
|
// If there are other errors anyway, don't
|
|
|
|
// bother adding to the noise.
|
|
|
|
break;
|
|
|
|
}
|
2009-08-04 17:53:06 -06:00
|
|
|
fatal("var without type, init: %S", n->sym);
|
2010-06-12 12:17:24 -06:00
|
|
|
}
|
2009-08-07 13:50:26 -06:00
|
|
|
if(n->defn->op == ONAME) {
|
|
|
|
typecheck(&n->defn, Erv);
|
|
|
|
n->type = n->defn->type;
|
|
|
|
break;
|
|
|
|
}
|
2009-08-05 01:42:44 -06:00
|
|
|
typecheck(&n->defn, Etop); // fills in n->type
|
2009-08-04 17:53:06 -06:00
|
|
|
break;
|
2009-08-07 13:50:26 -06:00
|
|
|
|
|
|
|
case OTYPE:
|
2010-07-15 15:25:50 -06:00
|
|
|
if(curfn)
|
|
|
|
defercheckwidth();
|
2009-08-07 13:50:26 -06:00
|
|
|
n->walkdef = 1;
|
2009-08-12 15:41:13 -06:00
|
|
|
n->type = typ(TFORW);
|
2009-08-07 13:50:26 -06:00
|
|
|
n->type->sym = n->sym;
|
2010-02-16 18:44:15 -07:00
|
|
|
walkdeftype(n);
|
2010-07-15 15:25:50 -06:00
|
|
|
if(curfn)
|
|
|
|
resumecheckwidth();
|
2009-08-07 13:50:26 -06:00
|
|
|
break;
|
2009-08-12 16:58:31 -06:00
|
|
|
|
|
|
|
case OPACK:
|
|
|
|
// nothing to see here
|
|
|
|
break;
|
2009-07-17 14:38:16 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
ret:
|
2010-06-12 12:17:24 -06:00
|
|
|
if(walkdefstack->n != n)
|
|
|
|
fatal("walkdefstack mismatch");
|
|
|
|
l = walkdefstack;
|
|
|
|
walkdefstack = l->next;
|
|
|
|
|
2009-07-17 14:38:16 -06:00
|
|
|
lineno = lno;
|
2009-07-29 13:00:34 -06:00
|
|
|
n->walkdef = 1;
|
2010-06-12 12:17:24 -06:00
|
|
|
return n;
|
2009-07-17 14:38:16 -06:00
|
|
|
}
|
|
|
|
|
2009-07-17 02:00:44 -06:00
|
|
|
void
|
|
|
|
walkstmtlist(NodeList *l)
|
|
|
|
{
|
|
|
|
for(; l; l=l->next)
|
2009-07-29 13:00:34 -06:00
|
|
|
walkstmt(&l->n);
|
2009-07-17 02:00:44 -06:00
|
|
|
}
|
|
|
|
|
2009-08-07 15:38:31 -06:00
|
|
|
static int
|
|
|
|
samelist(NodeList *a, NodeList *b)
|
|
|
|
{
|
|
|
|
for(; a && b; a=a->next, b=b->next)
|
|
|
|
if(a->n != b->n)
|
|
|
|
return 0;
|
|
|
|
return a == b;
|
|
|
|
}
|
|
|
|
|
2010-03-29 16:27:59 -06:00
|
|
|
static int
|
|
|
|
paramoutheap(Node *fn)
|
|
|
|
{
|
|
|
|
NodeList *l;
|
|
|
|
|
|
|
|
for(l=fn->dcl; l; l=l->next) {
|
|
|
|
switch(l->n->class) {
|
|
|
|
case PPARAMOUT|PHEAP:
|
|
|
|
return 1;
|
|
|
|
case PAUTO:
|
|
|
|
case PAUTO|PHEAP:
|
|
|
|
// stop early - parameters are over
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2009-08-07 15:38:31 -06:00
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
void
|
2009-07-29 13:00:34 -06:00
|
|
|
walkstmt(Node **np)
|
2008-09-04 13:21:10 -06:00
|
|
|
{
|
2009-07-17 02:00:44 -06:00
|
|
|
NodeList *init;
|
2009-08-07 15:38:31 -06:00
|
|
|
NodeList *ll, *rl;
|
|
|
|
int cl, lno;
|
2010-07-15 17:14:06 -06:00
|
|
|
Node *n, *f;
|
2009-07-29 13:47:51 -06:00
|
|
|
|
2009-07-29 13:00:34 -06:00
|
|
|
n = *np;
|
2008-09-04 13:21:10 -06:00
|
|
|
if(n == N)
|
|
|
|
return;
|
|
|
|
|
2009-07-10 17:29:26 -06:00
|
|
|
lno = lineno;
|
2009-06-25 17:32:33 -06:00
|
|
|
setlineno(n);
|
2009-06-06 13:46:38 -06:00
|
|
|
|
2008-09-04 13:21:10 -06:00
|
|
|
switch(n->op) {
|
|
|
|
default:
|
2009-05-20 15:24:23 -06:00
|
|
|
if(n->op == ONAME)
|
2009-07-17 02:00:44 -06:00
|
|
|
yyerror("%S is not a top level statement", n->sym);
|
2009-05-20 15:24:23 -06:00
|
|
|
else
|
2009-07-17 02:00:44 -06:00
|
|
|
yyerror("%O is not a top level statement", n->op);
|
2009-07-17 14:38:16 -06:00
|
|
|
dump("nottop", n);
|
2009-07-06 23:25:54 -06:00
|
|
|
break;
|
2008-09-04 13:21:10 -06:00
|
|
|
|
|
|
|
case OASOP:
|
|
|
|
case OAS:
|
2009-07-17 02:00:44 -06:00
|
|
|
case OAS2:
|
2009-08-04 11:26:29 -06:00
|
|
|
case OAS2DOTTYPE:
|
|
|
|
case OAS2RECV:
|
|
|
|
case OAS2FUNC:
|
|
|
|
case OAS2MAPW:
|
|
|
|
case OAS2MAPR:
|
2009-03-12 18:55:11 -06:00
|
|
|
case OCLOSE:
|
|
|
|
case OCLOSED:
|
2009-11-17 21:41:44 -07:00
|
|
|
case OCOPY:
|
2008-09-04 13:21:10 -06:00
|
|
|
case OCALLMETH:
|
|
|
|
case OCALLINTER:
|
|
|
|
case OCALL:
|
2009-07-30 17:53:08 -06:00
|
|
|
case OCALLFUNC:
|
2008-09-04 13:21:10 -06:00
|
|
|
case OSEND:
|
|
|
|
case ORECV:
|
|
|
|
case OPRINT:
|
2008-10-02 15:38:07 -06:00
|
|
|
case OPRINTN:
|
2008-09-04 13:21:10 -06:00
|
|
|
case OPANIC:
|
|
|
|
case OEMPTY:
|
2010-03-31 12:46:01 -06:00
|
|
|
case ORECOVER:
|
2009-08-04 11:26:29 -06:00
|
|
|
if(n->typecheck == 0)
|
|
|
|
fatal("missing typecheck");
|
2009-07-29 13:00:34 -06:00
|
|
|
init = n->ninit;
|
|
|
|
n->ninit = nil;
|
2009-07-31 10:29:28 -06:00
|
|
|
walkexpr(&n, &init);
|
2009-07-29 13:00:34 -06:00
|
|
|
n->ninit = concat(init, n->ninit);
|
2009-07-10 17:29:26 -06:00
|
|
|
break;
|
|
|
|
|
2008-09-04 13:21:10 -06:00
|
|
|
case OBREAK:
|
2009-07-10 17:29:26 -06:00
|
|
|
case ODCL:
|
2008-09-04 13:21:10 -06:00
|
|
|
case OCONTINUE:
|
2009-07-10 17:29:26 -06:00
|
|
|
case OFALL:
|
2008-09-04 13:21:10 -06:00
|
|
|
case OGOTO:
|
|
|
|
case OLABEL:
|
2009-08-07 13:50:26 -06:00
|
|
|
case ODCLCONST:
|
|
|
|
case ODCLTYPE:
|
2009-07-10 17:29:26 -06:00
|
|
|
break;
|
|
|
|
|
2009-07-17 02:00:44 -06:00
|
|
|
case OBLOCK:
|
|
|
|
walkstmtlist(n->list);
|
|
|
|
break;
|
|
|
|
|
2008-09-04 13:21:10 -06:00
|
|
|
case OXCASE:
|
2009-07-10 17:29:26 -06:00
|
|
|
yyerror("case statement out of place");
|
|
|
|
n->op = OCASE;
|
2008-09-04 13:21:10 -06:00
|
|
|
case OCASE:
|
2009-07-29 13:00:34 -06:00
|
|
|
walkstmt(&n->right);
|
2009-07-10 17:29:26 -06:00
|
|
|
break;
|
|
|
|
|
2009-01-27 13:03:53 -07:00
|
|
|
case ODEFER:
|
2009-07-10 17:29:26 -06:00
|
|
|
hasdefer = 1;
|
2010-01-27 16:37:08 -07:00
|
|
|
switch(n->left->op) {
|
|
|
|
case OPRINT:
|
|
|
|
case OPRINTN:
|
|
|
|
walkexprlist(n->left->list, &n->ninit);
|
|
|
|
n->left = walkprint(n->left, &n->ninit, 1);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
walkexpr(&n->left, &n->ninit);
|
|
|
|
break;
|
|
|
|
}
|
2008-09-04 13:21:10 -06:00
|
|
|
break;
|
|
|
|
|
2009-07-10 17:29:26 -06:00
|
|
|
case OFOR:
|
2009-07-17 02:00:44 -06:00
|
|
|
walkstmtlist(n->ninit);
|
2009-08-05 03:33:30 -06:00
|
|
|
if(n->ntest != N) {
|
|
|
|
walkstmtlist(n->ntest->ninit);
|
2010-06-08 19:50:02 -06:00
|
|
|
init = n->ntest->ninit;
|
|
|
|
n->ntest->ninit = nil;
|
|
|
|
walkexpr(&n->ntest, &init);
|
|
|
|
n->ntest->ninit = concat(init, n->ntest->ninit);
|
2009-08-05 03:33:30 -06:00
|
|
|
}
|
2009-07-29 13:00:34 -06:00
|
|
|
walkstmt(&n->nincr);
|
2009-07-17 02:00:44 -06:00
|
|
|
walkstmtlist(n->nbody);
|
2009-07-10 17:29:26 -06:00
|
|
|
break;
|
2008-09-04 13:21:10 -06:00
|
|
|
|
2009-07-10 17:29:26 -06:00
|
|
|
case OIF:
|
2009-07-17 02:00:44 -06:00
|
|
|
walkstmtlist(n->ninit);
|
2009-10-07 23:19:42 -06:00
|
|
|
walkexpr(&n->ntest, &n->ninit);
|
2009-07-17 02:00:44 -06:00
|
|
|
walkstmtlist(n->nbody);
|
|
|
|
walkstmtlist(n->nelse);
|
2009-07-10 17:29:26 -06:00
|
|
|
break;
|
|
|
|
|
|
|
|
case OPROC:
|
2009-07-31 10:29:28 -06:00
|
|
|
walkexpr(&n->left, &n->ninit);
|
2009-07-10 17:29:26 -06:00
|
|
|
break;
|
|
|
|
|
|
|
|
case ORETURN:
|
2009-07-31 10:29:28 -06:00
|
|
|
walkexprlist(n->list, &n->ninit);
|
2010-03-29 16:27:59 -06:00
|
|
|
if(n->list == nil)
|
|
|
|
break;
|
|
|
|
if((curfn->type->outnamed && count(n->list) > 1) || paramoutheap(curfn)) {
|
2009-08-07 15:38:31 -06:00
|
|
|
// assign to the function out parameters,
|
|
|
|
// so that reorder3 can fix up conflicts
|
|
|
|
rl = nil;
|
|
|
|
for(ll=curfn->dcl; ll != nil; ll=ll->next) {
|
|
|
|
cl = ll->n->class & ~PHEAP;
|
|
|
|
if(cl == PAUTO)
|
|
|
|
break;
|
|
|
|
if(cl == PPARAMOUT)
|
|
|
|
rl = list(rl, ll->n);
|
|
|
|
}
|
|
|
|
if(samelist(rl, n->list)) {
|
|
|
|
// special return in disguise
|
|
|
|
n->list = nil;
|
|
|
|
break;
|
|
|
|
}
|
2010-07-15 17:14:06 -06:00
|
|
|
if(count(n->list) == 1 && count(rl) > 1) {
|
|
|
|
// OAS2FUNC in disguise
|
|
|
|
f = n->list->n;
|
|
|
|
if(f->op != OCALLFUNC && f->op != OCALLMETH && f->op != OCALLINTER)
|
|
|
|
fatal("expected return of call, have %#N", f);
|
|
|
|
n->list = concat(list1(f), ascompatet(n->op, rl, &f->type, 0, &n->ninit));
|
|
|
|
break;
|
|
|
|
}
|
2009-08-07 15:38:31 -06:00
|
|
|
ll = ascompatee(n->op, rl, n->list, &n->ninit);
|
|
|
|
n->list = reorder3(ll);
|
2009-07-10 17:29:26 -06:00
|
|
|
break;
|
|
|
|
}
|
2009-07-17 02:00:44 -06:00
|
|
|
ll = ascompatte(n->op, getoutarg(curfn->type), n->list, 1, &n->ninit);
|
2010-06-08 19:50:02 -06:00
|
|
|
n->list = ll;
|
2009-07-10 17:29:26 -06:00
|
|
|
break;
|
|
|
|
|
|
|
|
case OSELECT:
|
|
|
|
walkselect(n);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OSWITCH:
|
|
|
|
walkswitch(n);
|
|
|
|
break;
|
|
|
|
|
2009-08-05 03:33:30 -06:00
|
|
|
case ORANGE:
|
|
|
|
walkrange(n);
|
|
|
|
break;
|
|
|
|
|
2009-07-10 17:29:26 -06:00
|
|
|
case OXFALL:
|
|
|
|
yyerror("fallthrough statement out of place");
|
|
|
|
n->op = OFALL;
|
|
|
|
break;
|
2008-09-04 13:21:10 -06:00
|
|
|
}
|
2009-07-29 13:47:51 -06:00
|
|
|
|
2009-07-29 13:00:34 -06:00
|
|
|
*np = n;
|
2008-09-04 18:15:15 -06:00
|
|
|
}
|
|
|
|
|
2009-07-29 13:47:51 -06:00
|
|
|
|
|
|
|
/*
|
|
|
|
* walk the whole tree of the body of an
|
|
|
|
* expression or simple statement.
|
|
|
|
* the types expressions are calculated.
|
|
|
|
* compile-time constants are evaluated.
|
|
|
|
* complex side effects like statements are appended to init
|
|
|
|
*/
|
|
|
|
|
|
|
|
void
|
2009-07-31 10:29:28 -06:00
|
|
|
walkexprlist(NodeList *l, NodeList **init)
|
2009-07-29 13:47:51 -06:00
|
|
|
{
|
|
|
|
for(; l; l=l->next)
|
2009-07-31 10:29:28 -06:00
|
|
|
walkexpr(&l->n, init);
|
2009-07-29 13:47:51 -06:00
|
|
|
}
|
|
|
|
|
2010-02-01 23:18:51 -07:00
|
|
|
void
|
|
|
|
walkexprlistsafe(NodeList *l, NodeList **init)
|
|
|
|
{
|
|
|
|
for(; l; l=l->next) {
|
|
|
|
l->n = safeexpr(l->n, init);
|
|
|
|
walkexpr(&l->n, init);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-29 13:47:51 -06:00
|
|
|
void
|
2009-07-31 10:29:28 -06:00
|
|
|
walkexpr(Node **np, NodeList **init)
|
2009-07-29 13:47:51 -06:00
|
|
|
{
|
2010-03-22 19:51:14 -06:00
|
|
|
Node *r, *l, *var, *a;
|
|
|
|
NodeList *ll, *lr, *lpost;
|
2009-07-29 13:47:51 -06:00
|
|
|
Type *t;
|
2009-08-04 11:26:29 -06:00
|
|
|
int et;
|
2010-08-03 01:26:02 -06:00
|
|
|
int64 v, v1, v2, len;
|
2009-07-29 13:47:51 -06:00
|
|
|
int32 lno;
|
2009-08-03 12:58:52 -06:00
|
|
|
Node *n, *fn;
|
2010-06-08 19:50:02 -06:00
|
|
|
char buf[100], *p;
|
2009-07-29 13:47:51 -06:00
|
|
|
|
|
|
|
n = *np;
|
|
|
|
|
|
|
|
if(n == N)
|
|
|
|
return;
|
|
|
|
|
2009-10-07 23:19:42 -06:00
|
|
|
if(init == &n->ninit) {
|
|
|
|
// not okay to use n->ninit when walking n,
|
|
|
|
// because we might replace n with some other node
|
|
|
|
// and would lose the init list.
|
|
|
|
fatal("walkexpr init == &n->ninit");
|
|
|
|
}
|
|
|
|
|
2009-08-03 12:58:52 -06:00
|
|
|
// annoying case - not typechecked
|
|
|
|
if(n->op == OKEY) {
|
|
|
|
walkexpr(&n->left, init);
|
|
|
|
walkexpr(&n->right, init);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-07-29 13:47:51 -06:00
|
|
|
lno = setlineno(n);
|
|
|
|
|
2009-07-31 10:29:28 -06:00
|
|
|
if(debug['w'] > 1)
|
2009-07-29 13:47:51 -06:00
|
|
|
dump("walk-before", n);
|
|
|
|
|
2009-07-30 17:53:08 -06:00
|
|
|
if(n->typecheck != 1) {
|
|
|
|
dump("missed typecheck", n);
|
|
|
|
fatal("missed typecheck");
|
|
|
|
}
|
2009-07-29 13:47:51 -06:00
|
|
|
|
|
|
|
t = T;
|
|
|
|
et = Txxx;
|
|
|
|
|
|
|
|
switch(n->op) {
|
|
|
|
default:
|
|
|
|
dump("walk", n);
|
|
|
|
fatal("walkexpr: switch 1 unknown op %N", n);
|
|
|
|
goto ret;
|
|
|
|
|
|
|
|
case OTYPE:
|
2009-07-30 19:56:44 -06:00
|
|
|
case ONONAME:
|
|
|
|
case OINDREG:
|
|
|
|
case OEMPTY:
|
2009-07-17 14:38:16 -06:00
|
|
|
goto ret;
|
|
|
|
|
2009-07-30 19:56:44 -06:00
|
|
|
case ONOT:
|
|
|
|
case OMINUS:
|
|
|
|
case OPLUS:
|
|
|
|
case OCOM:
|
2010-03-05 21:16:04 -07:00
|
|
|
case OREAL:
|
|
|
|
case OIMAG:
|
2009-07-30 19:56:44 -06:00
|
|
|
case ODOT:
|
|
|
|
case ODOTPTR:
|
|
|
|
case ODOTMETH:
|
|
|
|
case ODOTINTER:
|
|
|
|
case OIND:
|
2009-07-31 10:29:28 -06:00
|
|
|
walkexpr(&n->left, init);
|
2009-07-29 13:00:34 -06:00
|
|
|
goto ret;
|
2008-09-02 17:21:30 -06:00
|
|
|
|
2010-07-01 19:04:25 -06:00
|
|
|
case OLEN:
|
|
|
|
case OCAP:
|
|
|
|
walkexpr(&n->left, init);
|
|
|
|
|
|
|
|
// replace len(*[10]int) with 10.
|
|
|
|
// delayed until now to preserve side effects.
|
|
|
|
t = n->left->type;
|
|
|
|
if(isptr[t->etype])
|
|
|
|
t = t->type;
|
|
|
|
if(isfixedarray(t)) {
|
|
|
|
safeexpr(n->left, init);
|
|
|
|
nodconst(n, n->type, t->bound);
|
|
|
|
n->typecheck = 1;
|
|
|
|
}
|
|
|
|
goto ret;
|
|
|
|
|
2009-07-31 10:29:28 -06:00
|
|
|
case OLSH:
|
|
|
|
case ORSH:
|
|
|
|
case OAND:
|
|
|
|
case OOR:
|
|
|
|
case OXOR:
|
|
|
|
case OSUB:
|
|
|
|
case OMUL:
|
2009-08-03 12:58:52 -06:00
|
|
|
case OEQ:
|
|
|
|
case ONE:
|
|
|
|
case OLT:
|
|
|
|
case OLE:
|
|
|
|
case OGE:
|
|
|
|
case OGT:
|
|
|
|
case OADD:
|
2010-03-05 21:16:04 -07:00
|
|
|
case OCMPLX:
|
2009-07-31 10:29:28 -06:00
|
|
|
walkexpr(&n->left, init);
|
|
|
|
walkexpr(&n->right, init);
|
2008-10-02 15:38:07 -06:00
|
|
|
goto ret;
|
2010-10-06 07:53:12 -06:00
|
|
|
|
|
|
|
case OANDAND:
|
|
|
|
case OOROR:
|
|
|
|
walkexpr(&n->left, init);
|
|
|
|
// cannot put side effects from n->right on init,
|
|
|
|
// because they cannot run before n->left is checked.
|
|
|
|
// save elsewhere and store on the eventual n->right.
|
|
|
|
ll = nil;
|
|
|
|
walkexpr(&n->right, &ll);
|
|
|
|
n->right->ninit = concat(n->right->ninit, ll);
|
|
|
|
goto ret;
|
2008-10-02 15:38:07 -06:00
|
|
|
|
2009-07-31 10:29:28 -06:00
|
|
|
case OPRINT:
|
2008-10-02 15:38:07 -06:00
|
|
|
case OPRINTN:
|
2009-07-31 10:29:28 -06:00
|
|
|
walkexprlist(n->list, init);
|
2010-01-27 16:37:08 -07:00
|
|
|
n = walkprint(n, init, 0);
|
2008-06-04 15:37:38 -06:00
|
|
|
goto ret;
|
|
|
|
|
2010-03-30 11:53:16 -06:00
|
|
|
case OPANIC:
|
|
|
|
n = mkcall("panic", T, init, n->left);
|
|
|
|
goto ret;
|
|
|
|
|
|
|
|
case ORECOVER:
|
2010-03-31 12:46:01 -06:00
|
|
|
n = mkcall("recover", n->type, init, nod(OADDR, nodfp, N));
|
2010-03-30 11:53:16 -06:00
|
|
|
goto ret;
|
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
case OLITERAL:
|
|
|
|
n->addable = 1;
|
|
|
|
goto ret;
|
|
|
|
|
|
|
|
case ONAME:
|
2009-02-06 14:47:10 -07:00
|
|
|
if(!(n->class & PHEAP) && n->class != PPARAMREF)
|
2009-01-29 18:38:58 -07:00
|
|
|
n->addable = 1;
|
2008-06-04 15:37:38 -06:00
|
|
|
goto ret;
|
|
|
|
|
2009-08-03 12:58:52 -06:00
|
|
|
case OCALLINTER:
|
|
|
|
t = n->left->type;
|
|
|
|
if(n->list && n->list->n->op == OAS)
|
2008-06-04 15:37:38 -06:00
|
|
|
goto ret;
|
2009-07-31 10:29:28 -06:00
|
|
|
walkexpr(&n->left, init);
|
2009-08-03 12:58:52 -06:00
|
|
|
walkexprlist(n->list, init);
|
|
|
|
ll = ascompatte(n->op, getinarg(t), n->list, 0, init);
|
|
|
|
n->list = reorder1(ll);
|
|
|
|
goto ret;
|
2009-02-16 18:44:05 -07:00
|
|
|
|
2009-08-03 12:58:52 -06:00
|
|
|
case OCALLFUNC:
|
2008-06-04 15:37:38 -06:00
|
|
|
t = n->left->type;
|
2009-08-03 12:58:52 -06:00
|
|
|
if(n->list && n->list->n->op == OAS)
|
2008-06-04 15:37:38 -06:00
|
|
|
goto ret;
|
2009-08-03 12:58:52 -06:00
|
|
|
walkexpr(&n->left, init);
|
|
|
|
walkexprlist(n->list, init);
|
|
|
|
ll = ascompatte(n->op, getinarg(t), n->list, 0, init);
|
|
|
|
n->list = reorder1(ll);
|
|
|
|
if(isselect(n)) {
|
|
|
|
// special prob with selectsend and selectrecv:
|
|
|
|
// if chan is nil, they don't know big the channel
|
|
|
|
// element is and therefore don't know how to find
|
|
|
|
// the output bool, so we clear it before the call.
|
|
|
|
Node *b;
|
|
|
|
b = nodbool(0);
|
2010-06-08 19:50:02 -06:00
|
|
|
typecheck(&b, Erv);
|
2009-08-03 12:58:52 -06:00
|
|
|
lr = ascompatte(n->op, getoutarg(t), list1(b), 0, init);
|
|
|
|
n->list = concat(n->list, lr);
|
2009-07-14 00:38:39 -06:00
|
|
|
}
|
2009-08-03 12:58:52 -06:00
|
|
|
goto ret;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-08-03 12:58:52 -06:00
|
|
|
case OCALLMETH:
|
|
|
|
t = n->left->type;
|
|
|
|
if(n->list && n->list->n->op == OAS)
|
2008-06-04 15:37:38 -06:00
|
|
|
goto ret;
|
2009-08-03 12:58:52 -06:00
|
|
|
walkexpr(&n->left, init);
|
2009-07-31 10:29:28 -06:00
|
|
|
walkexprlist(n->list, init);
|
2010-07-15 17:42:32 -06:00
|
|
|
ll = ascompatte(n->op, getthis(t), list1(n->left->left), 0, init);
|
|
|
|
lr = ascompatte(n->op, getinarg(t), n->list, 0, init);
|
2009-08-03 12:58:52 -06:00
|
|
|
ll = concat(ll, lr);
|
|
|
|
n->left->left = N;
|
|
|
|
ullmancalc(n->left);
|
|
|
|
n->list = reorder1(ll);
|
2008-06-04 15:37:38 -06:00
|
|
|
goto ret;
|
|
|
|
|
|
|
|
case OAS:
|
2009-07-17 02:00:44 -06:00
|
|
|
*init = concat(*init, n->ninit);
|
|
|
|
n->ninit = nil;
|
2009-07-31 10:29:28 -06:00
|
|
|
walkexpr(&n->left, init);
|
2010-02-01 23:18:51 -07:00
|
|
|
n->left = safeexpr(n->left, init);
|
2009-09-08 16:52:27 -06:00
|
|
|
if(oaslit(n, init))
|
|
|
|
goto ret;
|
2009-07-31 10:29:28 -06:00
|
|
|
walkexpr(&n->right, init);
|
2008-06-04 15:37:38 -06:00
|
|
|
l = n->left;
|
2008-06-15 21:24:30 -06:00
|
|
|
r = n->right;
|
2008-06-22 22:02:06 -06:00
|
|
|
if(l == N || r == N)
|
2008-06-15 21:24:30 -06:00
|
|
|
goto ret;
|
2009-07-29 13:00:34 -06:00
|
|
|
r = ascompatee1(n->op, l, r, init);
|
2010-05-03 23:51:30 -06:00
|
|
|
if(r != N) {
|
|
|
|
r->dodata = n->dodata;
|
2009-07-29 13:00:34 -06:00
|
|
|
n = r;
|
2010-05-03 23:51:30 -06:00
|
|
|
}
|
2009-07-17 02:00:44 -06:00
|
|
|
goto ret;
|
2008-06-15 21:24:30 -06:00
|
|
|
|
2009-07-17 02:00:44 -06:00
|
|
|
case OAS2:
|
|
|
|
*init = concat(*init, n->ninit);
|
|
|
|
n->ninit = nil;
|
2010-02-01 23:18:51 -07:00
|
|
|
walkexprlistsafe(n->list, init);
|
|
|
|
walkexprlistsafe(n->rlist, init);
|
2009-08-04 11:26:29 -06:00
|
|
|
ll = ascompatee(OAS, n->list, n->rlist, init);
|
|
|
|
ll = reorder3(ll);
|
|
|
|
n = liststmt(ll);
|
|
|
|
goto ret;
|
2009-07-17 02:00:44 -06:00
|
|
|
|
2009-08-04 11:26:29 -06:00
|
|
|
case OAS2FUNC:
|
|
|
|
as2func:
|
|
|
|
// a,b,... = fn()
|
|
|
|
*init = concat(*init, n->ninit);
|
|
|
|
n->ninit = nil;
|
|
|
|
r = n->rlist->n;
|
2010-02-01 23:18:51 -07:00
|
|
|
walkexprlistsafe(n->list, init);
|
2009-08-04 11:26:29 -06:00
|
|
|
walkexpr(&r, init);
|
2010-03-22 19:51:14 -06:00
|
|
|
l = n->list->n;
|
|
|
|
|
|
|
|
// all the really hard stuff - explicit function calls and so on -
|
|
|
|
// is gone, but map assignments remain.
|
|
|
|
// if there are map assignments here, assign via
|
|
|
|
// temporaries, because ascompatet assumes
|
|
|
|
// the targets can be addressed without function calls
|
|
|
|
// and map index has an implicit one.
|
|
|
|
lpost = nil;
|
|
|
|
if(l->op == OINDEXMAP) {
|
|
|
|
var = nod(OXXX, N, N);
|
|
|
|
tempname(var, l->type);
|
|
|
|
n->list->n = var;
|
|
|
|
a = nod(OAS, l, var);
|
|
|
|
typecheck(&a, Etop);
|
|
|
|
lpost = list(lpost, a);
|
|
|
|
}
|
|
|
|
l = n->list->next->n;
|
|
|
|
if(l->op == OINDEXMAP) {
|
|
|
|
var = nod(OXXX, N, N);
|
|
|
|
tempname(var, l->type);
|
|
|
|
n->list->next->n = var;
|
|
|
|
a = nod(OAS, l, var);
|
|
|
|
typecheck(&a, Etop);
|
|
|
|
lpost = list(lpost, a);
|
|
|
|
}
|
2009-08-04 11:26:29 -06:00
|
|
|
ll = ascompatet(n->op, n->list, &r->type, 0, init);
|
2010-03-22 19:51:14 -06:00
|
|
|
walkexprlist(lpost, init);
|
|
|
|
n = liststmt(concat(concat(list1(r), ll), lpost));
|
2009-08-04 11:26:29 -06:00
|
|
|
goto ret;
|
2008-06-22 22:02:06 -06:00
|
|
|
|
2009-08-04 11:26:29 -06:00
|
|
|
case OAS2RECV:
|
|
|
|
// a,b = <-c
|
|
|
|
*init = concat(*init, n->ninit);
|
|
|
|
n->ninit = nil;
|
|
|
|
r = n->rlist->n;
|
2010-02-01 23:18:51 -07:00
|
|
|
walkexprlistsafe(n->list, init);
|
2009-08-04 11:26:29 -06:00
|
|
|
walkexpr(&r->left, init);
|
|
|
|
fn = chanfn("chanrecv2", 2, r->left->type);
|
|
|
|
r = mkcall1(fn, getoutargx(fn->type), init, r->left);
|
|
|
|
n->rlist->n = r;
|
|
|
|
n->op = OAS2FUNC;
|
|
|
|
goto as2func;
|
2008-06-22 22:02:06 -06:00
|
|
|
|
2009-08-04 11:26:29 -06:00
|
|
|
case OAS2MAPR:
|
|
|
|
// a,b = m[i];
|
|
|
|
*init = concat(*init, n->ninit);
|
|
|
|
n->ninit = nil;
|
2009-07-17 02:00:44 -06:00
|
|
|
r = n->rlist->n;
|
2010-02-01 23:18:51 -07:00
|
|
|
walkexprlistsafe(n->list, init);
|
2009-08-04 11:26:29 -06:00
|
|
|
walkexpr(&r->left, init);
|
|
|
|
fn = mapfn("mapaccess2", r->left->type);
|
|
|
|
r = mkcall1(fn, getoutargx(fn->type), init, r->left, r->right);
|
|
|
|
n->rlist = list1(r);
|
|
|
|
n->op = OAS2FUNC;
|
|
|
|
goto as2func;
|
|
|
|
|
|
|
|
case OAS2MAPW:
|
|
|
|
// map[] = a,b - mapassign2
|
|
|
|
// a,b = m[i];
|
|
|
|
*init = concat(*init, n->ninit);
|
|
|
|
n->ninit = nil;
|
2010-02-01 23:18:51 -07:00
|
|
|
walkexprlistsafe(n->list, init);
|
2009-08-04 11:26:29 -06:00
|
|
|
l = n->list->n;
|
|
|
|
t = l->left->type;
|
|
|
|
n = mkcall1(mapfn("mapassign2", t), T, init, l->left, l->right, n->rlist->n, n->rlist->next->n);
|
|
|
|
goto ret;
|
2008-07-13 15:29:46 -06:00
|
|
|
|
2009-08-04 11:26:29 -06:00
|
|
|
case OAS2DOTTYPE:
|
|
|
|
// a,b = i.(T)
|
|
|
|
*init = concat(*init, n->ninit);
|
|
|
|
n->ninit = nil;
|
|
|
|
r = n->rlist->n;
|
2010-02-01 23:18:51 -07:00
|
|
|
walkexprlistsafe(n->list, init);
|
2010-06-08 19:50:02 -06:00
|
|
|
r->op = ODOTTYPE2;
|
|
|
|
walkexpr(&r, init);
|
2009-08-04 11:26:29 -06:00
|
|
|
ll = ascompatet(n->op, n->list, &r->type, 0, init);
|
|
|
|
n = liststmt(concat(list1(r), ll));
|
2008-06-04 15:37:38 -06:00
|
|
|
goto ret;
|
|
|
|
|
2009-03-03 09:41:02 -07:00
|
|
|
case ODOTTYPE:
|
2010-06-27 18:37:01 -06:00
|
|
|
case ODOTTYPE2:
|
2010-06-08 19:50:02 -06:00
|
|
|
// Build name of function: assertI2E2 etc.
|
|
|
|
strcpy(buf, "assert");
|
|
|
|
p = buf+strlen(buf);
|
|
|
|
if(isnilinter(n->left->type))
|
|
|
|
*p++ = 'E';
|
|
|
|
else
|
|
|
|
*p++ = 'I';
|
|
|
|
*p++ = '2';
|
|
|
|
if(isnilinter(n->type))
|
|
|
|
*p++ = 'E';
|
|
|
|
else if(isinter(n->type))
|
|
|
|
*p++ = 'I';
|
|
|
|
else
|
|
|
|
*p++ = 'T';
|
|
|
|
if(n->op == ODOTTYPE2)
|
|
|
|
*p++ = '2';
|
|
|
|
*p = '\0';
|
|
|
|
|
|
|
|
fn = syslook(buf, 1);
|
|
|
|
ll = list1(typename(n->type));
|
|
|
|
ll = list(ll, n->left);
|
|
|
|
argtype(fn, n->left->type);
|
|
|
|
argtype(fn, n->type);
|
|
|
|
n = nod(OCALL, fn, N);
|
|
|
|
n->list = ll;
|
|
|
|
typecheck(&n, Erv | Efnstruct);
|
|
|
|
walkexpr(&n, init);
|
|
|
|
goto ret;
|
|
|
|
|
|
|
|
case OCONVIFACE:
|
|
|
|
// Build name of function: convI2E etc.
|
|
|
|
// Not all names are possible
|
|
|
|
// (e.g., we'll never generate convE2E or convE2I).
|
|
|
|
walkexpr(&n->left, init);
|
|
|
|
strcpy(buf, "conv");
|
|
|
|
p = buf+strlen(buf);
|
|
|
|
if(isnilinter(n->left->type))
|
|
|
|
*p++ = 'E';
|
|
|
|
else if(isinter(n->left->type))
|
|
|
|
*p++ = 'I';
|
|
|
|
else
|
|
|
|
*p++ = 'T';
|
|
|
|
*p++ = '2';
|
|
|
|
if(isnilinter(n->type))
|
|
|
|
*p++ = 'E';
|
|
|
|
else
|
|
|
|
*p++ = 'I';
|
|
|
|
*p = '\0';
|
|
|
|
|
|
|
|
fn = syslook(buf, 1);
|
|
|
|
ll = nil;
|
|
|
|
if(!isinter(n->left->type))
|
|
|
|
ll = list(ll, typename(n->left->type));
|
|
|
|
if(!isnilinter(n->type))
|
|
|
|
ll = list(ll, typename(n->type));
|
|
|
|
ll = list(ll, n->left);
|
|
|
|
argtype(fn, n->left->type);
|
|
|
|
argtype(fn, n->type);
|
|
|
|
dowidth(fn->type);
|
|
|
|
n = nod(OCALL, fn, N);
|
|
|
|
n->list = ll;
|
|
|
|
typecheck(&n, Erv);
|
|
|
|
walkexpr(&n, init);
|
2008-12-19 18:11:54 -07:00
|
|
|
goto ret;
|
2009-07-03 10:44:59 -06:00
|
|
|
|
2009-08-03 12:58:52 -06:00
|
|
|
case OCONV:
|
|
|
|
case OCONVNOP:
|
2009-10-10 23:06:26 -06:00
|
|
|
if(thechar == '5') {
|
2010-02-18 18:55:11 -07:00
|
|
|
if(isfloat[n->left->type->etype] &&
|
|
|
|
(n->type->etype == TINT64 || n->type->etype == TUINT64)) {
|
2009-10-10 23:06:26 -06:00
|
|
|
n = mkcall("float64toint64", n->type, init, conv(n->left, types[TFLOAT64]));
|
|
|
|
goto ret;
|
|
|
|
}
|
2010-02-18 18:55:11 -07:00
|
|
|
if((n->left->type->etype == TINT64 || n->left->type->etype == TUINT64) &&
|
|
|
|
isfloat[n->type->etype]) {
|
2009-10-10 23:06:26 -06:00
|
|
|
n = mkcall("int64tofloat64", n->type, init, conv(n->left, types[TINT64]));
|
|
|
|
goto ret;
|
|
|
|
}
|
|
|
|
}
|
2009-08-03 12:58:52 -06:00
|
|
|
walkexpr(&n->left, init);
|
2008-06-04 15:37:38 -06:00
|
|
|
goto ret;
|
|
|
|
|
|
|
|
case OASOP:
|
2010-02-01 23:18:51 -07:00
|
|
|
n->left = safeexpr(n->left, init);
|
2009-07-31 10:29:28 -06:00
|
|
|
walkexpr(&n->left, init);
|
2008-08-10 17:49:01 -06:00
|
|
|
l = n->left;
|
2009-07-31 10:29:28 -06:00
|
|
|
walkexpr(&n->right, init);
|
|
|
|
if(n->etype == OANDNOT) {
|
|
|
|
n->etype = OAND;
|
|
|
|
n->right = nod(OCOM, n->right, N);
|
2009-09-21 16:45:55 -06:00
|
|
|
typecheck(&n->right, Erv);
|
2009-07-31 10:29:28 -06:00
|
|
|
}
|
2009-08-03 12:58:52 -06:00
|
|
|
|
2009-07-31 10:29:28 -06:00
|
|
|
/*
|
2010-03-05 16:35:09 -07:00
|
|
|
* on 32-bit arch, rewrite 64-bit ops into l = l op r.
|
|
|
|
* on 386, rewrite float ops into l = l op r.
|
2010-03-22 19:51:14 -06:00
|
|
|
* everywhere, rewrite map ops into l = l op r.
|
|
|
|
* everywhere, rewrite string += into l = l op r.
|
2010-03-05 16:35:09 -07:00
|
|
|
* TODO(rsc): Maybe this rewrite should be done always?
|
2009-07-31 10:29:28 -06:00
|
|
|
*/
|
|
|
|
et = n->left->type->etype;
|
2010-03-05 16:35:09 -07:00
|
|
|
if((widthptr == 4 && (et == TUINT64 || et == TINT64)) ||
|
2010-03-22 19:51:14 -06:00
|
|
|
(thechar == '8' && isfloat[et]) ||
|
|
|
|
l->op == OINDEXMAP ||
|
|
|
|
et == TSTRING) {
|
2010-02-01 23:18:51 -07:00
|
|
|
l = safeexpr(n->left, init);
|
2010-03-22 19:51:14 -06:00
|
|
|
a = l;
|
|
|
|
if(a->op == OINDEXMAP) {
|
|
|
|
// map index has "lhs" bit set in a->etype.
|
|
|
|
// make a copy so we can clear it on the rhs.
|
|
|
|
a = nod(OXXX, N, N);
|
|
|
|
*a = *l;
|
|
|
|
a->etype = 0;
|
|
|
|
}
|
|
|
|
r = nod(OAS, l, nod(n->etype, a, n->right));
|
2009-07-31 10:29:28 -06:00
|
|
|
typecheck(&r, Etop);
|
|
|
|
walkexpr(&r, init);
|
|
|
|
n = r;
|
|
|
|
}
|
2009-07-30 19:56:44 -06:00
|
|
|
goto ret;
|
2008-08-28 20:59:42 -06:00
|
|
|
|
2009-03-11 20:59:35 -06:00
|
|
|
case OANDNOT:
|
2009-07-31 10:29:28 -06:00
|
|
|
walkexpr(&n->left, init);
|
|
|
|
walkexpr(&n->right, init);
|
|
|
|
n->op = OAND;
|
|
|
|
n->right = nod(OCOM, n->right, N);
|
2009-09-21 16:45:55 -06:00
|
|
|
typecheck(&n->right, Erv);
|
2009-07-31 10:29:28 -06:00
|
|
|
goto ret;
|
|
|
|
|
|
|
|
case ODIV:
|
|
|
|
case OMOD:
|
2010-03-09 13:49:24 -07:00
|
|
|
walkexpr(&n->left, init);
|
|
|
|
walkexpr(&n->right, init);
|
|
|
|
/*
|
|
|
|
* rewrite complex div into function call.
|
|
|
|
*/
|
|
|
|
et = n->left->type->etype;
|
|
|
|
if(iscomplex[et] && n->op == ODIV) {
|
|
|
|
n = mkcall("complex128div", n->type, init,
|
|
|
|
conv(n->left, types[TCOMPLEX128]),
|
|
|
|
conv(n->right, types[TCOMPLEX128]));
|
|
|
|
goto ret;
|
|
|
|
}
|
2009-07-30 19:56:44 -06:00
|
|
|
/*
|
|
|
|
* rewrite div and mod into function calls
|
|
|
|
* on 32-bit architectures.
|
|
|
|
*/
|
2009-07-31 10:29:28 -06:00
|
|
|
if(widthptr > 4 || (et != TUINT64 && et != TINT64))
|
|
|
|
goto ret;
|
|
|
|
if(et == TINT64)
|
|
|
|
strcpy(namebuf, "int64");
|
|
|
|
else
|
|
|
|
strcpy(namebuf, "uint64");
|
|
|
|
if(n->op == ODIV)
|
|
|
|
strcat(namebuf, "div");
|
|
|
|
else
|
|
|
|
strcat(namebuf, "mod");
|
|
|
|
n = mkcall(namebuf, n->type, init,
|
|
|
|
conv(n->left, types[et]), conv(n->right, types[et]));
|
2008-08-27 18:28:30 -06:00
|
|
|
goto ret;
|
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
case OINDEX:
|
2009-07-31 10:29:28 -06:00
|
|
|
walkexpr(&n->left, init);
|
|
|
|
walkexpr(&n->right, init);
|
2010-02-25 16:11:07 -07:00
|
|
|
|
2009-12-02 18:30:07 -07:00
|
|
|
// if range of type cannot exceed static array bound,
|
|
|
|
// disable bounds check
|
|
|
|
if(!isslice(n->left->type))
|
|
|
|
if(n->right->type->width < 4)
|
|
|
|
if((1<<(8*n->right->type->width)) <= n->left->type->bound)
|
|
|
|
n->etype = 1;
|
|
|
|
|
2010-08-03 01:26:02 -06:00
|
|
|
// check for static out of bounds
|
|
|
|
if(isconst(n->right, CTINT) && !n->etype) {
|
|
|
|
v = mpgetfix(n->right->val.u.xval);
|
|
|
|
len = 1LL<<60;
|
|
|
|
t = n->left->type;
|
|
|
|
if(t != T && isptr[t->etype])
|
|
|
|
t = t->type;
|
|
|
|
if(isfixedarray(t))
|
|
|
|
len = t->bound;
|
|
|
|
if(v < 0 || v >= (1LL<<31) || v >= len)
|
|
|
|
yyerror("index out of bounds");
|
|
|
|
}
|
2009-08-03 12:58:52 -06:00
|
|
|
goto ret;
|
|
|
|
|
|
|
|
case OINDEXMAP:
|
|
|
|
if(n->etype == 1)
|
2008-06-04 15:37:38 -06:00
|
|
|
goto ret;
|
|
|
|
t = n->left->type;
|
2009-08-03 12:58:52 -06:00
|
|
|
n = mkcall1(mapfn("mapaccess1", t), t->type, init, n->left, n->right);
|
2008-06-04 15:37:38 -06:00
|
|
|
goto ret;
|
|
|
|
|
2008-07-13 15:29:46 -06:00
|
|
|
case ORECV:
|
2009-07-31 10:29:28 -06:00
|
|
|
walkexpr(&n->left, init);
|
|
|
|
walkexpr(&n->right, init);
|
2009-08-03 12:58:52 -06:00
|
|
|
n = mkcall1(chanfn("chanrecv1", 2, n->left->type), n->type, init, n->left);
|
2008-07-13 15:29:46 -06:00
|
|
|
goto ret;
|
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
case OSLICE:
|
2010-08-03 01:26:02 -06:00
|
|
|
case OSLICEARR:
|
2009-07-31 10:29:28 -06:00
|
|
|
walkexpr(&n->left, init);
|
2010-03-08 15:19:28 -07:00
|
|
|
n->left = safeexpr(n->left, init);
|
2009-07-31 10:29:28 -06:00
|
|
|
walkexpr(&n->right->left, init);
|
2010-03-08 15:19:28 -07:00
|
|
|
n->right->left = safeexpr(n->right->left, init);
|
2009-07-31 10:29:28 -06:00
|
|
|
walkexpr(&n->right->right, init);
|
2010-03-08 15:19:28 -07:00
|
|
|
n->right->right = safeexpr(n->right->right, init);
|
2010-08-03 01:26:02 -06:00
|
|
|
|
|
|
|
len = 1LL<<60;
|
|
|
|
t = n->left->type;
|
|
|
|
if(t != T && isptr[t->etype])
|
|
|
|
t = t->type;
|
|
|
|
if(isfixedarray(t))
|
|
|
|
len = t->bound;
|
|
|
|
|
|
|
|
// check for static out of bounds
|
|
|
|
// NOTE: v > len not v >= len.
|
|
|
|
v1 = -1;
|
|
|
|
v2 = -1;
|
|
|
|
if(isconst(n->right->left, CTINT)) {
|
|
|
|
v1 = mpgetfix(n->right->left->val.u.xval);
|
|
|
|
if(v1 < 0 || v1 >= (1LL<<31) || v1 > len) {
|
|
|
|
yyerror("slice index out of bounds");
|
|
|
|
v1 = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(isconst(n->right->right, CTINT)) {
|
|
|
|
v2 = mpgetfix(n->right->right->val.u.xval);
|
|
|
|
if(v2 < 0 || v2 >= (1LL<<31) || v2 > len) {
|
|
|
|
yyerror("slice index out of bounds");
|
|
|
|
v2 = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(v1 >= 0 && v2 >= 0 && v1 > v2)
|
|
|
|
yyerror("inverted slice range");
|
|
|
|
|
|
|
|
if(n->op == OSLICEARR)
|
|
|
|
goto slicearray;
|
|
|
|
|
2009-08-03 12:58:52 -06:00
|
|
|
// dynamic slice
|
2010-08-03 01:26:02 -06:00
|
|
|
// sliceslice(old []any, lb uint64, hb uint64, width uint64) (ary []any)
|
|
|
|
// sliceslice1(old []any, lb uint64, width uint64) (ary []any)
|
2009-08-03 12:58:52 -06:00
|
|
|
t = n->type;
|
2010-09-08 20:20:29 -06:00
|
|
|
if(n->right->left == N)
|
|
|
|
l = nodintconst(0);
|
|
|
|
else
|
|
|
|
l = conv(n->right->left, types[TUINT64]);
|
2009-11-20 10:11:46 -07:00
|
|
|
if(n->right->right != N) {
|
|
|
|
fn = syslook("sliceslice", 1);
|
|
|
|
argtype(fn, t->type); // any-1
|
|
|
|
argtype(fn, t->type); // any-2
|
|
|
|
n = mkcall1(fn, t, init,
|
|
|
|
n->left,
|
2010-09-08 20:20:29 -06:00
|
|
|
l,
|
2010-08-03 01:26:02 -06:00
|
|
|
conv(n->right->right, types[TUINT64]),
|
2009-11-20 10:11:46 -07:00
|
|
|
nodintconst(t->type->width));
|
|
|
|
} else {
|
|
|
|
fn = syslook("sliceslice1", 1);
|
|
|
|
argtype(fn, t->type); // any-1
|
|
|
|
argtype(fn, t->type); // any-2
|
|
|
|
n = mkcall1(fn, t, init,
|
|
|
|
n->left,
|
2010-09-08 20:20:29 -06:00
|
|
|
l,
|
2009-11-20 10:11:46 -07:00
|
|
|
nodintconst(t->type->width));
|
|
|
|
}
|
2009-08-03 12:58:52 -06:00
|
|
|
goto ret;
|
|
|
|
|
2010-08-03 01:26:02 -06:00
|
|
|
slicearray:
|
2009-08-03 12:58:52 -06:00
|
|
|
// static slice
|
2010-08-03 01:26:02 -06:00
|
|
|
// slicearray(old *any, uint64 nel, lb uint64, hb uint64, width uint64) (ary []any)
|
2009-08-03 12:58:52 -06:00
|
|
|
t = n->type;
|
2009-08-25 16:54:25 -06:00
|
|
|
fn = syslook("slicearray", 1);
|
2010-09-10 09:53:27 -06:00
|
|
|
argtype(fn, n->left->type->type); // any-1
|
2009-08-03 12:58:52 -06:00
|
|
|
argtype(fn, t->type); // any-2
|
2010-09-08 20:20:29 -06:00
|
|
|
if(n->right->left == N)
|
|
|
|
l = nodintconst(0);
|
|
|
|
else
|
|
|
|
l = conv(n->right->left, types[TUINT64]);
|
2009-11-20 10:11:46 -07:00
|
|
|
if(n->right->right == N)
|
2010-09-10 09:53:27 -06:00
|
|
|
r = nodintconst(n->left->type->type->bound);
|
2009-11-20 10:11:46 -07:00
|
|
|
else
|
2010-08-03 01:26:02 -06:00
|
|
|
r = conv(n->right->right, types[TUINT64]);
|
2009-08-03 12:58:52 -06:00
|
|
|
n = mkcall1(fn, t, init,
|
2010-09-10 09:53:27 -06:00
|
|
|
n->left, nodintconst(n->left->type->type->bound),
|
2010-09-08 20:20:29 -06:00
|
|
|
l,
|
2009-11-20 10:11:46 -07:00
|
|
|
r,
|
2009-08-03 12:58:52 -06:00
|
|
|
nodintconst(t->type->width));
|
|
|
|
goto ret;
|
|
|
|
|
|
|
|
case OADDR:;
|
|
|
|
Node *nvar, *nstar;
|
|
|
|
|
|
|
|
// turn &Point(1, 2) or &[]int(1, 2) or &[...]int(1, 2) into allocation.
|
|
|
|
// initialize with
|
|
|
|
// nvar := new(*Point);
|
|
|
|
// *nvar = Point(1, 2);
|
|
|
|
// and replace expression with nvar
|
|
|
|
switch(n->left->op) {
|
|
|
|
case OARRAYLIT:
|
|
|
|
case OMAPLIT:
|
|
|
|
case OSTRUCTLIT:
|
|
|
|
nvar = makenewvar(n->type, init, &nstar);
|
2010-09-20 15:23:25 -06:00
|
|
|
anylit(0, n->left, nstar, init);
|
2009-08-03 12:58:52 -06:00
|
|
|
n = nvar;
|
2008-08-27 18:28:30 -06:00
|
|
|
goto ret;
|
|
|
|
}
|
2009-08-03 12:58:52 -06:00
|
|
|
|
|
|
|
walkexpr(&n->left, init);
|
2008-06-04 15:37:38 -06:00
|
|
|
goto ret;
|
|
|
|
|
2009-08-03 12:58:52 -06:00
|
|
|
case ONEW:
|
|
|
|
n = callnew(n->type->type);
|
|
|
|
goto ret;
|
2009-07-14 00:38:39 -06:00
|
|
|
|
2009-08-03 12:58:52 -06:00
|
|
|
case OCMPSTR:
|
2010-04-11 16:24:44 -06:00
|
|
|
// If one argument to the comparison is an empty string,
|
|
|
|
// comparing the lengths instead will yield the same result
|
|
|
|
// without the function call.
|
|
|
|
if((isconst(n->left, CTSTR) && n->left->val.u.sval->len == 0) ||
|
|
|
|
(isconst(n->right, CTSTR) && n->right->val.u.sval->len == 0)) {
|
|
|
|
r = nod(n->etype, nod(OLEN, n->left, N), nod(OLEN, n->right, N));
|
|
|
|
typecheck(&r, Erv);
|
|
|
|
walkexpr(&r, init);
|
|
|
|
n = r;
|
|
|
|
goto ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// s + "badgerbadgerbadger" == "badgerbadgerbadger"
|
|
|
|
if((n->etype == OEQ || n->etype == ONE) &&
|
|
|
|
isconst(n->right, CTSTR) &&
|
|
|
|
n->left->op == OADDSTR && isconst(n->left->right, CTSTR) &&
|
|
|
|
cmpslit(n->right, n->left->right) == 0) {
|
|
|
|
r = nod(n->etype, nod(OLEN, n->left->left, N), nodintconst(0));
|
|
|
|
typecheck(&r, Erv);
|
|
|
|
walkexpr(&r, init);
|
|
|
|
n = r;
|
|
|
|
goto ret;
|
|
|
|
}
|
|
|
|
|
2010-10-06 07:53:12 -06:00
|
|
|
// prepare for rewrite below
|
|
|
|
if(n->etype == OEQ || n->etype == ONE) {
|
|
|
|
n->left = cheapexpr(n->left, init);
|
|
|
|
n->right = cheapexpr(n->right, init);
|
|
|
|
}
|
|
|
|
|
2009-08-03 12:58:52 -06:00
|
|
|
// sys_cmpstring(s1, s2) :: 0
|
|
|
|
r = mkcall("cmpstring", types[TINT], init,
|
|
|
|
conv(n->left, types[TSTRING]),
|
|
|
|
conv(n->right, types[TSTRING]));
|
|
|
|
r = nod(n->etype, r, nodintconst(0));
|
2010-10-06 07:53:12 -06:00
|
|
|
|
|
|
|
// quick check of len before full compare for == or !=
|
|
|
|
if(n->etype == OEQ || n->etype == ONE) {
|
|
|
|
if(n->etype == OEQ)
|
|
|
|
r = nod(OANDAND, nod(OEQ, nod(OLEN, n->left, N), nod(OLEN, n->right, N)), r);
|
|
|
|
else
|
|
|
|
r = nod(OOROR, nod(ONE, nod(OLEN, n->left, N), nod(OLEN, n->right, N)), r);
|
|
|
|
typecheck(&r, Erv);
|
|
|
|
walkexpr(&r, nil);
|
|
|
|
}
|
2009-08-03 12:58:52 -06:00
|
|
|
typecheck(&r, Erv);
|
|
|
|
n = r;
|
|
|
|
goto ret;
|
2009-05-17 20:16:16 -06:00
|
|
|
|
2009-08-03 12:58:52 -06:00
|
|
|
case OADDSTR:
|
2010-09-11 22:53:04 -06:00
|
|
|
n = addstr(n, init);
|
2009-08-03 12:58:52 -06:00
|
|
|
goto ret;
|
2008-10-21 17:53:54 -06:00
|
|
|
|
2009-08-03 12:58:52 -06:00
|
|
|
case OSLICESTR:
|
|
|
|
// sys_slicestring(s, lb, hb)
|
2010-09-08 20:20:29 -06:00
|
|
|
if(n->right->left == N)
|
|
|
|
l = nodintconst(0);
|
|
|
|
else
|
|
|
|
l = conv(n->right->left, types[TINT]);
|
2009-11-20 12:42:28 -07:00
|
|
|
if(n->right->right) {
|
|
|
|
n = mkcall("slicestring", n->type, init,
|
|
|
|
conv(n->left, types[TSTRING]),
|
2010-09-08 20:20:29 -06:00
|
|
|
l,
|
2009-11-20 12:42:28 -07:00
|
|
|
conv(n->right->right, types[TINT]));
|
|
|
|
} else {
|
|
|
|
n = mkcall("slicestring1", n->type, init,
|
|
|
|
conv(n->left, types[TSTRING]),
|
2010-09-08 20:20:29 -06:00
|
|
|
l);
|
2009-11-20 12:42:28 -07:00
|
|
|
}
|
2009-08-03 12:58:52 -06:00
|
|
|
goto ret;
|
2008-10-21 17:53:54 -06:00
|
|
|
|
2009-08-03 12:58:52 -06:00
|
|
|
case OINDEXSTR:
|
|
|
|
// TODO(rsc): should be done in back end
|
|
|
|
// sys_indexstring(s, i)
|
|
|
|
n = mkcall("indexstring", n->type, init,
|
|
|
|
conv(n->left, types[TSTRING]),
|
|
|
|
conv(n->right, types[TINT]));
|
|
|
|
goto ret;
|
2009-02-13 15:48:16 -07:00
|
|
|
|
2009-11-17 21:41:44 -07:00
|
|
|
case OCOPY:
|
|
|
|
fn = syslook("slicecopy", 1);
|
|
|
|
argtype(fn, n->left->type);
|
|
|
|
argtype(fn, n->right->type);
|
|
|
|
n = mkcall1(fn, n->type, init,
|
|
|
|
n->left, n->right,
|
2009-11-18 14:43:48 -07:00
|
|
|
nodintconst(n->left->type->type->width));
|
2009-11-17 21:41:44 -07:00
|
|
|
goto ret;
|
|
|
|
|
2009-08-03 12:58:52 -06:00
|
|
|
case OCLOSE:
|
|
|
|
// cannot use chanfn - closechan takes any, not chan any
|
|
|
|
fn = syslook("closechan", 1);
|
|
|
|
argtype(fn, n->left->type);
|
|
|
|
n = mkcall1(fn, T, init, n->left);
|
|
|
|
goto ret;
|
2009-02-13 15:48:16 -07:00
|
|
|
|
2009-08-03 12:58:52 -06:00
|
|
|
case OCLOSED:
|
|
|
|
// cannot use chanfn - closechan takes any, not chan any
|
|
|
|
fn = syslook("closedchan", 1);
|
|
|
|
argtype(fn, n->left->type);
|
|
|
|
n = mkcall1(fn, n->type, init, n->left);
|
|
|
|
goto ret;
|
2009-02-13 15:48:16 -07:00
|
|
|
|
2009-08-03 12:58:52 -06:00
|
|
|
case OMAKECHAN:
|
2009-08-25 16:54:25 -06:00
|
|
|
n = mkcall1(chanfn("makechan", 1, n->type), n->type, init,
|
2009-09-08 14:46:54 -06:00
|
|
|
typename(n->type->type),
|
2010-05-01 14:15:42 -06:00
|
|
|
conv(n->left, types[TINT64]));
|
2008-06-04 15:37:38 -06:00
|
|
|
goto ret;
|
|
|
|
|
2009-08-03 12:58:52 -06:00
|
|
|
case OMAKEMAP:
|
|
|
|
t = n->type;
|
|
|
|
|
2009-08-25 16:54:25 -06:00
|
|
|
fn = syslook("makemap", 1);
|
2009-08-03 12:58:52 -06:00
|
|
|
argtype(fn, t->down); // any-1
|
|
|
|
argtype(fn, t->type); // any-2
|
|
|
|
|
|
|
|
n = mkcall1(fn, n->type, init,
|
2009-09-08 14:46:54 -06:00
|
|
|
typename(t->down), // key type
|
|
|
|
typename(t->type), // value type
|
2010-05-01 14:15:42 -06:00
|
|
|
conv(n->left, types[TINT64]));
|
2009-01-06 15:52:26 -07:00
|
|
|
goto ret;
|
|
|
|
|
2009-08-03 12:58:52 -06:00
|
|
|
case OMAKESLICE:
|
2010-05-01 14:15:42 -06:00
|
|
|
// makeslice(t *Type, nel int64, max int64) (ary []any)
|
|
|
|
l = n->left;
|
|
|
|
r = n->right;
|
|
|
|
if(r == nil)
|
|
|
|
l = r = safeexpr(l, init);
|
2009-08-03 12:58:52 -06:00
|
|
|
t = n->type;
|
2009-08-25 16:54:25 -06:00
|
|
|
fn = syslook("makeslice", 1);
|
2009-08-03 12:58:52 -06:00
|
|
|
argtype(fn, t->type); // any-1
|
2010-03-05 20:29:14 -07:00
|
|
|
n = mkcall1(fn, n->type, init,
|
2009-12-04 22:44:05 -07:00
|
|
|
typename(n->type),
|
2010-05-01 14:15:42 -06:00
|
|
|
conv(l, types[TINT64]),
|
|
|
|
conv(r, types[TINT64]));
|
2009-08-03 12:58:52 -06:00
|
|
|
goto ret;
|
|
|
|
|
|
|
|
case ORUNESTR:
|
|
|
|
// sys_intstring(v)
|
2009-11-17 21:41:44 -07:00
|
|
|
n = mkcall("intstring", n->type, init,
|
2010-06-08 19:50:02 -06:00
|
|
|
conv(n->left, types[TINT64]));
|
2009-08-03 12:58:52 -06:00
|
|
|
goto ret;
|
|
|
|
|
|
|
|
case OARRAYBYTESTR:
|
2009-08-25 16:54:25 -06:00
|
|
|
// slicebytetostring([]byte) string;
|
|
|
|
n = mkcall("slicebytetostring", n->type, init, n->left);
|
2009-08-03 12:58:52 -06:00
|
|
|
goto ret;
|
|
|
|
|
|
|
|
case OARRAYRUNESTR:
|
2010-02-25 16:11:07 -07:00
|
|
|
// sliceinttostring([]int) string;
|
2009-08-25 16:54:25 -06:00
|
|
|
n = mkcall("sliceinttostring", n->type, init, n->left);
|
2009-08-03 12:58:52 -06:00
|
|
|
goto ret;
|
|
|
|
|
2010-02-25 16:11:07 -07:00
|
|
|
case OSTRARRAYBYTE:
|
|
|
|
// stringtoslicebyte(string) []byte;
|
|
|
|
n = mkcall("stringtoslicebyte", n->type, init, n->left);
|
|
|
|
goto ret;
|
|
|
|
|
|
|
|
case OSTRARRAYRUNE:
|
|
|
|
// stringtosliceint(string) []int
|
|
|
|
n = mkcall("stringtosliceint", n->type, init, n->left);
|
|
|
|
goto ret;
|
|
|
|
|
2009-08-03 12:58:52 -06:00
|
|
|
case OCMPIFACE:
|
|
|
|
// ifaceeq(i1 any-1, i2 any-2) (ret bool);
|
|
|
|
if(!eqtype(n->left->type, n->right->type))
|
|
|
|
fatal("ifaceeq %O %T %T", n->op, n->left->type, n->right->type);
|
|
|
|
if(isnilinter(n->left->type))
|
|
|
|
fn = syslook("efaceeq", 1);
|
2009-06-06 13:46:38 -06:00
|
|
|
else
|
2009-08-03 12:58:52 -06:00
|
|
|
fn = syslook("ifaceeq", 1);
|
|
|
|
argtype(fn, n->right->type);
|
|
|
|
argtype(fn, n->left->type);
|
|
|
|
r = mkcall1(fn, n->type, init, n->left, n->right);
|
|
|
|
if(n->etype == ONE) {
|
|
|
|
r = nod(ONOT, r, N);
|
|
|
|
typecheck(&r, Erv);
|
|
|
|
}
|
|
|
|
n = r;
|
|
|
|
goto ret;
|
|
|
|
|
|
|
|
case OARRAYLIT:
|
|
|
|
case OMAPLIT:
|
|
|
|
case OSTRUCTLIT:
|
2009-09-05 21:32:24 -06:00
|
|
|
nvar = nod(OXXX, N, N);
|
|
|
|
tempname(nvar, n->type);
|
2010-09-20 15:23:25 -06:00
|
|
|
anylit(0, n, nvar, init);
|
2009-09-05 21:32:24 -06:00
|
|
|
n = nvar;
|
2009-08-03 12:58:52 -06:00
|
|
|
goto ret;
|
|
|
|
|
|
|
|
case OSEND:
|
|
|
|
n = mkcall1(chanfn("chansend1", 2, n->left->type), T, init, n->left, n->right);
|
|
|
|
goto ret;
|
|
|
|
|
|
|
|
case OSENDNB:
|
|
|
|
n = mkcall1(chanfn("chansend2", 2, n->left->type), n->type, init, n->left, n->right);
|
|
|
|
goto ret;
|
|
|
|
|
2009-08-07 13:50:26 -06:00
|
|
|
case OCLOSURE:
|
|
|
|
n = walkclosure(n, init);
|
|
|
|
goto ret;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
2009-07-31 10:29:28 -06:00
|
|
|
fatal("missing switch %O", n->op);
|
2008-06-04 15:37:38 -06:00
|
|
|
|
|
|
|
ret:
|
2009-07-31 10:29:28 -06:00
|
|
|
if(debug['w'] && n != N)
|
2008-06-17 19:07:40 -06:00
|
|
|
dump("walk", n);
|
2008-06-16 23:34:50 -06:00
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
ullmancalc(n);
|
2008-06-26 18:54:44 -06:00
|
|
|
lineno = lno;
|
2009-07-29 13:00:34 -06:00
|
|
|
*np = n;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
2009-12-27 10:32:30 -07:00
|
|
|
static Node*
|
2009-08-03 12:58:52 -06:00
|
|
|
makenewvar(Type *t, NodeList **init, Node **nstar)
|
|
|
|
{
|
|
|
|
Node *nvar, *nas;
|
|
|
|
|
|
|
|
nvar = nod(OXXX, N, N);
|
|
|
|
tempname(nvar, t);
|
|
|
|
nas = nod(OAS, nvar, callnew(t->type));
|
|
|
|
typecheck(&nas, Etop);
|
|
|
|
walkexpr(&nas, init);
|
|
|
|
*init = list(*init, nas);
|
|
|
|
|
|
|
|
*nstar = nod(OIND, nvar, N);
|
|
|
|
typecheck(nstar, Erv);
|
|
|
|
return nvar;
|
|
|
|
}
|
|
|
|
|
2010-06-14 12:24:51 -06:00
|
|
|
static Node*
|
2009-07-17 02:00:44 -06:00
|
|
|
ascompatee1(int op, Node *l, Node *r, NodeList **init)
|
2008-06-04 15:37:38 -06:00
|
|
|
{
|
2009-08-04 11:26:29 -06:00
|
|
|
return convas(nod(OAS, l, r), init);
|
2009-07-17 02:00:44 -06:00
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2010-06-14 12:24:51 -06:00
|
|
|
static NodeList*
|
2009-07-17 02:00:44 -06:00
|
|
|
ascompatee(int op, NodeList *nl, NodeList *nr, NodeList **init)
|
|
|
|
{
|
|
|
|
NodeList *ll, *lr, *nn;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* check assign expression list to
|
|
|
|
* a expression list. called in
|
|
|
|
* expr-list = expr-list
|
|
|
|
*/
|
2010-02-01 23:18:51 -07:00
|
|
|
|
|
|
|
// ensure order of evaluation for function calls
|
|
|
|
for(ll=nl; ll; ll=ll->next)
|
|
|
|
ll->n = safeexpr(ll->n, init);
|
|
|
|
for(lr=nr; lr; lr=lr->next)
|
|
|
|
lr->n = safeexpr(lr->n, init);
|
|
|
|
|
2009-07-17 02:00:44 -06:00
|
|
|
nn = nil;
|
|
|
|
for(ll=nl, lr=nr; ll && lr; ll=ll->next, lr=lr->next)
|
|
|
|
nn = list(nn, ascompatee1(op, ll->n, lr->n, init));
|
|
|
|
|
|
|
|
// cannot happen: caller checked that lists had same length
|
|
|
|
if(ll || lr)
|
|
|
|
yyerror("error in shape across %O", op);
|
|
|
|
return nn;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
2009-05-26 16:56:37 -06:00
|
|
|
/*
|
2009-09-09 00:16:19 -06:00
|
|
|
* l is an lv and rt is the type of an rv
|
2009-05-26 16:56:37 -06:00
|
|
|
* return 1 if this implies a function call
|
|
|
|
* evaluating the lv or a function call
|
|
|
|
* in the conversion of the types
|
|
|
|
*/
|
2010-06-14 12:24:51 -06:00
|
|
|
static int
|
2009-05-26 16:56:37 -06:00
|
|
|
fncall(Node *l, Type *rt)
|
|
|
|
{
|
|
|
|
if(l->ullman >= UINF)
|
|
|
|
return 1;
|
|
|
|
if(eqtype(l->type, rt))
|
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2010-06-14 12:24:51 -06:00
|
|
|
static NodeList*
|
2009-07-17 02:00:44 -06:00
|
|
|
ascompatet(int op, NodeList *nl, Type **nr, int fp, NodeList **init)
|
2008-06-04 15:37:38 -06:00
|
|
|
{
|
2009-07-17 02:00:44 -06:00
|
|
|
Node *l, *tmp, *a;
|
|
|
|
NodeList *ll;
|
2008-06-04 15:37:38 -06:00
|
|
|
Type *r;
|
2009-07-17 02:00:44 -06:00
|
|
|
Iter saver;
|
2009-05-26 16:56:37 -06:00
|
|
|
int ucount;
|
2009-07-17 02:00:44 -06:00
|
|
|
NodeList *nn, *mm;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2008-06-10 22:29:57 -06:00
|
|
|
/*
|
|
|
|
* check assign type list to
|
|
|
|
* a expression list. called in
|
|
|
|
* expr-list = func()
|
|
|
|
*/
|
2008-06-04 15:37:38 -06:00
|
|
|
r = structfirst(&saver, nr);
|
2009-07-17 02:00:44 -06:00
|
|
|
nn = nil;
|
|
|
|
mm = nil;
|
2009-05-26 16:56:37 -06:00
|
|
|
ucount = 0;
|
2009-07-17 02:00:44 -06:00
|
|
|
for(ll=nl; ll; ll=ll->next) {
|
|
|
|
if(r == T)
|
|
|
|
break;
|
|
|
|
l = ll->n;
|
2009-09-09 00:16:19 -06:00
|
|
|
if(isblank(l)) {
|
|
|
|
r = structnext(&saver);
|
|
|
|
continue;
|
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-07-17 02:00:44 -06:00
|
|
|
// any lv that causes a fn call must be
|
|
|
|
// deferred until all the return arguments
|
|
|
|
// have been pulled from the output arguments
|
|
|
|
if(fncall(l, r->type)) {
|
|
|
|
tmp = nod(OXXX, N, N);
|
|
|
|
tempname(tmp, r->type);
|
2010-06-08 19:50:02 -06:00
|
|
|
typecheck(&tmp, Erv);
|
2009-07-17 02:00:44 -06:00
|
|
|
a = nod(OAS, l, tmp);
|
|
|
|
a = convas(a, init);
|
|
|
|
mm = list(mm, a);
|
|
|
|
l = tmp;
|
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-07-17 02:00:44 -06:00
|
|
|
a = nod(OAS, l, nodarg(r, fp));
|
2009-07-10 17:29:26 -06:00
|
|
|
a = convas(a, init);
|
2009-07-17 02:00:44 -06:00
|
|
|
ullmancalc(a);
|
|
|
|
if(a->ullman >= UINF)
|
|
|
|
ucount++;
|
|
|
|
nn = list(nn, a);
|
|
|
|
r = structnext(&saver);
|
2009-05-26 16:56:37 -06:00
|
|
|
}
|
|
|
|
|
2009-07-17 02:00:44 -06:00
|
|
|
if(ll != nil || r != T)
|
|
|
|
yyerror("assignment count mismatch: %d = %d",
|
|
|
|
count(nl), structcount(*nr));
|
|
|
|
if(ucount)
|
2010-03-22 19:51:14 -06:00
|
|
|
fatal("reorder2: too many function calls evaluating parameters");
|
2009-07-17 02:00:44 -06:00
|
|
|
return concat(nn, mm);
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
2010-02-01 01:25:59 -07:00
|
|
|
/*
|
|
|
|
* package all the arguments that match a ... T parameter into a []T.
|
|
|
|
*/
|
2010-06-14 12:24:51 -06:00
|
|
|
static NodeList*
|
2010-02-01 01:25:59 -07:00
|
|
|
mkdotargslice(NodeList *lr0, NodeList *nn, Type *l, int fp, NodeList **init)
|
|
|
|
{
|
|
|
|
Node *a, *n;
|
|
|
|
Type *tslice;
|
2010-02-25 16:11:07 -07:00
|
|
|
|
2010-02-01 01:25:59 -07:00
|
|
|
tslice = typ(TARRAY);
|
|
|
|
tslice->type = l->type->type;
|
|
|
|
tslice->bound = -1;
|
2010-02-25 16:11:07 -07:00
|
|
|
|
2010-02-01 01:25:59 -07:00
|
|
|
n = nod(OCOMPLIT, N, typenod(tslice));
|
|
|
|
n->list = lr0;
|
|
|
|
typecheck(&n, Erv);
|
|
|
|
if(n->type == T)
|
|
|
|
fatal("mkdotargslice: typecheck failed");
|
|
|
|
walkexpr(&n, init);
|
2010-02-25 16:11:07 -07:00
|
|
|
|
2010-02-01 01:25:59 -07:00
|
|
|
a = nod(OAS, nodarg(l, fp), n);
|
|
|
|
nn = list(nn, convas(a, init));
|
|
|
|
return nn;
|
|
|
|
}
|
|
|
|
|
2009-05-07 11:29:35 -06:00
|
|
|
/*
|
|
|
|
* helpers for shape errors
|
|
|
|
*/
|
2010-07-15 17:42:32 -06:00
|
|
|
static char*
|
2009-05-07 11:29:35 -06:00
|
|
|
dumptypes(Type **nl, char *what)
|
|
|
|
{
|
|
|
|
int first;
|
|
|
|
Type *l;
|
|
|
|
Iter savel;
|
2010-07-15 17:42:32 -06:00
|
|
|
Fmt fmt;
|
2009-05-07 11:29:35 -06:00
|
|
|
|
2010-07-15 17:42:32 -06:00
|
|
|
fmtstrinit(&fmt);
|
|
|
|
fmtprint(&fmt, "\t");
|
2009-05-07 11:29:35 -06:00
|
|
|
l = structfirst(&savel, nl);
|
|
|
|
first = 1;
|
|
|
|
for(l = structfirst(&savel, nl); l != T; l = structnext(&savel)) {
|
|
|
|
if(first)
|
|
|
|
first = 0;
|
|
|
|
else
|
2010-07-15 17:42:32 -06:00
|
|
|
fmtprint(&fmt, ", ");
|
|
|
|
fmtprint(&fmt, "%T", l);
|
2009-05-07 11:29:35 -06:00
|
|
|
}
|
|
|
|
if(first)
|
2010-07-15 17:42:32 -06:00
|
|
|
fmtprint(&fmt, "[no arguments %s]", what);
|
|
|
|
return fmtstrflush(&fmt);
|
2009-05-07 11:29:35 -06:00
|
|
|
}
|
|
|
|
|
2010-07-15 17:42:32 -06:00
|
|
|
static char*
|
2009-07-17 02:00:44 -06:00
|
|
|
dumpnodetypes(NodeList *l, char *what)
|
2009-05-07 11:29:35 -06:00
|
|
|
{
|
|
|
|
int first;
|
|
|
|
Node *r;
|
2010-07-15 17:42:32 -06:00
|
|
|
Fmt fmt;
|
2009-05-07 11:29:35 -06:00
|
|
|
|
2010-07-15 17:42:32 -06:00
|
|
|
fmtstrinit(&fmt);
|
|
|
|
fmtprint(&fmt, "\t");
|
2009-05-07 11:29:35 -06:00
|
|
|
first = 1;
|
2009-07-17 02:00:44 -06:00
|
|
|
for(; l; l=l->next) {
|
|
|
|
r = l->n;
|
2009-05-07 11:29:35 -06:00
|
|
|
if(first)
|
|
|
|
first = 0;
|
|
|
|
else
|
2010-07-15 17:42:32 -06:00
|
|
|
fmtprint(&fmt, ", ");
|
|
|
|
fmtprint(&fmt, "%T", r->type);
|
2009-05-07 11:29:35 -06:00
|
|
|
}
|
|
|
|
if(first)
|
2010-07-15 17:42:32 -06:00
|
|
|
fmtprint(&fmt, "[no arguments %s]", what);
|
|
|
|
return fmtstrflush(&fmt);
|
2009-05-07 11:29:35 -06:00
|
|
|
}
|
|
|
|
|
2009-01-08 15:30:00 -07:00
|
|
|
/*
|
|
|
|
* check assign expression list to
|
|
|
|
* a type list. called in
|
|
|
|
* return expr-list
|
|
|
|
* func(expr-list)
|
|
|
|
*/
|
2010-06-14 12:24:51 -06:00
|
|
|
static NodeList*
|
2009-07-17 02:00:44 -06:00
|
|
|
ascompatte(int op, Type **nl, NodeList *lr, int fp, NodeList **init)
|
2008-06-04 15:37:38 -06:00
|
|
|
{
|
2008-11-03 16:32:49 -07:00
|
|
|
Type *l, *ll;
|
2009-07-17 02:00:44 -06:00
|
|
|
Node *r, *a;
|
2009-08-07 15:00:18 -06:00
|
|
|
NodeList *nn, *lr0, *alist;
|
2010-04-30 14:27:08 -06:00
|
|
|
Iter savel;
|
2010-07-15 17:42:32 -06:00
|
|
|
char *l1, *l2;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-07-17 02:00:44 -06:00
|
|
|
lr0 = lr;
|
2008-06-04 15:37:38 -06:00
|
|
|
l = structfirst(&savel, nl);
|
2009-07-17 02:00:44 -06:00
|
|
|
r = N;
|
|
|
|
if(lr)
|
|
|
|
r = lr->n;
|
|
|
|
nn = nil;
|
2010-04-30 14:27:08 -06:00
|
|
|
|
|
|
|
// f(g()) where g has multiple return values
|
|
|
|
if(r != N && lr->next == nil && r->type->etype == TSTRUCT && r->type->funarg) {
|
2009-08-07 15:00:18 -06:00
|
|
|
// optimization - can do block copy
|
|
|
|
if(eqtypenoname(r->type, *nl)) {
|
|
|
|
a = nodarg(*nl, fp);
|
|
|
|
a->type = r->type;
|
|
|
|
nn = list1(convas(nod(OAS, a, r), init));
|
|
|
|
goto ret;
|
|
|
|
}
|
2010-04-30 14:27:08 -06:00
|
|
|
|
2009-08-07 15:00:18 -06:00
|
|
|
// conversions involved.
|
|
|
|
// copy into temporaries.
|
|
|
|
alist = nil;
|
|
|
|
for(l=structfirst(&savel, &r->type); l; l=structnext(&savel)) {
|
|
|
|
a = nod(OXXX, N, N);
|
|
|
|
tempname(a, l->type);
|
|
|
|
alist = list(alist, a);
|
|
|
|
}
|
|
|
|
a = nod(OAS2, N, N);
|
|
|
|
a->list = alist;
|
|
|
|
a->rlist = lr;
|
|
|
|
typecheck(&a, Etop);
|
|
|
|
walkstmt(&a);
|
|
|
|
*init = list(*init, a);
|
|
|
|
lr = alist;
|
|
|
|
r = lr->n;
|
|
|
|
l = structfirst(&savel, nl);
|
2009-02-08 12:01:52 -07:00
|
|
|
}
|
2009-01-08 15:30:00 -07:00
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
loop:
|
2010-02-01 01:25:59 -07:00
|
|
|
if(l != T && l->isddd) {
|
2008-11-03 16:32:49 -07:00
|
|
|
// the ddd parameter must be last
|
|
|
|
ll = structnext(&savel);
|
|
|
|
if(ll != T)
|
|
|
|
yyerror("... must be last argument");
|
|
|
|
|
|
|
|
// special case --
|
|
|
|
// only if we are assigning a single ddd
|
|
|
|
// argument to a ddd parameter then it is
|
|
|
|
// passed thru unencapsulated
|
2010-02-01 01:25:59 -07:00
|
|
|
if(r != N && lr->next == nil && r->isddd && eqtype(l->type, r->type)) {
|
2008-11-03 16:32:49 -07:00
|
|
|
a = nod(OAS, nodarg(l, fp), r);
|
2009-07-10 17:29:26 -06:00
|
|
|
a = convas(a, init);
|
2009-07-17 02:00:44 -06:00
|
|
|
nn = list(nn, a);
|
2009-07-30 17:53:08 -06:00
|
|
|
goto ret;
|
2008-11-01 17:36:46 -06:00
|
|
|
}
|
|
|
|
|
2010-06-14 12:24:51 -06:00
|
|
|
// normal case -- make a slice of all
|
|
|
|
// remaining arguments and pass it to
|
|
|
|
// the ddd parameter.
|
|
|
|
nn = mkdotargslice(lr, nn, l, fp, init);
|
2009-07-30 17:53:08 -06:00
|
|
|
goto ret;
|
2008-11-01 17:36:46 -06:00
|
|
|
}
|
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
if(l == T || r == N) {
|
2009-05-07 11:29:35 -06:00
|
|
|
if(l != T || r != N) {
|
2010-07-15 17:42:32 -06:00
|
|
|
l1 = dumptypes(nl, "expected");
|
|
|
|
l2 = dumpnodetypes(lr0, "given");
|
2009-05-07 11:29:35 -06:00
|
|
|
if(l != T)
|
2010-07-15 17:42:32 -06:00
|
|
|
yyerror("not enough arguments to %O\n%s\n%s", op, l1, l2);
|
2009-05-07 11:29:35 -06:00
|
|
|
else
|
2010-07-15 17:42:32 -06:00
|
|
|
yyerror("too many arguments to %O\n%s\n%s", op, l1, l2);
|
2009-05-07 11:29:35 -06:00
|
|
|
}
|
2009-07-30 17:53:08 -06:00
|
|
|
goto ret;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
2009-08-03 12:58:52 -06:00
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
a = nod(OAS, nodarg(l, fp), r);
|
2009-07-10 17:29:26 -06:00
|
|
|
a = convas(a, init);
|
2009-07-17 02:00:44 -06:00
|
|
|
nn = list(nn, a);
|
2008-06-04 15:37:38 -06:00
|
|
|
|
|
|
|
l = structnext(&savel);
|
2009-07-17 02:00:44 -06:00
|
|
|
r = N;
|
|
|
|
lr = lr->next;
|
|
|
|
if(lr != nil)
|
|
|
|
r = lr->n;
|
2008-06-04 15:37:38 -06:00
|
|
|
goto loop;
|
2009-07-30 17:53:08 -06:00
|
|
|
|
|
|
|
ret:
|
|
|
|
for(lr=nn; lr; lr=lr->next)
|
|
|
|
lr->n->typecheck = 1;
|
|
|
|
return nn;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
2009-04-15 23:38:09 -06:00
|
|
|
// generate code for print
|
2009-07-31 10:29:28 -06:00
|
|
|
static Node*
|
2010-01-27 16:37:08 -07:00
|
|
|
walkprint(Node *nn, NodeList **init, int defer)
|
2008-06-04 15:37:38 -06:00
|
|
|
{
|
2009-07-17 02:00:44 -06:00
|
|
|
Node *r;
|
|
|
|
Node *n;
|
2009-07-31 10:29:28 -06:00
|
|
|
NodeList *l, *all;
|
2008-08-12 15:04:03 -06:00
|
|
|
Node *on;
|
2008-06-04 15:37:38 -06:00
|
|
|
Type *t;
|
2009-07-31 10:29:28 -06:00
|
|
|
int notfirst, et, op;
|
2010-01-27 16:37:08 -07:00
|
|
|
NodeList *calls, *intypes, *args;
|
|
|
|
Fmt fmt;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2010-01-27 16:37:08 -07:00
|
|
|
on = nil;
|
2009-07-31 10:29:28 -06:00
|
|
|
op = nn->op;
|
|
|
|
all = nn->list;
|
2009-07-17 02:00:44 -06:00
|
|
|
calls = nil;
|
2008-10-02 15:38:07 -06:00
|
|
|
notfirst = 0;
|
2010-01-27 16:37:08 -07:00
|
|
|
intypes = nil;
|
|
|
|
args = nil;
|
|
|
|
|
|
|
|
memset(&fmt, 0, sizeof fmt);
|
|
|
|
if(defer) {
|
|
|
|
// defer print turns into defer printf with format string
|
|
|
|
fmtstrinit(&fmt);
|
|
|
|
intypes = list(intypes, nod(ODCLFIELD, N, typenod(types[TSTRING])));
|
|
|
|
args = list1(nod(OXXX, N, N));
|
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-07-17 02:00:44 -06:00
|
|
|
for(l=all; l; l=l->next) {
|
2010-01-27 16:37:08 -07:00
|
|
|
if(notfirst) {
|
|
|
|
if(defer)
|
|
|
|
fmtprint(&fmt, " ");
|
|
|
|
else
|
|
|
|
calls = list(calls, mkcall("printsp", T, init));
|
|
|
|
}
|
2010-03-24 17:53:54 -06:00
|
|
|
notfirst = op == OPRINTN;
|
2009-07-17 02:00:44 -06:00
|
|
|
|
|
|
|
n = l->n;
|
|
|
|
if(n->op == OLITERAL) {
|
|
|
|
switch(n->val.ctype) {
|
|
|
|
case CTINT:
|
2009-07-17 14:38:16 -06:00
|
|
|
defaultlit(&n, types[TINT64]);
|
2009-07-17 02:00:44 -06:00
|
|
|
break;
|
|
|
|
case CTFLT:
|
2009-07-17 14:38:16 -06:00
|
|
|
defaultlit(&n, types[TFLOAT64]);
|
2009-07-17 02:00:44 -06:00
|
|
|
break;
|
|
|
|
}
|
2008-12-18 23:17:05 -07:00
|
|
|
}
|
2009-07-30 17:53:08 -06:00
|
|
|
if(n->op != OLITERAL && n->type && n->type->etype == TIDEAL)
|
|
|
|
defaultlit(&n, types[TINT64]);
|
2009-07-27 17:17:09 -06:00
|
|
|
defaultlit(&n, nil);
|
|
|
|
l->n = n;
|
2009-08-03 12:58:52 -06:00
|
|
|
if(n->type == T || n->type->etype == TFORW)
|
2009-07-17 02:00:44 -06:00
|
|
|
continue;
|
2008-07-16 13:44:21 -06:00
|
|
|
|
2010-01-27 16:37:08 -07:00
|
|
|
t = n->type;
|
2009-07-17 02:00:44 -06:00
|
|
|
et = n->type->etype;
|
|
|
|
if(isinter(n->type)) {
|
2010-01-27 16:37:08 -07:00
|
|
|
if(defer) {
|
|
|
|
if(isnilinter(n->type))
|
|
|
|
fmtprint(&fmt, "%%e");
|
|
|
|
else
|
|
|
|
fmtprint(&fmt, "%%i");
|
|
|
|
} else {
|
|
|
|
if(isnilinter(n->type))
|
|
|
|
on = syslook("printeface", 1);
|
|
|
|
else
|
|
|
|
on = syslook("printiface", 1);
|
|
|
|
argtype(on, n->type); // any-1
|
|
|
|
}
|
2009-07-17 02:00:44 -06:00
|
|
|
} else if(isptr[et] || et == TCHAN || et == TMAP || et == TFUNC) {
|
2010-01-27 16:37:08 -07:00
|
|
|
if(defer) {
|
|
|
|
fmtprint(&fmt, "%%p");
|
|
|
|
} else {
|
|
|
|
on = syslook("printpointer", 1);
|
|
|
|
argtype(on, n->type); // any-1
|
|
|
|
}
|
2009-07-17 02:00:44 -06:00
|
|
|
} else if(isslice(n->type)) {
|
2010-01-27 16:37:08 -07:00
|
|
|
if(defer) {
|
|
|
|
fmtprint(&fmt, "%%a");
|
|
|
|
} else {
|
|
|
|
on = syslook("printslice", 1);
|
|
|
|
argtype(on, n->type); // any-1
|
|
|
|
}
|
2009-07-17 02:00:44 -06:00
|
|
|
} else if(isint[et]) {
|
2010-01-27 16:37:08 -07:00
|
|
|
if(defer) {
|
|
|
|
if(et == TUINT64)
|
|
|
|
fmtprint(&fmt, "%%U");
|
|
|
|
else {
|
|
|
|
fmtprint(&fmt, "%%D");
|
|
|
|
t = types[TINT64];
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if(et == TUINT64)
|
|
|
|
on = syslook("printuint", 0);
|
|
|
|
else
|
|
|
|
on = syslook("printint", 0);
|
|
|
|
}
|
2009-07-17 02:00:44 -06:00
|
|
|
} else if(isfloat[et]) {
|
2010-01-27 16:37:08 -07:00
|
|
|
if(defer) {
|
|
|
|
fmtprint(&fmt, "%%f");
|
|
|
|
t = types[TFLOAT64];
|
|
|
|
} else
|
|
|
|
on = syslook("printfloat", 0);
|
2010-02-18 15:46:28 -07:00
|
|
|
} else if(iscomplex[et]) {
|
|
|
|
if(defer) {
|
2010-02-19 21:42:50 -07:00
|
|
|
fmtprint(&fmt, "%%C");
|
2010-02-18 18:55:11 -07:00
|
|
|
t = types[TCOMPLEX128];
|
2010-02-18 15:46:28 -07:00
|
|
|
} else
|
|
|
|
on = syslook("printcomplex", 0);
|
2009-07-17 02:00:44 -06:00
|
|
|
} else if(et == TBOOL) {
|
2010-01-27 16:37:08 -07:00
|
|
|
if(defer)
|
|
|
|
fmtprint(&fmt, "%%t");
|
|
|
|
else
|
|
|
|
on = syslook("printbool", 0);
|
2009-07-17 02:00:44 -06:00
|
|
|
} else if(et == TSTRING) {
|
2010-01-27 16:37:08 -07:00
|
|
|
if(defer)
|
|
|
|
fmtprint(&fmt, "%%S");
|
|
|
|
else
|
|
|
|
on = syslook("printstring", 0);
|
2009-07-17 02:00:44 -06:00
|
|
|
} else {
|
|
|
|
badtype(OPRINT, n->type, T);
|
|
|
|
continue;
|
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2010-01-27 16:37:08 -07:00
|
|
|
if(!defer) {
|
|
|
|
t = *getinarg(on->type);
|
|
|
|
if(t != nil)
|
|
|
|
t = t->type;
|
|
|
|
if(t != nil)
|
|
|
|
t = t->type;
|
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-07-17 02:00:44 -06:00
|
|
|
if(!eqtype(t, n->type)) {
|
|
|
|
n = nod(OCONV, n, N);
|
|
|
|
n->type = t;
|
|
|
|
}
|
2010-02-25 16:11:07 -07:00
|
|
|
|
2010-01-27 16:37:08 -07:00
|
|
|
if(defer) {
|
|
|
|
intypes = list(intypes, nod(ODCLFIELD, N, typenod(t)));
|
|
|
|
args = list(args, n);
|
|
|
|
} else {
|
|
|
|
r = nod(OCALL, on, N);
|
|
|
|
r->list = list1(n);
|
|
|
|
calls = list(calls, r);
|
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
2010-01-27 16:37:08 -07:00
|
|
|
if(defer) {
|
|
|
|
if(op == OPRINTN)
|
|
|
|
fmtprint(&fmt, "\n");
|
|
|
|
on = syslook("printf", 1);
|
|
|
|
on->type = functype(nil, intypes, nil);
|
|
|
|
args->n = nod(OLITERAL, N, N);
|
|
|
|
args->n->val.ctype = CTSTR;
|
|
|
|
args->n->val.u.sval = strlit(fmtstrflush(&fmt));
|
|
|
|
r = nod(OCALL, on, N);
|
|
|
|
r->list = args;
|
|
|
|
typecheck(&r, Etop);
|
|
|
|
walkexpr(&r, init);
|
|
|
|
} else {
|
|
|
|
if(op == OPRINTN)
|
|
|
|
calls = list(calls, mkcall("printnl", T, nil));
|
|
|
|
typechecklist(calls, Etop);
|
|
|
|
walkexprlist(calls, init);
|
2010-02-25 16:11:07 -07:00
|
|
|
|
2010-04-01 23:31:27 -06:00
|
|
|
r = nod(OEMPTY, N, N);
|
2010-01-27 16:37:08 -07:00
|
|
|
typecheck(&r, Etop);
|
|
|
|
walkexpr(&r, init);
|
|
|
|
r->ninit = calls;
|
|
|
|
}
|
2009-07-17 02:00:44 -06:00
|
|
|
return r;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
2009-01-06 15:52:26 -07:00
|
|
|
Node*
|
2009-01-29 18:38:58 -07:00
|
|
|
callnew(Type *t)
|
2009-01-06 15:52:26 -07:00
|
|
|
{
|
2009-07-31 10:29:28 -06:00
|
|
|
Node *fn;
|
2009-01-06 15:52:26 -07:00
|
|
|
|
2009-01-29 18:38:58 -07:00
|
|
|
dowidth(t);
|
2009-07-31 10:29:28 -06:00
|
|
|
fn = syslook("mal", 1);
|
|
|
|
argtype(fn, t);
|
|
|
|
return mkcall1(fn, ptrto(t), nil, nodintconst(t->width));
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
2010-06-14 12:24:51 -06:00
|
|
|
static Node*
|
2009-07-17 02:00:44 -06:00
|
|
|
convas(Node *n, NodeList **init)
|
2008-08-12 20:13:09 -06:00
|
|
|
{
|
2008-06-04 15:37:38 -06:00
|
|
|
Node *l, *r;
|
|
|
|
Type *lt, *rt;
|
|
|
|
|
|
|
|
if(n->op != OAS)
|
2008-06-21 16:11:29 -06:00
|
|
|
fatal("convas: not OAS %O", n->op);
|
2009-08-03 12:58:52 -06:00
|
|
|
n->typecheck = 1;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2008-11-01 17:36:46 -06:00
|
|
|
lt = T;
|
|
|
|
rt = T;
|
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
l = n->left;
|
|
|
|
r = n->right;
|
|
|
|
if(l == N || r == N)
|
2008-09-02 18:12:32 -06:00
|
|
|
goto out;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
|
|
|
lt = l->type;
|
|
|
|
rt = r->type;
|
|
|
|
if(lt == T || rt == T)
|
2008-09-02 18:12:32 -06:00
|
|
|
goto out;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2010-02-18 18:55:11 -07:00
|
|
|
if(isblank(n->left)) {
|
|
|
|
defaultlit(&n->right, T);
|
2009-09-14 19:38:30 -06:00
|
|
|
goto out;
|
2010-02-18 18:55:11 -07:00
|
|
|
}
|
2009-09-14 19:38:30 -06:00
|
|
|
|
2009-08-03 12:58:52 -06:00
|
|
|
if(n->left->op == OINDEXMAP) {
|
2009-08-04 11:26:29 -06:00
|
|
|
n = mkcall1(mapfn("mapassign1", n->left->left->type), T, init,
|
|
|
|
n->left->left, n->left->right, n->right);
|
2008-09-02 18:12:32 -06:00
|
|
|
goto out;
|
2008-06-16 23:34:50 -06:00
|
|
|
}
|
2010-06-08 19:50:02 -06:00
|
|
|
|
2009-05-08 15:40:38 -06:00
|
|
|
if(eqtype(lt, rt))
|
2008-09-02 18:12:32 -06:00
|
|
|
goto out;
|
2010-06-08 19:50:02 -06:00
|
|
|
|
|
|
|
n->right = assignconv(r, lt, "assignment");
|
|
|
|
walkexpr(&n->right, init);
|
2008-08-27 18:28:30 -06:00
|
|
|
|
2008-09-02 18:12:32 -06:00
|
|
|
out:
|
|
|
|
ullmancalc(n);
|
2008-06-04 15:37:38 -06:00
|
|
|
return n;
|
2008-12-05 19:24:05 -07:00
|
|
|
}
|
|
|
|
|
2008-06-24 18:16:06 -06:00
|
|
|
/*
|
|
|
|
* from ascompat[te]
|
|
|
|
* evaluating actual function arguments.
|
|
|
|
* f(a,b)
|
|
|
|
* if there is exactly one function expr,
|
|
|
|
* then it is done first. otherwise must
|
|
|
|
* make temp variables
|
|
|
|
*/
|
2009-07-17 02:00:44 -06:00
|
|
|
NodeList*
|
|
|
|
reorder1(NodeList *all)
|
2008-06-10 22:29:57 -06:00
|
|
|
{
|
2009-07-17 02:00:44 -06:00
|
|
|
Node *f, *a, *n;
|
|
|
|
NodeList *l, *r, *g;
|
2009-12-03 00:54:51 -07:00
|
|
|
int c, d, t;
|
2008-06-10 22:29:57 -06:00
|
|
|
|
|
|
|
c = 0; // function calls
|
|
|
|
t = 0; // total parameters
|
|
|
|
|
2009-07-17 02:00:44 -06:00
|
|
|
for(l=all; l; l=l->next) {
|
|
|
|
n = l->n;
|
|
|
|
t++;
|
|
|
|
ullmancalc(n);
|
|
|
|
if(n->ullman >= UINF)
|
|
|
|
c++;
|
2008-06-10 22:29:57 -06:00
|
|
|
}
|
2009-07-17 02:00:44 -06:00
|
|
|
if(c == 0 || t == 1)
|
|
|
|
return all;
|
2008-06-10 22:29:57 -06:00
|
|
|
|
2009-07-17 02:00:44 -06:00
|
|
|
g = nil; // fncalls assigned to tempnames
|
2009-12-03 00:54:51 -07:00
|
|
|
f = N; // last fncall assigned to stack
|
2009-07-17 02:00:44 -06:00
|
|
|
r = nil; // non fncalls and tempnames assigned to stack
|
2009-12-03 00:54:51 -07:00
|
|
|
d = 0;
|
2009-07-17 02:00:44 -06:00
|
|
|
for(l=all; l; l=l->next) {
|
|
|
|
n = l->n;
|
|
|
|
if(n->ullman < UINF) {
|
|
|
|
r = list(r, n);
|
|
|
|
continue;
|
|
|
|
}
|
2009-12-03 00:54:51 -07:00
|
|
|
d++;
|
|
|
|
if(d == c) {
|
2009-07-17 02:00:44 -06:00
|
|
|
f = n;
|
|
|
|
continue;
|
|
|
|
}
|
2008-06-11 22:06:26 -06:00
|
|
|
|
2009-07-17 02:00:44 -06:00
|
|
|
// make assignment of fncall to tempname
|
|
|
|
a = nod(OXXX, N, N);
|
|
|
|
tempname(a, n->right->type);
|
|
|
|
a = nod(OAS, a, n->right);
|
|
|
|
g = list(g, a);
|
|
|
|
|
|
|
|
// put normal arg assignment on list
|
|
|
|
// with fncall replaced by tempname
|
|
|
|
n->right = a->left;
|
|
|
|
r = list(r, n);
|
|
|
|
}
|
2008-06-10 22:29:57 -06:00
|
|
|
|
2009-07-17 02:00:44 -06:00
|
|
|
if(f != N)
|
|
|
|
g = list(g, f);
|
|
|
|
return concat(g, r);
|
2008-06-10 22:29:57 -06:00
|
|
|
}
|
|
|
|
|
2008-06-24 18:16:06 -06:00
|
|
|
/*
|
|
|
|
* from ascompat[ee]
|
|
|
|
* a,b = c,d
|
2008-06-25 12:35:06 -06:00
|
|
|
* simultaneous assignment. there cannot
|
|
|
|
* be later use of an earlier lvalue.
|
2008-06-24 18:16:06 -06:00
|
|
|
*/
|
2009-08-07 17:47:54 -06:00
|
|
|
|
2010-06-14 12:24:51 -06:00
|
|
|
static int
|
2008-06-25 12:35:06 -06:00
|
|
|
vmatch2(Node *l, Node *r)
|
2008-06-24 18:16:06 -06:00
|
|
|
{
|
2009-07-17 02:00:44 -06:00
|
|
|
NodeList *ll;
|
2008-06-25 12:35:06 -06:00
|
|
|
|
|
|
|
/*
|
|
|
|
* isolate all right sides
|
|
|
|
*/
|
|
|
|
if(r == N)
|
|
|
|
return 0;
|
|
|
|
switch(r->op) {
|
|
|
|
case ONAME:
|
|
|
|
// match each right given left
|
|
|
|
if(l == r)
|
|
|
|
return 1;
|
|
|
|
case OLITERAL:
|
|
|
|
return 0;
|
|
|
|
}
|
2009-07-17 02:00:44 -06:00
|
|
|
if(vmatch2(l, r->left))
|
|
|
|
return 1;
|
2008-06-25 12:35:06 -06:00
|
|
|
if(vmatch2(l, r->right))
|
|
|
|
return 1;
|
2009-07-17 02:00:44 -06:00
|
|
|
for(ll=r->list; ll; ll=ll->next)
|
|
|
|
if(vmatch2(l, ll->n))
|
|
|
|
return 1;
|
|
|
|
return 0;
|
2008-06-25 12:35:06 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
vmatch1(Node *l, Node *r)
|
|
|
|
{
|
2009-07-17 02:00:44 -06:00
|
|
|
NodeList *ll;
|
2008-06-25 12:35:06 -06:00
|
|
|
|
|
|
|
/*
|
|
|
|
* isolate all left sides
|
|
|
|
*/
|
2009-11-15 13:57:09 -07:00
|
|
|
if(l == N || r == N)
|
2008-06-25 12:35:06 -06:00
|
|
|
return 0;
|
|
|
|
switch(l->op) {
|
|
|
|
case ONAME:
|
2009-08-07 17:47:54 -06:00
|
|
|
switch(l->class) {
|
|
|
|
case PPARAM:
|
|
|
|
case PPARAMREF:
|
|
|
|
case PAUTO:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// assignment to non-stack variable
|
|
|
|
// must be delayed if right has function calls.
|
|
|
|
if(r->ullman >= UINF)
|
|
|
|
return 1;
|
|
|
|
break;
|
|
|
|
}
|
2008-06-25 12:35:06 -06:00
|
|
|
return vmatch2(l, r);
|
|
|
|
case OLITERAL:
|
|
|
|
return 0;
|
|
|
|
}
|
2009-07-17 02:00:44 -06:00
|
|
|
if(vmatch1(l->left, r))
|
|
|
|
return 1;
|
2008-06-25 12:35:06 -06:00
|
|
|
if(vmatch1(l->right, r))
|
|
|
|
return 1;
|
2009-07-17 02:00:44 -06:00
|
|
|
for(ll=l->list; ll; ll=ll->next)
|
|
|
|
if(vmatch1(ll->n, r))
|
|
|
|
return 1;
|
|
|
|
return 0;
|
2008-06-24 18:16:06 -06:00
|
|
|
}
|
|
|
|
|
2009-07-17 02:00:44 -06:00
|
|
|
NodeList*
|
|
|
|
reorder3(NodeList *all)
|
2008-06-10 22:29:57 -06:00
|
|
|
{
|
2009-07-17 02:00:44 -06:00
|
|
|
Node *n1, *n2, *q;
|
2008-06-24 18:16:06 -06:00
|
|
|
int c1, c2;
|
2009-07-17 02:00:44 -06:00
|
|
|
NodeList *l1, *l2, *r;
|
2008-06-24 18:16:06 -06:00
|
|
|
|
2009-07-17 02:00:44 -06:00
|
|
|
r = nil;
|
|
|
|
for(l1=all, c1=0; l1; l1=l1->next, c1++) {
|
|
|
|
n1 = l1->n;
|
|
|
|
for(l2=all, c2=0; l2; l2=l2->next, c2++) {
|
|
|
|
n2 = l2->n;
|
2008-06-24 18:16:06 -06:00
|
|
|
if(c2 > c1) {
|
2009-07-17 02:00:44 -06:00
|
|
|
if(vmatch1(n1->left, n2->right)) {
|
2009-08-07 17:47:54 -06:00
|
|
|
// delay assignment to n1->left
|
2008-06-25 12:35:06 -06:00
|
|
|
q = nod(OXXX, N, N);
|
2009-07-17 02:00:44 -06:00
|
|
|
tempname(q, n1->right->type);
|
|
|
|
q = nod(OAS, n1->left, q);
|
|
|
|
n1->left = q->right;
|
2008-09-27 18:46:40 -06:00
|
|
|
r = list(r, q);
|
2008-06-25 12:35:06 -06:00
|
|
|
break;
|
2008-06-24 18:16:06 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-06-25 12:35:06 -06:00
|
|
|
}
|
2009-07-17 02:00:44 -06:00
|
|
|
return concat(all, r);
|
2008-06-10 22:29:57 -06:00
|
|
|
}
|
|
|
|
|
2009-01-29 18:38:58 -07:00
|
|
|
/*
|
|
|
|
* walk through argin parameters.
|
|
|
|
* generate and return code to allocate
|
|
|
|
* copies of escaped parameters to the heap.
|
|
|
|
*/
|
2010-06-14 12:24:51 -06:00
|
|
|
static NodeList*
|
2010-04-12 15:28:27 -06:00
|
|
|
paramstoheap(Type **argin, int out)
|
2009-01-29 18:38:58 -07:00
|
|
|
{
|
|
|
|
Type *t;
|
|
|
|
Iter savet;
|
2009-07-17 02:00:44 -06:00
|
|
|
Node *v;
|
|
|
|
NodeList *nn;
|
2009-01-29 18:38:58 -07:00
|
|
|
|
2009-07-17 02:00:44 -06:00
|
|
|
nn = nil;
|
2009-01-29 18:38:58 -07:00
|
|
|
for(t = structfirst(&savet, argin); t != T; t = structnext(&savet)) {
|
2009-02-06 14:47:10 -07:00
|
|
|
v = t->nname;
|
2010-04-12 15:28:27 -06:00
|
|
|
if(v == N && out && hasdefer) {
|
|
|
|
// Defer might stop a panic and show the
|
|
|
|
// return values as they exist at the time of panic.
|
|
|
|
// Make sure to zero them on entry to the function.
|
|
|
|
nn = list(nn, nod(OAS, nodarg(t, 1), N));
|
|
|
|
}
|
2009-01-29 18:38:58 -07:00
|
|
|
if(v == N || !(v->class & PHEAP))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// generate allocation & copying code
|
2010-02-01 17:22:16 -07:00
|
|
|
if(v->alloc == nil)
|
|
|
|
v->alloc = callnew(v->type);
|
2009-01-29 18:38:58 -07:00
|
|
|
nn = list(nn, nod(OAS, v->heapaddr, v->alloc));
|
2010-03-26 19:01:02 -06:00
|
|
|
if((v->class & ~PHEAP) != PPARAMOUT)
|
|
|
|
nn = list(nn, nod(OAS, v, v->stackparam));
|
|
|
|
}
|
|
|
|
return nn;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* walk through argout parameters copying back to stack
|
|
|
|
*/
|
2010-06-14 12:24:51 -06:00
|
|
|
static NodeList*
|
2010-03-26 19:01:02 -06:00
|
|
|
returnsfromheap(Type **argin)
|
|
|
|
{
|
|
|
|
Type *t;
|
|
|
|
Iter savet;
|
|
|
|
Node *v;
|
|
|
|
NodeList *nn;
|
|
|
|
|
|
|
|
nn = nil;
|
|
|
|
for(t = structfirst(&savet, argin); t != T; t = structnext(&savet)) {
|
|
|
|
v = t->nname;
|
|
|
|
if(v == N || v->class != (PHEAP|PPARAMOUT))
|
|
|
|
continue;
|
|
|
|
nn = list(nn, nod(OAS, v->stackparam, v));
|
2009-01-29 18:38:58 -07:00
|
|
|
}
|
|
|
|
return nn;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* take care of migrating any function in/out args
|
|
|
|
* between the stack and the heap. adds code to
|
|
|
|
* curfn's before and after lists.
|
|
|
|
*/
|
2010-06-14 12:24:51 -06:00
|
|
|
static void
|
2009-01-29 18:38:58 -07:00
|
|
|
heapmoves(void)
|
|
|
|
{
|
2009-07-17 02:00:44 -06:00
|
|
|
NodeList *nn;
|
2010-09-10 09:53:27 -06:00
|
|
|
int32 lno;
|
|
|
|
|
|
|
|
lno = lineno;
|
|
|
|
lineno = curfn->lineno;
|
2010-04-12 15:28:27 -06:00
|
|
|
nn = paramstoheap(getthis(curfn->type), 0);
|
|
|
|
nn = concat(nn, paramstoheap(getinarg(curfn->type), 0));
|
|
|
|
nn = concat(nn, paramstoheap(getoutarg(curfn->type), 1));
|
2009-07-17 02:00:44 -06:00
|
|
|
curfn->enter = concat(curfn->enter, nn);
|
2010-09-10 09:53:27 -06:00
|
|
|
lineno = curfn->endlineno;
|
2010-03-26 19:01:02 -06:00
|
|
|
curfn->exit = returnsfromheap(getoutarg(curfn->type));
|
2010-09-10 09:53:27 -06:00
|
|
|
lineno = lno;
|
2009-01-29 18:38:58 -07:00
|
|
|
}
|
2009-07-31 10:29:28 -06:00
|
|
|
|
|
|
|
static Node*
|
|
|
|
vmkcall(Node *fn, Type *t, NodeList **init, va_list va)
|
|
|
|
{
|
|
|
|
int i, n;
|
|
|
|
Node *r;
|
|
|
|
NodeList *args;
|
|
|
|
|
|
|
|
if(fn->type == T || fn->type->etype != TFUNC)
|
|
|
|
fatal("mkcall %#N %T", fn, fn->type);
|
|
|
|
|
|
|
|
args = nil;
|
|
|
|
n = fn->type->intuple;
|
|
|
|
for(i=0; i<n; i++)
|
|
|
|
args = list(args, va_arg(va, Node*));
|
2009-08-03 12:58:52 -06:00
|
|
|
|
2009-07-31 10:29:28 -06:00
|
|
|
r = nod(OCALL, fn, N);
|
|
|
|
r->list = args;
|
|
|
|
if(fn->type->outtuple > 0)
|
2009-08-05 01:42:44 -06:00
|
|
|
typecheck(&r, Erv | Efnstruct);
|
2009-07-31 10:29:28 -06:00
|
|
|
else
|
|
|
|
typecheck(&r, Etop);
|
|
|
|
walkexpr(&r, init);
|
|
|
|
r->type = t;
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2009-08-04 13:57:48 -06:00
|
|
|
Node*
|
2009-07-31 10:29:28 -06:00
|
|
|
mkcall(char *name, Type *t, NodeList **init, ...)
|
|
|
|
{
|
|
|
|
Node *r;
|
|
|
|
va_list va;
|
2009-08-03 12:58:52 -06:00
|
|
|
|
2009-07-31 10:29:28 -06:00
|
|
|
va_start(va, init);
|
|
|
|
r = vmkcall(syslook(name, 0), t, init, va);
|
|
|
|
va_end(va);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2009-08-04 13:57:48 -06:00
|
|
|
Node*
|
2009-07-31 10:29:28 -06:00
|
|
|
mkcall1(Node *fn, Type *t, NodeList **init, ...)
|
|
|
|
{
|
|
|
|
Node *r;
|
|
|
|
va_list va;
|
2009-08-03 12:58:52 -06:00
|
|
|
|
2009-07-31 10:29:28 -06:00
|
|
|
va_start(va, init);
|
|
|
|
r = vmkcall(fn, t, init, va);
|
|
|
|
va_end(va);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Node*
|
|
|
|
conv(Node *n, Type *t)
|
|
|
|
{
|
|
|
|
if(eqtype(n->type, t))
|
|
|
|
return n;
|
|
|
|
n = nod(OCONV, n, N);
|
|
|
|
n->type = t;
|
|
|
|
typecheck(&n, Erv);
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2009-08-04 13:57:48 -06:00
|
|
|
Node*
|
2009-07-31 10:29:28 -06:00
|
|
|
chanfn(char *name, int n, Type *t)
|
|
|
|
{
|
|
|
|
Node *fn;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if(t->etype != TCHAN)
|
|
|
|
fatal("chanfn %T", t);
|
|
|
|
fn = syslook(name, 1);
|
|
|
|
for(i=0; i<n; i++)
|
|
|
|
argtype(fn, t->type);
|
|
|
|
return fn;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Node*
|
|
|
|
mapfn(char *name, Type *t)
|
|
|
|
{
|
|
|
|
Node *fn;
|
|
|
|
|
|
|
|
if(t->etype != TMAP)
|
|
|
|
fatal("mapfn %T", t);
|
|
|
|
fn = syslook(name, 1);
|
|
|
|
argtype(fn, t->down);
|
|
|
|
argtype(fn, t->type);
|
|
|
|
argtype(fn, t->down);
|
|
|
|
argtype(fn, t->type);
|
|
|
|
return fn;
|
|
|
|
}
|
2010-09-11 22:53:04 -06:00
|
|
|
|
|
|
|
static Node*
|
|
|
|
addstr(Node *n, NodeList **init)
|
|
|
|
{
|
|
|
|
Node *r, *cat, *typstr;
|
|
|
|
NodeList *in, *args;
|
|
|
|
int i, count;
|
|
|
|
|
|
|
|
count = 0;
|
|
|
|
for(r=n; r->op == OADDSTR; r=r->left)
|
|
|
|
count++; // r->right
|
|
|
|
count++; // r
|
|
|
|
|
|
|
|
// prepare call of runtime.catstring of type int, string, string, string
|
|
|
|
// with as many strings as we have.
|
|
|
|
cat = syslook("concatstring", 1);
|
|
|
|
cat->type = T;
|
|
|
|
cat->ntype = nod(OTFUNC, N, N);
|
|
|
|
in = list1(nod(ODCLFIELD, N, typenod(types[TINT]))); // count
|
|
|
|
typstr = typenod(types[TSTRING]);
|
|
|
|
for(i=0; i<count; i++)
|
|
|
|
in = list(in, nod(ODCLFIELD, N, typstr));
|
|
|
|
cat->ntype->list = in;
|
|
|
|
cat->ntype->rlist = list1(nod(ODCLFIELD, N, typstr));
|
|
|
|
|
|
|
|
args = nil;
|
|
|
|
for(r=n; r->op == OADDSTR; r=r->left)
|
|
|
|
args = concat(list1(conv(r->right, types[TSTRING])), args);
|
|
|
|
args = concat(list1(conv(r, types[TSTRING])), args);
|
|
|
|
args = concat(list1(nodintconst(count)), args);
|
|
|
|
|
|
|
|
r = nod(OCALL, cat, N);
|
|
|
|
r->list = args;
|
|
|
|
typecheck(&r, Erv);
|
|
|
|
walkexpr(&r, init);
|
|
|
|
r->type = n->type;
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|