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"
|
|
|
|
|
2009-08-03 12:58:52 -06:00
|
|
|
static Node* walkprint(Node*, NodeList**);
|
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**);
|
2008-09-22 13:16:19 -06:00
|
|
|
enum
|
|
|
|
{
|
|
|
|
Inone,
|
|
|
|
I2T,
|
2008-11-05 15:27:07 -07:00
|
|
|
I2T2,
|
2008-09-22 13:16:19 -06:00
|
|
|
I2I,
|
2009-05-20 19:23:19 -06:00
|
|
|
I2Ix,
|
2008-11-05 15:27:07 -07:00
|
|
|
I2I2,
|
|
|
|
T2I,
|
2009-01-27 19:21:03 -07:00
|
|
|
I2Isame,
|
2009-05-20 15:57:55 -06:00
|
|
|
E2T,
|
|
|
|
E2T2,
|
|
|
|
E2I,
|
|
|
|
E2I2,
|
|
|
|
I2E,
|
|
|
|
I2E2,
|
|
|
|
T2E,
|
|
|
|
E2Esame,
|
2008-09-22 13:16:19 -06:00
|
|
|
};
|
|
|
|
|
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
|
|
|
|
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:
|
|
|
|
return 0;
|
2009-07-14 00:38:39 -06:00
|
|
|
|
|
|
|
case OCALL:
|
|
|
|
if(n->left->op == ONAME) {
|
|
|
|
switch(n->left->etype) {
|
|
|
|
case OPANIC:
|
|
|
|
case OPANICN:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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];
|
|
|
|
|
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-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
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-07-29 13:00:34 -06:00
|
|
|
gettype(Node **np, NodeList **init)
|
2008-09-09 16:47:31 -06:00
|
|
|
{
|
|
|
|
if(debug['W'])
|
2009-07-29 13:00:34 -06:00
|
|
|
dump("\nbefore gettype", *np);
|
2009-07-30 17:53:08 -06:00
|
|
|
typecheck(np, Erv);
|
2008-06-17 23:33:32 -06:00
|
|
|
if(debug['W'])
|
2009-07-29 13:00:34 -06:00
|
|
|
dump("after gettype", *np);
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
2009-07-17 14:38:16 -06:00
|
|
|
void
|
|
|
|
walkdeflist(NodeList *l)
|
|
|
|
{
|
|
|
|
for(; l; l=l->next)
|
|
|
|
walkdef(l->n);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
walkdef(Node *n)
|
|
|
|
{
|
|
|
|
int lno;
|
|
|
|
NodeList *init;
|
|
|
|
Node *e;
|
|
|
|
Type *t;
|
|
|
|
|
|
|
|
lno = lineno;
|
|
|
|
setlineno(n);
|
|
|
|
|
|
|
|
if(n->op == ONONAME) {
|
|
|
|
if(!n->diag) {
|
|
|
|
n->diag = 1;
|
|
|
|
yyerror("undefined: %S", n->sym);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-07-29 13:00:34 -06:00
|
|
|
if(n->walkdef == 1)
|
2009-07-17 14:38:16 -06:00
|
|
|
return;
|
2009-07-29 13:00:34 -06:00
|
|
|
if(n->walkdef == 2) {
|
2009-07-17 14:38:16 -06:00
|
|
|
// TODO(rsc): better loop message
|
|
|
|
fatal("loop");
|
|
|
|
}
|
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) {
|
|
|
|
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-07-30 17:53:08 -06:00
|
|
|
typecheck(&e, Erv);
|
2009-07-17 14:38:16 -06:00
|
|
|
if(e->op != OLITERAL) {
|
|
|
|
yyerror("const initializer must be constant");
|
|
|
|
goto ret;
|
|
|
|
}
|
|
|
|
t = n->type;
|
|
|
|
if(t != T)
|
|
|
|
convlit(&e, t);
|
|
|
|
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;
|
|
|
|
if(n->defn == N)
|
|
|
|
fatal("var without type, init: %S", n->sym);
|
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-07-17 14:38:16 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
ret:
|
|
|
|
lineno = lno;
|
2009-07-29 13:00:34 -06:00
|
|
|
n->walkdef = 1;
|
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
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
NodeList *ll;
|
2009-07-10 17:29:26 -06:00
|
|
|
int lno;
|
2009-07-29 13:00:34 -06:00
|
|
|
Node *n;
|
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
|
|
|
|
2009-08-03 12:58:52 -06:00
|
|
|
case OAPPENDSTR:
|
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:
|
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:
|
2008-10-02 15:38:07 -06:00
|
|
|
case OPANICN:
|
2008-09-04 13:21:10 -06:00
|
|
|
case OEMPTY:
|
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-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;
|
2009-07-31 10:29:28 -06:00
|
|
|
walkexpr(&n->left, &n->ninit);
|
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-04 11:26:29 -06:00
|
|
|
walkexpr(&n->ntest, &n->ntest->ninit);
|
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-08-04 11:26:29 -06:00
|
|
|
walkexpr(&n->ntest, &n->ntest->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);
|
2009-07-17 02:00:44 -06:00
|
|
|
if(curfn->type->outnamed && n->list == nil) {
|
2009-07-10 17:29:26 -06:00
|
|
|
// print("special return\n");
|
|
|
|
break;
|
|
|
|
}
|
2009-07-17 02:00:44 -06:00
|
|
|
ll = ascompatte(n->op, getoutarg(curfn->type), n->list, 1, &n->ninit);
|
|
|
|
n->list = reorder4(ll);
|
2009-07-10 17:29:26 -06:00
|
|
|
break;
|
|
|
|
|
|
|
|
case OSELECT:
|
|
|
|
walkselect(n);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OSWITCH:
|
|
|
|
walkswitch(n);
|
|
|
|
break;
|
|
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-07-31 10:29:28 -06:00
|
|
|
walkexpr(Node **np, NodeList **init)
|
2009-07-29 13:47:51 -06:00
|
|
|
{
|
|
|
|
Node *r, *l;
|
|
|
|
NodeList *ll, *lr;
|
|
|
|
Type *t;
|
2009-08-04 11:26:29 -06:00
|
|
|
int et;
|
2009-07-29 13:47:51 -06:00
|
|
|
int32 lno;
|
2009-08-03 12:58:52 -06:00
|
|
|
Node *n, *fn;
|
2009-07-29 13:47:51 -06:00
|
|
|
|
|
|
|
n = *np;
|
|
|
|
|
|
|
|
if(n == N)
|
|
|
|
return;
|
|
|
|
|
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:
|
|
|
|
case OLEN:
|
|
|
|
case OCAP:
|
|
|
|
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
|
|
|
|
2009-07-31 10:29:28 -06:00
|
|
|
case OLSH:
|
|
|
|
case ORSH:
|
|
|
|
case OAND:
|
|
|
|
case OOR:
|
|
|
|
case OXOR:
|
|
|
|
case OANDAND:
|
|
|
|
case OOROR:
|
|
|
|
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:
|
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;
|
|
|
|
|
2009-07-31 10:29:28 -06:00
|
|
|
case OPRINT:
|
2008-10-02 15:38:07 -06:00
|
|
|
case OPRINTN:
|
2008-06-04 15:37:38 -06:00
|
|
|
case OPANIC:
|
2008-10-02 15:38:07 -06:00
|
|
|
case OPANICN:
|
2009-07-31 10:29:28 -06:00
|
|
|
walkexprlist(n->list, init);
|
2009-08-03 12:58:52 -06:00
|
|
|
n = walkprint(n, init);
|
2008-06-04 15:37:38 -06:00
|
|
|
goto ret;
|
|
|
|
|
|
|
|
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);
|
|
|
|
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);
|
2009-08-03 12:58:52 -06:00
|
|
|
ll = ascompatte(n->op, getinarg(t), n->list, 0, init);
|
|
|
|
lr = ascompatte(n->op, getthis(t), list1(n->left->left), 0, init);
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
if(r != N)
|
|
|
|
n = r;
|
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:
|
2009-08-04 11:26:29 -06:00
|
|
|
as2:
|
2009-07-17 02:00:44 -06:00
|
|
|
*init = concat(*init, n->ninit);
|
|
|
|
n->ninit = nil;
|
2009-08-04 11:26:29 -06:00
|
|
|
walkexprlist(n->list, init);
|
|
|
|
walkexprlist(n->rlist, init);
|
|
|
|
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;
|
2009-07-31 10:29:28 -06:00
|
|
|
walkexprlist(n->list, init);
|
2009-08-04 11:26:29 -06:00
|
|
|
walkexpr(&r, init);
|
|
|
|
ll = ascompatet(n->op, n->list, &r->type, 0, init);
|
|
|
|
n = liststmt(concat(list1(r), ll));
|
|
|
|
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;
|
|
|
|
walkexprlist(n->list, init);
|
|
|
|
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;
|
2009-08-04 11:26:29 -06:00
|
|
|
walkexprlist(n->list, init);
|
|
|
|
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;
|
|
|
|
walkexprlist(n->list, init);
|
|
|
|
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;
|
|
|
|
walkexprlist(n->list, init);
|
|
|
|
walkdottype(r, init);
|
|
|
|
et = ifaceas1(r->type, r->left->type, 1);
|
|
|
|
switch(et) {
|
|
|
|
case I2Isame:
|
|
|
|
case E2Esame:
|
|
|
|
n->rlist = list(list1(r->left), nodbool(1));
|
|
|
|
typechecklist(n->rlist, Erv);
|
|
|
|
goto as2;
|
|
|
|
case I2E:
|
|
|
|
n->list = list(list1(n->right), nodbool(1));
|
|
|
|
typechecklist(n->rlist, Erv);
|
|
|
|
goto as2;
|
|
|
|
case I2T:
|
|
|
|
et = I2T2;
|
2008-06-22 22:02:06 -06:00
|
|
|
break;
|
2009-08-04 11:26:29 -06:00
|
|
|
case I2Ix:
|
|
|
|
et = I2I2;
|
2008-06-24 15:11:20 -06:00
|
|
|
break;
|
2009-08-04 11:26:29 -06:00
|
|
|
case E2I:
|
|
|
|
et = E2I2;
|
2008-07-13 15:29:46 -06:00
|
|
|
break;
|
2009-08-04 11:26:29 -06:00
|
|
|
case E2T:
|
|
|
|
et = E2T2;
|
2008-11-05 15:27:07 -07:00
|
|
|
break;
|
2009-08-04 11:26:29 -06:00
|
|
|
default:
|
|
|
|
et = Inone;
|
2008-06-22 22:02:06 -06:00
|
|
|
break;
|
|
|
|
}
|
2009-08-04 11:26:29 -06:00
|
|
|
if(et == Inone)
|
|
|
|
break;
|
|
|
|
r = ifacecvt(r->type, r->left, et, init);
|
|
|
|
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:
|
2009-07-14 00:38:39 -06:00
|
|
|
walkdottype(n, init);
|
2009-07-29 13:00:34 -06:00
|
|
|
walkconv(&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:
|
|
|
|
walkexpr(&n->left, init);
|
2008-06-04 15:37:38 -06:00
|
|
|
goto ret;
|
|
|
|
|
|
|
|
case OASOP:
|
2009-07-31 10:29:28 -06:00
|
|
|
walkexpr(&n->left, init);
|
2008-08-10 17:49:01 -06:00
|
|
|
l = n->left;
|
2009-08-03 12:58:52 -06:00
|
|
|
if(l->op == OINDEXMAP)
|
2009-07-31 10:29:28 -06:00
|
|
|
n = mapop(n, init);
|
|
|
|
walkexpr(&n->right, init);
|
|
|
|
if(n->etype == OANDNOT) {
|
|
|
|
n->etype = OAND;
|
|
|
|
n->right = nod(OCOM, n->right, N);
|
|
|
|
n->right->type = n->right->left->type;
|
2008-08-28 20:59:42 -06:00
|
|
|
goto ret;
|
2009-07-31 10:29:28 -06:00
|
|
|
}
|
2009-08-03 12:58:52 -06:00
|
|
|
|
2009-07-31 10:29:28 -06:00
|
|
|
/*
|
|
|
|
* on 32-bit arch, rewrite 64-bit ops into l = l op r
|
|
|
|
*/
|
|
|
|
et = n->left->type->etype;
|
|
|
|
if(widthptr == 4 && (et == TUINT64 || et == TINT64)) {
|
|
|
|
l = saferef(n->left, init);
|
|
|
|
r = nod(OAS, l, nod(n->etype, l, n->right));
|
|
|
|
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);
|
|
|
|
n->right->type = n->right->left->type;
|
|
|
|
goto ret;
|
|
|
|
|
|
|
|
case ODIV:
|
|
|
|
case OMOD:
|
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
|
|
|
walkexpr(&n->left, init);
|
|
|
|
walkexpr(&n->right, init);
|
|
|
|
et = n->left->type->etype;
|
|
|
|
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);
|
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:
|
2009-07-31 10:29:28 -06:00
|
|
|
walkexpr(&n->left, init);
|
|
|
|
walkexpr(&n->right->left, init);
|
|
|
|
walkexpr(&n->right->right, init);
|
2009-08-03 12:58:52 -06:00
|
|
|
// dynamic slice
|
|
|
|
// arraysliced(old []any, lb int, hb int, width int) (ary []any)
|
|
|
|
t = n->type;
|
|
|
|
fn = syslook("arraysliced", 1);
|
|
|
|
argtype(fn, t->type); // any-1
|
|
|
|
argtype(fn, t->type); // any-2
|
|
|
|
n = mkcall1(fn, t, init,
|
|
|
|
n->left,
|
|
|
|
conv(n->right->left, types[TINT]),
|
|
|
|
conv(n->right->right, types[TINT]),
|
|
|
|
nodintconst(t->type->width));
|
|
|
|
goto ret;
|
|
|
|
|
|
|
|
case OSLICEARR:
|
|
|
|
walkexpr(&n->left, init);
|
|
|
|
walkexpr(&n->right->left, init);
|
|
|
|
walkexpr(&n->right->right, init);
|
|
|
|
// static slice
|
|
|
|
// arrayslices(old *any, nel int, lb int, hb int, width int) (ary []any)
|
|
|
|
t = n->type;
|
|
|
|
fn = syslook("arrayslices", 1);
|
|
|
|
argtype(fn, n->left->type); // any-1
|
|
|
|
argtype(fn, t->type); // any-2
|
|
|
|
n = mkcall1(fn, t, init,
|
|
|
|
nod(OADDR, n->left, N), nodintconst(t->bound),
|
|
|
|
conv(n->right->left, types[TINT]),
|
|
|
|
conv(n->right->right, types[TINT]),
|
|
|
|
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:
|
|
|
|
nvar = makenewvar(n->type, init, &nstar);
|
|
|
|
arraylit(n->left, nstar, init);
|
|
|
|
n = nvar;
|
2008-09-04 18:15:15 -06:00
|
|
|
goto ret;
|
2009-08-03 12:58:52 -06:00
|
|
|
|
|
|
|
case OMAPLIT:
|
|
|
|
nvar = makenewvar(n->type, init, &nstar);
|
|
|
|
maplit(n->left, nstar, init);
|
|
|
|
n = nvar;
|
2008-06-04 15:37:38 -06:00
|
|
|
goto ret;
|
2009-08-03 12:58:52 -06:00
|
|
|
|
|
|
|
|
|
|
|
case OSTRUCTLIT:
|
|
|
|
nvar = makenewvar(n->type, init, &nstar);
|
|
|
|
structlit(n->left, nstar, init);
|
|
|
|
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:
|
|
|
|
// 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));
|
|
|
|
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:
|
|
|
|
// sys_catstring(s1, s2)
|
|
|
|
n = mkcall("catstring", n->type, init,
|
|
|
|
conv(n->left, types[TSTRING]),
|
|
|
|
conv(n->right, types[TSTRING]));
|
|
|
|
goto ret;
|
2008-10-21 17:53:54 -06:00
|
|
|
|
2009-08-03 12:58:52 -06:00
|
|
|
case OAPPENDSTR:
|
|
|
|
// s1 = sys_catstring(s1, s2)
|
|
|
|
if(n->etype != OADD)
|
|
|
|
fatal("walkasopstring: not add");
|
|
|
|
r = mkcall("catstring", n->left->type, init,
|
|
|
|
conv(n->left, types[TSTRING]),
|
|
|
|
conv(n->right, types[TSTRING]));
|
|
|
|
r = nod(OAS, n->left, r);
|
|
|
|
n = r;
|
|
|
|
goto ret;
|
2008-11-05 12:27:50 -07:00
|
|
|
|
2009-08-03 12:58:52 -06:00
|
|
|
case OSLICESTR:
|
|
|
|
// sys_slicestring(s, lb, hb)
|
|
|
|
n = mkcall("slicestring", n->type, init,
|
|
|
|
conv(n->left, types[TSTRING]),
|
|
|
|
conv(n->right->left, types[TINT]),
|
|
|
|
conv(n->right->right, types[TINT]));
|
|
|
|
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-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:
|
|
|
|
n = mkcall1(chanfn("newchan", 1, n->type), n->type, init,
|
|
|
|
nodintconst(n->type->type->width),
|
|
|
|
nodintconst(algtype(n->type->type)),
|
|
|
|
conv(n->left, types[TINT]));
|
2008-06-04 15:37:38 -06:00
|
|
|
goto ret;
|
|
|
|
|
2009-08-03 12:58:52 -06:00
|
|
|
case OMAKEMAP:
|
|
|
|
t = n->type;
|
|
|
|
|
|
|
|
fn = syslook("newmap", 1);
|
|
|
|
argtype(fn, t->down); // any-1
|
|
|
|
argtype(fn, t->type); // any-2
|
|
|
|
|
|
|
|
n = mkcall1(fn, n->type, init,
|
|
|
|
nodintconst(t->down->width), // key width
|
|
|
|
nodintconst(t->type->width), // val width
|
|
|
|
nodintconst(algtype(t->down)), // key algorithm
|
|
|
|
nodintconst(algtype(t->type)), // val algorithm
|
|
|
|
conv(n->left, types[TINT]));
|
2009-01-06 15:52:26 -07:00
|
|
|
goto ret;
|
|
|
|
|
2009-08-03 12:58:52 -06:00
|
|
|
case OMAKESLICE:
|
|
|
|
// newarray(nel int, max int, width int) (ary []any)
|
|
|
|
t = n->type;
|
|
|
|
fn = syslook("newarray", 1);
|
|
|
|
argtype(fn, t->type); // any-1
|
|
|
|
n = mkcall1(fn, n->type, nil,
|
|
|
|
conv(n->left, types[TINT]),
|
|
|
|
conv(n->right, types[TINT]),
|
|
|
|
nodintconst(t->type->width));
|
|
|
|
goto ret;
|
|
|
|
|
|
|
|
case ORUNESTR:
|
|
|
|
// sys_intstring(v)
|
|
|
|
n = mkcall("intstring", n->type, init, conv(n->left, types[TINT64])); // TODO(rsc): int64?!
|
|
|
|
goto ret;
|
|
|
|
|
|
|
|
case OARRAYBYTESTR:
|
|
|
|
// arraystring([]byte) string;
|
|
|
|
n = mkcall("arraystring", n->type, init, n->left);
|
|
|
|
goto ret;
|
|
|
|
|
|
|
|
case OARRAYRUNESTR:
|
|
|
|
// arraystring([]byte) string;
|
|
|
|
n = mkcall("arraystringi", n->type, init, n->left);
|
|
|
|
goto ret;
|
|
|
|
|
|
|
|
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:
|
|
|
|
n = arraylit(n, N, init);
|
|
|
|
goto ret;
|
|
|
|
|
|
|
|
case OMAPLIT:
|
|
|
|
n = maplit(n, N, init);
|
|
|
|
goto ret;
|
|
|
|
|
|
|
|
case OSTRUCTLIT:
|
|
|
|
n = structlit(n, N, init);
|
|
|
|
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;
|
|
|
|
|
|
|
|
case OCONVIFACE:
|
|
|
|
walkexpr(&n->left, init);
|
|
|
|
n = ifacecvt(n->type, n->left, n->etype, init);
|
|
|
|
goto ret;
|
|
|
|
|
|
|
|
case OCONVSLICE:
|
|
|
|
// arrays2d(old *any, nel int) (ary []any)
|
|
|
|
fn = syslook("arrays2d", 1);
|
|
|
|
argtype(fn, n->left->type->type); // any-1
|
|
|
|
argtype(fn, n->type->type); // any-2
|
|
|
|
n = mkcall1(fn, n->type, init, n->left, nodintconst(n->left->type->type->bound));
|
2008-06-04 15:37:38 -06:00
|
|
|
goto ret;
|
|
|
|
}
|
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-08-03 12:58:52 -06:00
|
|
|
Node*
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-08-04 13:57:48 -06:00
|
|
|
// TODO(rsc): cut
|
2009-07-14 00:38:39 -06:00
|
|
|
void
|
2009-07-17 02:00:44 -06:00
|
|
|
walkdottype(Node *n, NodeList **init)
|
2009-07-14 00:38:39 -06:00
|
|
|
{
|
2009-07-31 10:29:28 -06:00
|
|
|
walkexpr(&n->left, init);
|
2009-07-14 00:38:39 -06:00
|
|
|
if(n->left == N)
|
|
|
|
return;
|
|
|
|
if(n->right != N) {
|
2009-07-31 10:29:28 -06:00
|
|
|
walkexpr(&n->right, init);
|
2009-07-14 00:38:39 -06:00
|
|
|
n->type = n->right->type;
|
|
|
|
n->right = N;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-04 13:57:48 -06:00
|
|
|
// TODO(rsc): cut
|
2009-02-13 15:48:16 -07:00
|
|
|
void
|
2009-07-29 13:00:34 -06:00
|
|
|
walkconv(Node **np, NodeList **init)
|
2009-02-13 15:48:16 -07:00
|
|
|
{
|
2009-03-03 09:41:02 -07:00
|
|
|
int et;
|
2009-05-20 15:57:55 -06:00
|
|
|
char *what;
|
2009-02-13 15:48:16 -07:00
|
|
|
Type *t;
|
|
|
|
Node *l;
|
2009-07-29 13:00:34 -06:00
|
|
|
Node *n;
|
2009-07-29 13:47:51 -06:00
|
|
|
|
2009-07-29 13:00:34 -06:00
|
|
|
n = *np;
|
2009-02-13 15:48:16 -07:00
|
|
|
t = n->type;
|
|
|
|
if(t == T)
|
|
|
|
return;
|
2009-07-31 10:29:28 -06:00
|
|
|
walkexpr(&n->left, init);
|
2009-02-13 15:48:16 -07:00
|
|
|
l = n->left;
|
|
|
|
if(l == N)
|
|
|
|
return;
|
2009-03-12 20:04:38 -06:00
|
|
|
if(l->type == T)
|
|
|
|
return;
|
2009-03-03 09:41:02 -07:00
|
|
|
|
|
|
|
// if using .(T), interface assertion.
|
|
|
|
if(n->op == ODOTTYPE) {
|
2009-05-20 15:57:55 -06:00
|
|
|
et = ifaceas1(t, l->type, 1);
|
2009-08-03 12:58:52 -06:00
|
|
|
if(et == I2Isame || et == E2Esame) {
|
|
|
|
n->op = OCONVNOP;
|
2009-03-03 09:41:02 -07:00
|
|
|
return;
|
|
|
|
}
|
2009-08-03 12:58:52 -06:00
|
|
|
if(et != Inone) {
|
|
|
|
n = ifacecvt(t, l, et, init);
|
2009-07-29 13:00:34 -06:00
|
|
|
*np = n;
|
2009-02-13 15:48:16 -07:00
|
|
|
return;
|
|
|
|
}
|
2009-08-03 12:58:52 -06:00
|
|
|
goto bad;
|
2009-02-13 15:48:16 -07:00
|
|
|
}
|
|
|
|
|
2009-08-03 12:58:52 -06:00
|
|
|
fatal("walkconv");
|
2009-02-13 15:48:16 -07:00
|
|
|
|
2009-03-03 09:41:02 -07:00
|
|
|
bad:
|
2009-04-17 00:07:30 -06:00
|
|
|
if(n->diag)
|
|
|
|
return;
|
|
|
|
n->diag = 1;
|
2009-05-20 15:57:55 -06:00
|
|
|
if(n->op == ODOTTYPE)
|
|
|
|
what = "type assertion";
|
|
|
|
else
|
|
|
|
what = "conversion";
|
2009-02-13 15:48:16 -07:00
|
|
|
if(l->type != T)
|
2009-05-20 15:57:55 -06:00
|
|
|
yyerror("invalid %s: %T to %T", what, l->type, t);
|
2009-02-13 15:48:16 -07:00
|
|
|
}
|
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
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
|
|
|
|
2009-07-17 02:00:44 -06:00
|
|
|
NodeList*
|
|
|
|
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
|
|
|
|
*/
|
|
|
|
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
|
|
|
/*
|
|
|
|
* n is an lv and t is the type of an rv
|
|
|
|
* return 1 if this implies a function call
|
|
|
|
* evaluating the lv or a function call
|
|
|
|
* in the conversion of the types
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
fncall(Node *l, Type *rt)
|
|
|
|
{
|
|
|
|
if(l->ullman >= UINF)
|
|
|
|
return 1;
|
|
|
|
if(eqtype(l->type, rt))
|
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2009-07-17 02:00:44 -06:00
|
|
|
NodeList*
|
|
|
|
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;
|
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);
|
|
|
|
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)
|
|
|
|
yyerror("reorder2: too many function calls evaluating parameters");
|
|
|
|
return concat(nn, mm);
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
2008-11-01 17:36:46 -06:00
|
|
|
/*
|
|
|
|
* make a tsig for the structure
|
|
|
|
* carrying the ... arguments
|
|
|
|
*/
|
|
|
|
Type*
|
|
|
|
sigtype(Type *st)
|
|
|
|
{
|
|
|
|
Sym *s;
|
|
|
|
Type *t;
|
|
|
|
static int sigdddgen;
|
|
|
|
|
|
|
|
dowidth(st);
|
|
|
|
|
|
|
|
sigdddgen++;
|
|
|
|
snprint(namebuf, sizeof(namebuf), "dsigddd_%d", sigdddgen);
|
|
|
|
s = lookup(namebuf);
|
|
|
|
t = newtype(s);
|
|
|
|
t = dodcltype(t);
|
|
|
|
updatetype(t, st);
|
2008-12-11 12:54:33 -07:00
|
|
|
t->local = 1;
|
2009-06-06 13:46:38 -06:00
|
|
|
return t;
|
2008-11-01 17:36:46 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* package all the arguments that
|
|
|
|
* match a ... parameter into an
|
|
|
|
* automatic structure.
|
|
|
|
* then call the ... arg (interface)
|
2009-01-29 18:38:58 -07:00
|
|
|
* with a pointer to the structure.
|
2008-11-01 17:36:46 -06:00
|
|
|
*/
|
2009-07-17 02:00:44 -06:00
|
|
|
NodeList*
|
|
|
|
mkdotargs(NodeList *lr0, NodeList *nn, Type *l, int fp, NodeList **init)
|
2008-11-01 17:36:46 -06:00
|
|
|
{
|
2009-07-17 02:00:44 -06:00
|
|
|
Node *r;
|
2008-11-01 17:36:46 -06:00
|
|
|
Type *t, *st, *ft;
|
2009-07-17 02:00:44 -06:00
|
|
|
Node *a, *var;
|
|
|
|
NodeList *lr, *n;
|
2008-11-01 17:36:46 -06:00
|
|
|
|
2009-07-17 02:00:44 -06:00
|
|
|
n = nil; // list of assignments
|
2008-11-01 17:36:46 -06:00
|
|
|
|
|
|
|
st = typ(TSTRUCT); // generated structure
|
|
|
|
ft = T; // last field
|
2009-07-17 02:00:44 -06:00
|
|
|
for(lr=lr0; lr; lr=lr->next) {
|
|
|
|
r = lr->n;
|
2009-05-27 19:37:02 -06:00
|
|
|
if(r->op == OLITERAL && r->val.ctype == CTNIL) {
|
|
|
|
if(r->type == T || r->type->etype == TNIL) {
|
|
|
|
yyerror("inappropriate use of nil in ... argument");
|
2009-07-17 02:00:44 -06:00
|
|
|
return nil;
|
2009-05-27 19:37:02 -06:00
|
|
|
}
|
|
|
|
}
|
2009-07-17 14:38:16 -06:00
|
|
|
defaultlit(&r, T);
|
|
|
|
lr->n = r;
|
2009-03-18 20:20:54 -06:00
|
|
|
if(r->type == T) // type check failed
|
2009-07-17 02:00:44 -06:00
|
|
|
return nil;
|
2009-03-18 20:20:54 -06:00
|
|
|
|
2008-11-01 17:36:46 -06:00
|
|
|
// generate the next structure field
|
|
|
|
t = typ(TFIELD);
|
|
|
|
t->type = r->type;
|
|
|
|
if(ft == T)
|
|
|
|
st->type = t;
|
|
|
|
else
|
|
|
|
ft->down = t;
|
|
|
|
ft = t;
|
|
|
|
|
|
|
|
a = nod(OAS, N, r);
|
|
|
|
n = list(n, a);
|
|
|
|
}
|
|
|
|
|
|
|
|
// make a named type for the struct
|
|
|
|
st = sigtype(st);
|
2009-01-29 18:38:58 -07:00
|
|
|
dowidth(st);
|
2008-11-01 17:36:46 -06:00
|
|
|
|
|
|
|
// now we have the size, make the struct
|
|
|
|
var = nod(OXXX, N, N);
|
|
|
|
tempname(var, st);
|
2009-01-29 18:38:58 -07:00
|
|
|
var->sym = lookup(".ddd");
|
2008-11-01 17:36:46 -06:00
|
|
|
|
2009-01-27 16:05:25 -07:00
|
|
|
// assign the fields to the struct.
|
2009-07-10 17:29:26 -06:00
|
|
|
// use the init list so that reorder1 doesn't reorder
|
2009-01-27 16:05:25 -07:00
|
|
|
// these assignments after the interface conversion
|
|
|
|
// below.
|
2008-11-01 17:36:46 -06:00
|
|
|
t = st->type;
|
2009-07-17 02:00:44 -06:00
|
|
|
for(lr=n; lr; lr=lr->next) {
|
|
|
|
r = lr->n;
|
2008-11-01 17:36:46 -06:00
|
|
|
r->left = nod(OXXX, N, N);
|
|
|
|
*r->left = *var;
|
|
|
|
r->left->type = r->right->type;
|
|
|
|
r->left->xoffset += t->width;
|
2009-07-30 17:53:08 -06:00
|
|
|
typecheck(&r, Etop);
|
2009-07-31 10:29:28 -06:00
|
|
|
walkexpr(&r, init);
|
2009-07-29 13:00:34 -06:00
|
|
|
lr->n = r;
|
2008-11-01 17:36:46 -06:00
|
|
|
t = t->down;
|
|
|
|
}
|
2009-07-17 02:00:44 -06:00
|
|
|
*init = concat(*init, n);
|
2008-11-01 17:36:46 -06:00
|
|
|
|
|
|
|
// last thing is to put assignment
|
2009-01-29 18:38:58 -07:00
|
|
|
// of the structure to the DDD parameter
|
2009-01-27 16:05:25 -07:00
|
|
|
a = nod(OAS, nodarg(l, fp), var);
|
2009-07-17 02:00:44 -06:00
|
|
|
nn = list(nn, convas(a, init));
|
2008-11-01 17:36:46 -06:00
|
|
|
return nn;
|
|
|
|
}
|
|
|
|
|
2009-05-07 11:29:35 -06:00
|
|
|
/*
|
|
|
|
* helpers for shape errors
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
dumptypes(Type **nl, char *what)
|
|
|
|
{
|
|
|
|
int first;
|
|
|
|
Type *l;
|
|
|
|
Iter savel;
|
|
|
|
|
|
|
|
l = structfirst(&savel, nl);
|
|
|
|
print("\t");
|
|
|
|
first = 1;
|
|
|
|
for(l = structfirst(&savel, nl); l != T; l = structnext(&savel)) {
|
|
|
|
if(first)
|
|
|
|
first = 0;
|
|
|
|
else
|
|
|
|
print(", ");
|
|
|
|
print("%T", l);
|
|
|
|
}
|
|
|
|
if(first)
|
|
|
|
print("[no arguments %s]", what);
|
|
|
|
print("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
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;
|
|
|
|
|
|
|
|
print("\t");
|
|
|
|
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
|
|
|
|
print(", ");
|
|
|
|
print("%T", r->type);
|
|
|
|
}
|
|
|
|
if(first)
|
|
|
|
print("[no arguments %s]", what);
|
|
|
|
print("\n");
|
|
|
|
}
|
|
|
|
|
2009-01-08 15:30:00 -07:00
|
|
|
/*
|
|
|
|
* check assign expression list to
|
|
|
|
* a type list. called in
|
|
|
|
* return expr-list
|
|
|
|
* func(expr-list)
|
|
|
|
*/
|
2009-07-17 02:00:44 -06:00
|
|
|
NodeList*
|
|
|
|
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;
|
|
|
|
NodeList *nn, *lr0;
|
|
|
|
Iter savel, peekl;
|
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;
|
2008-11-01 17:36:46 -06:00
|
|
|
|
2009-01-08 15:30:00 -07:00
|
|
|
// 1 to many
|
|
|
|
peekl = savel;
|
|
|
|
if(l != T && r != N
|
|
|
|
&& structnext(&peekl) != T
|
2009-07-17 02:00:44 -06:00
|
|
|
&& lr->next == nil
|
2009-02-08 12:01:52 -07:00
|
|
|
&& eqtypenoname(r->type, *nl)) {
|
2009-07-03 10:44:59 -06:00
|
|
|
// clumsy check for differently aligned structs.
|
|
|
|
// now that output structs are aligned separately
|
|
|
|
// from the input structs, should never happen.
|
|
|
|
if(r->type->width != (*nl)->width)
|
|
|
|
fatal("misaligned multiple return\n\t%T\n\t%T", r->type, *nl);
|
2009-02-08 12:01:52 -07:00
|
|
|
a = nodarg(*nl, fp);
|
|
|
|
a->type = r->type;
|
2009-07-30 17:53:08 -06:00
|
|
|
nn = list1(convas(nod(OAS, a, r), init));
|
|
|
|
goto ret;
|
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:
|
2008-11-01 17:36:46 -06:00
|
|
|
if(l != T && isddd(l->type)) {
|
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
|
2009-07-17 02:00:44 -06:00
|
|
|
if(r != N && lr->next == nil && isddd(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
|
|
|
}
|
|
|
|
|
2008-11-03 16:32:49 -07:00
|
|
|
// normal case -- make a structure of all
|
|
|
|
// remaining arguments and pass a pointer to
|
|
|
|
// it to the ddd parameter (empty interface)
|
2009-07-30 17:53:08 -06:00
|
|
|
nn = mkdotargs(lr, nn, l, fp, init);
|
|
|
|
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) {
|
|
|
|
if(l != T)
|
|
|
|
yyerror("not enough arguments to %O", op);
|
|
|
|
else
|
|
|
|
yyerror("too many arguments to %O", op);
|
|
|
|
dumptypes(nl, "expected");
|
2009-07-17 02:00:44 -06:00
|
|
|
dumpnodetypes(lr0, "given");
|
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*
|
2009-08-03 12:58:52 -06:00
|
|
|
walkprint(Node *nn, NodeList **init)
|
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;
|
2009-07-17 02:00:44 -06:00
|
|
|
NodeList *calls;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
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;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-07-17 02:00:44 -06:00
|
|
|
for(l=all; l; l=l->next) {
|
2009-07-31 10:29:28 -06:00
|
|
|
if(notfirst)
|
2009-08-03 12:58:52 -06:00
|
|
|
calls = list(calls, mkcall("printsp", T, init));
|
2009-07-31 10:29:28 -06:00
|
|
|
notfirst = op == OPRINTN || op == OPANICN;
|
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
|
|
|
|
2009-07-17 02:00:44 -06:00
|
|
|
et = n->type->etype;
|
|
|
|
if(isinter(n->type)) {
|
|
|
|
if(isnilinter(n->type))
|
|
|
|
on = syslook("printeface", 1);
|
|
|
|
else
|
|
|
|
on = syslook("printiface", 1);
|
|
|
|
argtype(on, n->type); // any-1
|
|
|
|
} else if(isptr[et] || et == TCHAN || et == TMAP || et == TFUNC) {
|
|
|
|
on = syslook("printpointer", 1);
|
|
|
|
argtype(on, n->type); // any-1
|
|
|
|
} else if(isslice(n->type)) {
|
|
|
|
on = syslook("printarray", 1);
|
|
|
|
argtype(on, n->type); // any-1
|
|
|
|
} else if(isint[et]) {
|
|
|
|
if(et == TUINT64)
|
|
|
|
on = syslook("printuint", 0);
|
|
|
|
else
|
|
|
|
on = syslook("printint", 0);
|
|
|
|
} else if(isfloat[et]) {
|
|
|
|
on = syslook("printfloat", 0);
|
|
|
|
} else if(et == TBOOL) {
|
|
|
|
on = syslook("printbool", 0);
|
|
|
|
} else if(et == TSTRING) {
|
|
|
|
on = syslook("printstring", 0);
|
|
|
|
} else {
|
|
|
|
badtype(OPRINT, n->type, T);
|
|
|
|
continue;
|
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-07-17 02:00:44 -06:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
r = nod(OCALL, on, N);
|
|
|
|
r->list = list1(n);
|
|
|
|
calls = list(calls, r);
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
2009-07-31 10:29:28 -06:00
|
|
|
if(op == OPRINTN)
|
|
|
|
calls = list(calls, mkcall("printnl", T, nil));
|
2009-07-30 17:53:08 -06:00
|
|
|
typechecklist(calls, Etop);
|
2009-08-03 12:58:52 -06:00
|
|
|
walkexprlist(calls, init);
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-07-31 10:29:28 -06:00
|
|
|
if(op == OPANIC || op == OPANICN)
|
|
|
|
r = mkcall("panicl", T, nil);
|
2009-07-17 02:00:44 -06:00
|
|
|
else
|
|
|
|
r = nod(OEMPTY, N, N);
|
2009-07-30 17:53:08 -06:00
|
|
|
typecheck(&r, Etop);
|
2009-08-03 12:58:52 -06:00
|
|
|
walkexpr(&r, init);
|
2009-07-17 02:00:44 -06:00
|
|
|
r->ninit = calls;
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2008-07-12 14:08:53 -06:00
|
|
|
Type*
|
2009-01-09 12:13:39 -07:00
|
|
|
fixchan(Type *t)
|
2008-07-12 14:08:53 -06:00
|
|
|
{
|
2008-09-14 17:57:55 -06:00
|
|
|
if(t == T)
|
|
|
|
goto bad;
|
|
|
|
if(t->etype != TCHAN)
|
|
|
|
goto bad;
|
|
|
|
if(t->type == T)
|
|
|
|
goto bad;
|
2008-07-12 14:08:53 -06:00
|
|
|
|
|
|
|
dowidth(t->type);
|
|
|
|
|
|
|
|
return t;
|
2008-09-14 17:57:55 -06:00
|
|
|
|
|
|
|
bad:
|
2009-01-09 12:13:39 -07:00
|
|
|
yyerror("not a channel: %lT", t);
|
2008-09-14 17:57:55 -06:00
|
|
|
return T;
|
2008-07-12 14:08:53 -06:00
|
|
|
}
|
|
|
|
|
2008-06-15 21:24:30 -06:00
|
|
|
Node*
|
2009-07-31 10:29:28 -06:00
|
|
|
mapop(Node *n, NodeList **init)
|
2008-06-15 21:24:30 -06:00
|
|
|
{
|
2009-08-04 11:26:29 -06:00
|
|
|
Node *r, *a;
|
2008-06-15 21:24:30 -06:00
|
|
|
Type *t;
|
|
|
|
|
|
|
|
r = n;
|
|
|
|
switch(n->op) {
|
|
|
|
default:
|
2008-07-13 15:29:46 -06:00
|
|
|
fatal("mapop: unknown op %O", n->op);
|
2008-08-10 17:49:01 -06:00
|
|
|
case OASOP:
|
|
|
|
// rewrite map[index] op= right
|
|
|
|
// into tmpi := index; map[tmpi] = map[tmpi] op right
|
2009-07-17 02:00:44 -06:00
|
|
|
// TODO(rsc): does this double-evaluate map?
|
2008-08-10 17:49:01 -06:00
|
|
|
|
2009-01-09 12:13:39 -07:00
|
|
|
t = n->left->left->type;
|
2008-08-10 17:49:01 -06:00
|
|
|
a = nod(OXXX, N, N);
|
|
|
|
tempname(a, t->down); // tmpi
|
|
|
|
r = nod(OAS, a, n->left->right); // tmpi := index
|
|
|
|
n->left->right = a; // m[tmpi]
|
2009-07-30 17:53:08 -06:00
|
|
|
typecheck(&r, Etop);
|
2009-07-31 10:29:28 -06:00
|
|
|
walkexpr(&r, init);
|
2009-07-17 02:00:44 -06:00
|
|
|
*init = list(*init, r);
|
2008-08-10 17:49:01 -06:00
|
|
|
|
|
|
|
a = nod(OXXX, N, N);
|
2009-07-29 13:00:34 -06:00
|
|
|
*a = *n->left; // copy of map[tmpi]
|
2009-08-03 12:58:52 -06:00
|
|
|
a->etype = 0;
|
2008-08-10 17:49:01 -06:00
|
|
|
a = nod(n->etype, a, n->right); // m[tmpi] op right
|
2009-07-17 02:00:44 -06:00
|
|
|
r = nod(OAS, n->left, a); // map[tmpi] = map[tmpi] op right
|
2009-07-30 17:53:08 -06:00
|
|
|
typecheck(&r, Etop);
|
2009-07-31 10:29:28 -06:00
|
|
|
walkexpr(&r, init);
|
2008-10-04 18:11:01 -06:00
|
|
|
break;
|
2008-06-16 23:34:50 -06:00
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
return r;
|
2008-08-27 18:28:30 -06:00
|
|
|
}
|
|
|
|
|
2009-01-08 19:06:06 -07:00
|
|
|
/*
|
|
|
|
* assigning src to dst involving interfaces?
|
|
|
|
* return op to use.
|
|
|
|
*/
|
2008-09-22 13:16:19 -06:00
|
|
|
int
|
2009-02-11 18:57:29 -07:00
|
|
|
ifaceas1(Type *dst, Type *src, int explicit)
|
2008-06-04 15:37:38 -06:00
|
|
|
{
|
2009-01-08 19:06:06 -07:00
|
|
|
if(src == T || dst == T)
|
|
|
|
return Inone;
|
2008-08-12 20:13:09 -06:00
|
|
|
|
2009-03-04 15:50:25 -07:00
|
|
|
if(explicit && !isinter(src))
|
|
|
|
yyerror("cannot use .(T) on non-interface type %T", src);
|
|
|
|
|
2009-01-08 19:06:06 -07:00
|
|
|
if(isinter(dst)) {
|
|
|
|
if(isinter(src)) {
|
2009-05-20 15:57:55 -06:00
|
|
|
if(isnilinter(dst)) {
|
|
|
|
if(isnilinter(src))
|
|
|
|
return E2Esame;
|
|
|
|
return I2E;
|
|
|
|
}
|
2009-05-08 15:40:38 -06:00
|
|
|
if(eqtype(dst, src))
|
2009-01-27 19:21:03 -07:00
|
|
|
return I2Isame;
|
2009-05-20 15:57:55 -06:00
|
|
|
ifacecheck(dst, src, lineno, explicit);
|
|
|
|
if(isnilinter(src))
|
|
|
|
return E2I;
|
2009-05-20 19:23:19 -06:00
|
|
|
if(explicit)
|
|
|
|
return I2Ix;
|
2009-01-08 19:06:06 -07:00
|
|
|
return I2I;
|
2008-10-02 21:51:10 -06:00
|
|
|
}
|
2009-01-08 19:06:06 -07:00
|
|
|
if(isnilinter(dst))
|
2009-05-20 15:57:55 -06:00
|
|
|
return T2E;
|
2009-02-11 18:57:29 -07:00
|
|
|
ifacecheck(dst, src, lineno, explicit);
|
2009-01-08 19:06:06 -07:00
|
|
|
return T2I;
|
2008-08-12 20:13:09 -06:00
|
|
|
}
|
2009-01-08 19:06:06 -07:00
|
|
|
if(isinter(src)) {
|
2009-02-11 18:57:29 -07:00
|
|
|
ifacecheck(dst, src, lineno, explicit);
|
2009-05-20 15:57:55 -06:00
|
|
|
if(isnilinter(src))
|
|
|
|
return E2T;
|
2009-01-08 19:06:06 -07:00
|
|
|
return I2T;
|
2008-08-12 20:13:09 -06:00
|
|
|
}
|
2008-09-22 13:16:19 -06:00
|
|
|
return Inone;
|
|
|
|
}
|
2008-08-12 20:13:09 -06:00
|
|
|
|
2009-01-27 19:21:03 -07:00
|
|
|
/*
|
|
|
|
* treat convert T to T as noop
|
|
|
|
*/
|
|
|
|
int
|
2009-02-11 18:57:29 -07:00
|
|
|
ifaceas(Type *dst, Type *src, int explicit)
|
2009-01-27 19:21:03 -07:00
|
|
|
{
|
|
|
|
int et;
|
|
|
|
|
2009-02-11 18:57:29 -07:00
|
|
|
et = ifaceas1(dst, src, explicit);
|
2009-05-20 15:57:55 -06:00
|
|
|
if(et == I2Isame || et == E2Esame)
|
2009-01-27 19:21:03 -07:00
|
|
|
et = Inone;
|
|
|
|
return et;
|
|
|
|
}
|
|
|
|
|
2008-11-05 15:27:07 -07:00
|
|
|
static char*
|
|
|
|
ifacename[] =
|
|
|
|
{
|
2009-01-27 19:21:03 -07:00
|
|
|
[I2T] = "ifaceI2T",
|
|
|
|
[I2T2] = "ifaceI2T2",
|
|
|
|
[I2I] = "ifaceI2I",
|
2009-05-20 19:23:19 -06:00
|
|
|
[I2Ix] = "ifaceI2Ix",
|
2009-01-27 19:21:03 -07:00
|
|
|
[I2I2] = "ifaceI2I2",
|
|
|
|
[I2Isame] = "ifaceI2Isame",
|
2009-05-20 15:57:55 -06:00
|
|
|
[E2T] = "ifaceE2T",
|
|
|
|
[E2T2] = "ifaceE2T2",
|
|
|
|
[E2I] = "ifaceE2I",
|
|
|
|
[E2I2] = "ifaceE2I2",
|
|
|
|
[I2E] = "ifaceI2E",
|
|
|
|
[I2E2] = "ifaceI2E2",
|
|
|
|
[T2I] = "ifaceT2I",
|
|
|
|
[T2E] = "ifaceT2E",
|
|
|
|
[E2Esame] = "ifaceE2Esame",
|
2008-11-05 15:27:07 -07:00
|
|
|
};
|
|
|
|
|
2008-09-22 13:16:19 -06:00
|
|
|
Node*
|
2009-08-03 12:58:52 -06:00
|
|
|
ifacecvt(Type *tl, Node *n, int et, NodeList **init)
|
2008-09-22 13:16:19 -06:00
|
|
|
{
|
|
|
|
Type *tr;
|
2009-07-17 02:00:44 -06:00
|
|
|
Node *r, *on;
|
|
|
|
NodeList *args;
|
2008-08-12 20:13:09 -06:00
|
|
|
|
2008-09-22 13:16:19 -06:00
|
|
|
tr = n->type;
|
|
|
|
|
2009-05-20 16:09:50 -06:00
|
|
|
switch(et) {
|
2008-09-22 13:16:19 -06:00
|
|
|
default:
|
2009-05-20 16:09:50 -06:00
|
|
|
fatal("ifacecvt: unknown op %d\n", et);
|
2008-09-22 13:16:19 -06:00
|
|
|
|
2009-08-03 12:58:52 -06:00
|
|
|
case I2Isame:
|
|
|
|
case E2Esame:
|
|
|
|
return n;
|
|
|
|
|
2008-09-22 13:16:19 -06:00
|
|
|
case T2I:
|
2008-09-22 17:58:30 -06:00
|
|
|
// ifaceT2I(sigi *byte, sigt *byte, elem any) (ret any);
|
2009-07-17 02:00:44 -06:00
|
|
|
args = list1(typename(tl)); // sigi
|
|
|
|
args = list(args, typename(tr)); // sigt
|
|
|
|
args = list(args, n); // elem
|
2008-09-22 13:16:19 -06:00
|
|
|
|
|
|
|
on = syslook("ifaceT2I", 1);
|
|
|
|
argtype(on, tr);
|
2008-09-22 17:58:30 -06:00
|
|
|
argtype(on, tl);
|
2009-08-03 12:58:52 -06:00
|
|
|
dowidth(on->type);
|
2008-09-22 13:16:19 -06:00
|
|
|
break;
|
|
|
|
|
2008-11-05 15:27:07 -07:00
|
|
|
case I2T:
|
|
|
|
case I2T2:
|
2008-09-22 13:16:19 -06:00
|
|
|
case I2I:
|
2009-05-20 19:23:19 -06:00
|
|
|
case I2Ix:
|
2008-11-05 15:27:07 -07:00
|
|
|
case I2I2:
|
2009-05-20 15:57:55 -06:00
|
|
|
case E2T:
|
|
|
|
case E2T2:
|
|
|
|
case E2I:
|
|
|
|
case E2I2:
|
2008-11-05 15:27:07 -07:00
|
|
|
// iface[IT]2[IT][2](sigt *byte, iface any) (ret any[, ok bool]);
|
2009-07-17 02:00:44 -06:00
|
|
|
args = list1(typename(tl)); // sigi or sigt
|
|
|
|
args = list(args, n); // iface
|
2008-09-22 17:58:30 -06:00
|
|
|
|
2009-05-20 16:09:50 -06:00
|
|
|
on = syslook(ifacename[et], 1);
|
2008-09-22 13:16:19 -06:00
|
|
|
argtype(on, tr);
|
2008-09-22 17:58:30 -06:00
|
|
|
argtype(on, tl);
|
2009-05-20 15:57:55 -06:00
|
|
|
break;
|
2008-11-05 15:27:07 -07:00
|
|
|
|
2009-05-20 15:57:55 -06:00
|
|
|
case I2E:
|
|
|
|
// TODO(rsc): Should do this in back end, without a call.
|
|
|
|
// ifaceI2E(elem any) (ret any);
|
2009-07-17 02:00:44 -06:00
|
|
|
args = list1(n); // elem
|
|
|
|
|
2009-05-20 15:57:55 -06:00
|
|
|
on = syslook("ifaceI2E", 1);
|
|
|
|
argtype(on, tr);
|
|
|
|
argtype(on, tl);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case T2E:
|
|
|
|
// TODO(rsc): Should do this in back end for pointer case, without a call.
|
|
|
|
// ifaceT2E(sigt *byte, elem any) (ret any);
|
2009-07-17 02:00:44 -06:00
|
|
|
args = list1(typename(tr)); // sigt
|
|
|
|
args = list(args, n); // elem
|
2009-05-20 15:57:55 -06:00
|
|
|
|
|
|
|
on = syslook("ifaceT2E", 1);
|
|
|
|
argtype(on, tr);
|
|
|
|
argtype(on, tl);
|
2008-09-22 13:16:19 -06:00
|
|
|
break;
|
2009-05-20 16:09:50 -06:00
|
|
|
}
|
|
|
|
|
2009-07-17 02:00:44 -06:00
|
|
|
r = nod(OCALL, on, N);
|
|
|
|
r->list = args;
|
2009-08-05 01:42:44 -06:00
|
|
|
typecheck(&r, Erv | Efnstruct);
|
2009-08-03 12:58:52 -06:00
|
|
|
walkexpr(&r, init);
|
2009-05-20 16:09:50 -06:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2008-08-12 20:13:09 -06:00
|
|
|
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;
|
2008-09-22 13:16:19 -06:00
|
|
|
int et;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
|
|
|
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
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2009-05-08 15:40:38 -06:00
|
|
|
if(eqtype(lt, rt))
|
2008-09-02 18:12:32 -06:00
|
|
|
goto out;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-02-11 18:57:29 -07:00
|
|
|
et = ifaceas(lt, rt, 0);
|
2008-09-22 13:16:19 -06:00
|
|
|
if(et != Inone) {
|
2009-08-03 12:58:52 -06:00
|
|
|
n->right = ifacecvt(lt, r, et, init);
|
2008-09-02 18:12:32 -06:00
|
|
|
goto out;
|
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-06 14:40:30 -07:00
|
|
|
/*
|
|
|
|
* rewrite a range statement
|
|
|
|
* k and v are names/new_names
|
|
|
|
* m is an array or map
|
2009-04-10 20:49:31 -06:00
|
|
|
* local is 0 (meaning =) or 1 (meaning :=)
|
2008-12-06 14:40:30 -07:00
|
|
|
*/
|
2008-12-05 19:24:05 -07:00
|
|
|
Node*
|
2008-12-06 14:40:30 -07:00
|
|
|
dorange(Node *nn)
|
2008-12-05 19:24:05 -07:00
|
|
|
{
|
2009-07-17 02:00:44 -06:00
|
|
|
Node *k, *v, *m;
|
|
|
|
Node *n, *hv, *hc, *ha, *hk, *ohk, *on, *r, *a, *as;
|
|
|
|
NodeList *init, *args;
|
2008-12-05 19:24:05 -07:00
|
|
|
Type *t, *th;
|
2008-12-06 14:40:30 -07:00
|
|
|
int local;
|
2009-07-17 02:00:44 -06:00
|
|
|
NodeList *nl;
|
2008-12-05 19:24:05 -07:00
|
|
|
|
2008-12-06 14:40:30 -07:00
|
|
|
if(nn->op != ORANGE)
|
|
|
|
fatal("dorange not ORANGE");
|
|
|
|
|
2009-07-17 02:00:44 -06:00
|
|
|
nl = nn->list;
|
|
|
|
k = nl->n;
|
|
|
|
if((nl = nl->next) != nil) {
|
|
|
|
v = nl->n;
|
|
|
|
nl = nl->next;
|
|
|
|
} else
|
|
|
|
v = N;
|
|
|
|
if(nl != nil)
|
|
|
|
yyerror("too many variables in range");
|
2008-12-05 19:24:05 -07:00
|
|
|
|
|
|
|
n = nod(OFOR, N, N);
|
2009-07-17 02:00:44 -06:00
|
|
|
init = nil;
|
2008-12-05 19:24:05 -07:00
|
|
|
|
2009-07-30 17:53:08 -06:00
|
|
|
typecheck(&nn->right, Erv);
|
2009-05-20 15:24:23 -06:00
|
|
|
m = nn->right;
|
|
|
|
local = nn->etype;
|
|
|
|
|
2008-12-05 19:24:05 -07:00
|
|
|
t = m->type;
|
|
|
|
if(t == T)
|
|
|
|
goto out;
|
|
|
|
if(t->etype == TARRAY)
|
|
|
|
goto ary;
|
|
|
|
if(t->etype == TMAP)
|
|
|
|
goto map;
|
2009-03-20 12:32:58 -06:00
|
|
|
if(t->etype == TCHAN)
|
|
|
|
goto chan;
|
2009-04-10 20:49:31 -06:00
|
|
|
if(t->etype == TSTRING)
|
|
|
|
goto strng;
|
2008-12-05 19:24:05 -07:00
|
|
|
|
2009-04-10 20:49:31 -06:00
|
|
|
yyerror("range must be over map/array/chan/string");
|
2008-12-05 19:24:05 -07:00
|
|
|
goto out;
|
|
|
|
|
|
|
|
ary:
|
|
|
|
hk = nod(OXXX, N, N); // hidden key
|
2009-03-20 12:32:58 -06:00
|
|
|
tempname(hk, types[TINT]);
|
2009-04-04 00:20:51 -06:00
|
|
|
|
2009-03-20 12:32:58 -06:00
|
|
|
ha = nod(OXXX, N, N); // hidden array
|
|
|
|
tempname(ha, t);
|
2008-12-05 19:24:05 -07:00
|
|
|
|
2009-05-26 20:48:39 -06:00
|
|
|
a = nod(OAS, hk, nodintconst(0));
|
|
|
|
init = list(init, a);
|
|
|
|
|
|
|
|
a = nod(OAS, ha, m);
|
|
|
|
init = list(init, a);
|
2009-03-20 12:32:58 -06:00
|
|
|
|
|
|
|
n->ntest = nod(OLT, hk, nod(OLEN, ha, N));
|
2009-03-12 20:04:38 -06:00
|
|
|
n->nincr = nod(OASOP, hk, nodintconst(1));
|
2008-12-05 19:24:05 -07:00
|
|
|
n->nincr->etype = OADD;
|
|
|
|
|
2008-12-06 14:40:30 -07:00
|
|
|
if(local)
|
2009-07-10 17:29:26 -06:00
|
|
|
k = old2new(k, hk->type, &init);
|
2009-07-17 02:00:44 -06:00
|
|
|
n->nbody = list1(nod(OAS, k, hk));
|
2008-12-05 19:24:05 -07:00
|
|
|
|
|
|
|
if(v != N) {
|
2008-12-06 14:40:30 -07:00
|
|
|
if(local)
|
2009-07-10 17:29:26 -06:00
|
|
|
v = old2new(v, t->type, &init);
|
2008-12-05 19:24:05 -07:00
|
|
|
n->nbody = list(n->nbody,
|
2009-03-20 12:32:58 -06:00
|
|
|
nod(OAS, v, nod(OINDEX, ha, hk)) );
|
2008-12-05 19:24:05 -07:00
|
|
|
}
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
map:
|
|
|
|
th = typ(TARRAY);
|
|
|
|
th->type = ptrto(types[TUINT8]);
|
|
|
|
th->bound = (sizeof(struct Hiter) + types[tptr]->width - 1) /
|
|
|
|
types[tptr]->width;
|
|
|
|
hk = nod(OXXX, N, N); // hidden iterator
|
|
|
|
tempname(hk, th); // hashmap hash_iter
|
|
|
|
|
|
|
|
on = syslook("mapiterinit", 1);
|
|
|
|
argtype(on, t->down);
|
|
|
|
argtype(on, t->type);
|
|
|
|
argtype(on, th);
|
2009-07-17 02:00:44 -06:00
|
|
|
a = nod(OADDR, hk, N);
|
|
|
|
r = nod(OCALL, on, N);
|
|
|
|
r->list = list(list1(m), a);
|
2009-05-26 20:48:39 -06:00
|
|
|
|
|
|
|
init = list(init, r);
|
2008-12-05 19:24:05 -07:00
|
|
|
|
2009-03-12 20:04:38 -06:00
|
|
|
r = nod(OINDEX, hk, nodintconst(0));
|
2008-12-05 19:24:05 -07:00
|
|
|
a = nod(OLITERAL, N, N);
|
|
|
|
a->val.ctype = CTNIL;
|
2009-03-12 20:04:38 -06:00
|
|
|
a->type = types[TNIL];
|
2008-12-05 19:24:05 -07:00
|
|
|
r = nod(ONE, r, a);
|
|
|
|
n->ntest = r;
|
|
|
|
|
|
|
|
on = syslook("mapiternext", 1);
|
|
|
|
argtype(on, th);
|
|
|
|
r = nod(OADDR, hk, N);
|
2009-07-17 02:00:44 -06:00
|
|
|
args = list1(r);
|
|
|
|
r = nod(OCALL, on, N);
|
|
|
|
r->list = args;
|
2008-12-05 19:24:05 -07:00
|
|
|
n->nincr = r;
|
|
|
|
|
2008-12-06 14:40:30 -07:00
|
|
|
if(local)
|
2009-07-10 17:29:26 -06:00
|
|
|
k = old2new(k, t->down, &init);
|
2008-12-05 19:24:05 -07:00
|
|
|
if(v == N) {
|
|
|
|
on = syslook("mapiter1", 1);
|
|
|
|
argtype(on, th);
|
|
|
|
argtype(on, t->down);
|
|
|
|
r = nod(OADDR, hk, N);
|
2009-07-17 02:00:44 -06:00
|
|
|
args = list1(r);
|
|
|
|
r = nod(OCALL, on, N);
|
|
|
|
r->list = args;
|
|
|
|
n->nbody = list1(nod(OAS, k, r));
|
2008-12-05 19:24:05 -07:00
|
|
|
goto out;
|
|
|
|
}
|
2008-12-06 14:40:30 -07:00
|
|
|
if(local)
|
2009-07-10 17:29:26 -06:00
|
|
|
v = old2new(v, t->type, &init);
|
2008-12-05 19:24:05 -07:00
|
|
|
on = syslook("mapiter2", 1);
|
|
|
|
argtype(on, th);
|
|
|
|
argtype(on, t->down);
|
|
|
|
argtype(on, t->type);
|
|
|
|
r = nod(OADDR, hk, N);
|
2009-07-17 02:00:44 -06:00
|
|
|
args = list1(r);
|
|
|
|
r = nod(OCALL, on, N);
|
|
|
|
r->list = args;
|
|
|
|
as = nod(OAS2, N, N);
|
|
|
|
as->list = list(list1(k), v);
|
|
|
|
as->rlist = list1(r);
|
|
|
|
n->nbody = list1(as);
|
2009-03-20 12:32:58 -06:00
|
|
|
goto out;
|
|
|
|
|
|
|
|
chan:
|
|
|
|
if(v != N)
|
|
|
|
yyerror("chan range can only have one variable");
|
|
|
|
|
|
|
|
hc = nod(OXXX, N, N); // hidden chan
|
|
|
|
tempname(hc, t);
|
2009-04-04 00:20:51 -06:00
|
|
|
|
2009-03-20 12:32:58 -06:00
|
|
|
hv = nod(OXXX, N, N); // hidden value
|
|
|
|
tempname(hv, t->type);
|
2008-12-05 19:24:05 -07:00
|
|
|
|
2009-05-26 20:48:39 -06:00
|
|
|
a = nod(OAS, hc, m);
|
|
|
|
init = list(init, a);
|
|
|
|
|
|
|
|
a = nod(ORECV, hc, N);
|
|
|
|
a = nod(OAS, hv, a);
|
|
|
|
init = list(init, a);
|
|
|
|
|
2009-07-17 02:00:44 -06:00
|
|
|
a = nod(OCLOSED, N, N);
|
|
|
|
a->list = list1(hc);
|
|
|
|
n->ntest = nod(ONOT, a, N);
|
2009-03-20 12:32:58 -06:00
|
|
|
n->nincr = nod(OAS, hv, nod(ORECV, hc, N));
|
|
|
|
|
|
|
|
if(local)
|
2009-07-10 17:29:26 -06:00
|
|
|
k = old2new(k, hv->type, &init);
|
2009-07-17 02:00:44 -06:00
|
|
|
n->nbody = list1(nod(OAS, k, hv));
|
2009-07-10 17:29:26 -06:00
|
|
|
|
2008-12-05 19:24:05 -07:00
|
|
|
goto out;
|
|
|
|
|
2009-04-10 20:49:31 -06:00
|
|
|
strng:
|
|
|
|
hk = nod(OXXX, N, N); // hidden key
|
|
|
|
tempname(hk, types[TINT]);
|
|
|
|
|
2009-04-13 06:31:44 -06:00
|
|
|
ohk = nod(OXXX, N, N); // old hidden key
|
|
|
|
tempname(ohk, types[TINT]);
|
|
|
|
|
2009-04-10 20:49:31 -06:00
|
|
|
ha = nod(OXXX, N, N); // hidden string
|
2009-07-27 16:16:28 -06:00
|
|
|
tempname(ha, types[TSTRING]);
|
2009-04-10 20:49:31 -06:00
|
|
|
|
2009-04-13 06:31:44 -06:00
|
|
|
hv = N;
|
|
|
|
if(v != N) {
|
|
|
|
hv = nod(OXXX, N, N); // hidden value
|
|
|
|
tempname(hv, types[TINT]);
|
|
|
|
}
|
2009-04-10 20:49:31 -06:00
|
|
|
|
|
|
|
if(local) {
|
2009-07-10 17:29:26 -06:00
|
|
|
k = old2new(k, types[TINT], &init);
|
2009-04-10 20:49:31 -06:00
|
|
|
if(v != N)
|
2009-07-10 17:29:26 -06:00
|
|
|
v = old2new(v, types[TINT], &init);
|
2009-04-10 20:49:31 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// ha = s
|
2009-07-27 16:16:28 -06:00
|
|
|
a = nod(OCONV, m, N);
|
|
|
|
a->type = ha->type;
|
|
|
|
a = nod(OAS, ha, a);
|
2009-05-26 20:48:39 -06:00
|
|
|
init = list(init, a);
|
2009-04-10 20:49:31 -06:00
|
|
|
|
2009-04-13 06:31:44 -06:00
|
|
|
// ohk = 0
|
|
|
|
a = nod(OAS, ohk, nodintconst(0));
|
2009-05-26 20:48:39 -06:00
|
|
|
init = list(init, a);
|
2009-04-10 20:49:31 -06:00
|
|
|
|
2009-04-13 06:31:44 -06:00
|
|
|
// hk[,hv] = stringiter(ha,hk)
|
2009-04-10 20:49:31 -06:00
|
|
|
if(v != N) {
|
|
|
|
// hk,v = stringiter2(ha, hk)
|
|
|
|
on = syslook("stringiter2", 0);
|
2009-07-17 02:00:44 -06:00
|
|
|
a = nod(OCALL, on, N);
|
|
|
|
a->list = list(list1(ha), nodintconst(0));
|
|
|
|
as = nod(OAS2, N, N);
|
|
|
|
as->list = list(list1(hk), hv);
|
|
|
|
as->rlist = list1(a);
|
|
|
|
a = as;
|
2009-04-10 20:49:31 -06:00
|
|
|
} else {
|
|
|
|
// hk = stringiter(ha, hk)
|
|
|
|
on = syslook("stringiter", 0);
|
2009-07-17 02:00:44 -06:00
|
|
|
a = nod(OCALL, on, N);
|
|
|
|
a->list = list(list1(ha), nodintconst(0));
|
2009-04-10 20:49:31 -06:00
|
|
|
a = nod(OAS, hk, a);
|
|
|
|
}
|
2009-05-26 20:48:39 -06:00
|
|
|
init = list(init, a);
|
2009-04-10 20:49:31 -06:00
|
|
|
|
|
|
|
// while(hk != 0)
|
|
|
|
n->ntest = nod(ONE, hk, nodintconst(0));
|
|
|
|
|
2009-04-13 06:31:44 -06:00
|
|
|
// hk[,hv] = stringiter(ha,hk)
|
2009-04-10 20:49:31 -06:00
|
|
|
if(v != N) {
|
2009-04-13 06:31:44 -06:00
|
|
|
// hk,hv = stringiter2(ha, hk)
|
2009-04-10 20:49:31 -06:00
|
|
|
on = syslook("stringiter2", 0);
|
2009-07-17 02:00:44 -06:00
|
|
|
a = nod(OCALL, on, N);
|
|
|
|
a->list = list(list1(ha), hk);
|
|
|
|
as = nod(OAS2, N, N);
|
|
|
|
as->list = list(list1(hk), hv);
|
|
|
|
as->rlist = list1(a);
|
|
|
|
a = as;
|
2009-04-10 20:49:31 -06:00
|
|
|
} else {
|
|
|
|
// hk = stringiter(ha, hk)
|
|
|
|
on = syslook("stringiter", 0);
|
2009-07-17 02:00:44 -06:00
|
|
|
a = nod(OCALL, on, N);
|
|
|
|
a->list = list(list1(ha), hk);
|
2009-04-10 20:49:31 -06:00
|
|
|
a = nod(OAS, hk, a);
|
|
|
|
}
|
2009-07-17 02:00:44 -06:00
|
|
|
n->nincr = a;
|
2009-04-10 20:49:31 -06:00
|
|
|
|
2009-04-13 06:31:44 -06:00
|
|
|
// k,ohk[,v] = ohk,hk,[,hv]
|
|
|
|
a = nod(OAS, k, ohk);
|
2009-07-17 02:00:44 -06:00
|
|
|
n->nbody = list1(a);
|
2009-04-13 06:31:44 -06:00
|
|
|
a = nod(OAS, ohk, hk);
|
|
|
|
n->nbody = list(n->nbody, a);
|
|
|
|
if(v != N) {
|
|
|
|
a = nod(OAS, v, hv);
|
|
|
|
n->nbody = list(n->nbody, a);
|
|
|
|
}
|
|
|
|
|
2008-12-05 19:24:05 -07:00
|
|
|
out:
|
2009-07-17 02:00:44 -06:00
|
|
|
n->ninit = concat(n->ninit, init);
|
2008-12-05 19:24:05 -07:00
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
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;
|
2008-06-10 22:29:57 -06:00
|
|
|
int c, t;
|
|
|
|
|
|
|
|
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
|
2008-06-11 22:06:26 -06:00
|
|
|
f = N; // one fncall assigned to stack
|
2009-07-17 02:00:44 -06:00
|
|
|
r = nil; // non fncalls and tempnames assigned to stack
|
2008-06-11 22:06:26 -06:00
|
|
|
|
2009-07-17 02:00:44 -06:00
|
|
|
for(l=all; l; l=l->next) {
|
|
|
|
n = l->n;
|
|
|
|
ullmancalc(n);
|
|
|
|
if(n->ullman < UINF) {
|
|
|
|
r = list(r, n);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if(f == N) {
|
|
|
|
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
|
|
|
*/
|
|
|
|
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
|
|
|
|
*/
|
|
|
|
if(l == N)
|
|
|
|
return 0;
|
|
|
|
switch(l->op) {
|
|
|
|
case ONAME:
|
|
|
|
// match each left with all rights
|
|
|
|
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)) {
|
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-07-17 02:00:44 -06:00
|
|
|
NodeList*
|
|
|
|
reorder4(NodeList *ll)
|
2008-06-10 22:29:57 -06:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* from ascompat[te]
|
|
|
|
* return c,d
|
|
|
|
* return expression assigned to output
|
|
|
|
* parameters. there may be no problems.
|
2009-07-17 02:00:44 -06:00
|
|
|
*
|
|
|
|
* TODO(rsc): i don't believe that.
|
|
|
|
* func f() (a, b int) {
|
|
|
|
* a, b = 1, 2;
|
|
|
|
* return b, a;
|
|
|
|
* }
|
2008-06-10 22:29:57 -06:00
|
|
|
*/
|
2009-07-17 02:00:44 -06:00
|
|
|
return ll;
|
2008-06-10 22:29:57 -06:00
|
|
|
}
|
2008-09-02 17:21:30 -06:00
|
|
|
|
|
|
|
Node*
|
2009-07-17 02:00:44 -06:00
|
|
|
structlit(Node *n, Node *var, NodeList **init)
|
2008-09-02 17:21:30 -06:00
|
|
|
{
|
2009-08-03 12:58:52 -06:00
|
|
|
Type *t;
|
2009-01-29 18:38:58 -07:00
|
|
|
Node *r, *a;
|
2009-07-17 02:00:44 -06:00
|
|
|
NodeList *nl;
|
2008-09-02 17:21:30 -06:00
|
|
|
|
|
|
|
t = n->type;
|
|
|
|
if(t->etype != TSTRUCT)
|
|
|
|
fatal("structlit: not struct");
|
|
|
|
|
2009-01-29 18:38:58 -07:00
|
|
|
if(var == N) {
|
|
|
|
var = nod(OXXX, N, N);
|
|
|
|
tempname(var, t);
|
|
|
|
}
|
2008-09-02 17:21:30 -06:00
|
|
|
|
2009-07-17 02:00:44 -06:00
|
|
|
nl = n->list;
|
2009-05-23 16:34:29 -06:00
|
|
|
|
2009-08-03 12:58:52 -06:00
|
|
|
if(count(n->list) < structcount(t)) {
|
|
|
|
a = nod(OAS, var, N);
|
2009-07-30 17:53:08 -06:00
|
|
|
typecheck(&a, Etop);
|
2009-07-31 10:29:28 -06:00
|
|
|
walkexpr(&a, init);
|
2009-07-10 17:29:26 -06:00
|
|
|
*init = list(*init, a);
|
2009-05-21 14:46:07 -06:00
|
|
|
}
|
2008-09-02 17:21:30 -06:00
|
|
|
|
2009-07-17 02:00:44 -06:00
|
|
|
for(; nl; nl=nl->next) {
|
|
|
|
r = nl->n;
|
|
|
|
|
2009-05-23 16:34:29 -06:00
|
|
|
// build list of var.field = expr
|
|
|
|
a = nod(ODOT, var, newname(r->left->sym));
|
|
|
|
a = nod(OAS, a, r->right);
|
2009-07-30 17:53:08 -06:00
|
|
|
typecheck(&a, Etop);
|
2009-07-31 10:29:28 -06:00
|
|
|
walkexpr(&a, init);
|
2009-07-10 17:29:26 -06:00
|
|
|
*init = list(*init, a);
|
2009-05-21 14:46:07 -06:00
|
|
|
}
|
2009-05-23 16:34:29 -06:00
|
|
|
return var;
|
|
|
|
}
|
2009-05-21 14:46:07 -06:00
|
|
|
|
2008-12-18 22:59:12 -07:00
|
|
|
Node*
|
2009-07-17 02:00:44 -06:00
|
|
|
arraylit(Node *n, Node *var, NodeList **init)
|
2008-12-18 22:59:12 -07:00
|
|
|
{
|
|
|
|
Type *t;
|
2009-05-17 20:16:16 -06:00
|
|
|
Node *r, *a;
|
2009-07-17 02:00:44 -06:00
|
|
|
NodeList *l;
|
2008-12-18 22:59:12 -07:00
|
|
|
|
|
|
|
t = n->type;
|
2009-01-07 14:20:10 -07:00
|
|
|
|
2009-02-13 15:48:16 -07:00
|
|
|
if(var == N) {
|
|
|
|
var = nod(OXXX, N, N);
|
|
|
|
tempname(var, t);
|
|
|
|
}
|
2008-12-19 04:05:54 -07:00
|
|
|
|
2009-08-03 12:58:52 -06:00
|
|
|
if(t->bound < 0) {
|
2009-01-06 18:31:24 -07:00
|
|
|
// slice
|
2009-07-17 02:00:44 -06:00
|
|
|
a = nod(OMAKE, N, N);
|
2009-08-03 12:58:52 -06:00
|
|
|
a->list = list(list1(typenod(t)), n->right);
|
2009-05-17 20:16:16 -06:00
|
|
|
a = nod(OAS, var, a);
|
2009-07-30 17:53:08 -06:00
|
|
|
typecheck(&a, Etop);
|
2009-07-31 10:29:28 -06:00
|
|
|
walkexpr(&a, init);
|
2009-07-10 17:29:26 -06:00
|
|
|
*init = list(*init, a);
|
2009-01-07 14:20:10 -07:00
|
|
|
} else {
|
2009-01-07 13:28:23 -07:00
|
|
|
// if entire array isnt initialized,
|
|
|
|
// then clear the array
|
2009-08-03 12:58:52 -06:00
|
|
|
if(count(n->list) < t->bound) {
|
2009-01-07 13:28:23 -07:00
|
|
|
a = nod(OAS, var, N);
|
2009-07-30 17:53:08 -06:00
|
|
|
typecheck(&a, Etop);
|
2009-07-31 10:29:28 -06:00
|
|
|
walkexpr(&a, init);
|
2009-07-10 17:29:26 -06:00
|
|
|
*init = list(*init, a);
|
2009-01-07 13:28:23 -07:00
|
|
|
}
|
2009-01-06 18:31:24 -07:00
|
|
|
}
|
2008-12-18 22:59:12 -07:00
|
|
|
|
2009-07-17 02:00:44 -06:00
|
|
|
for(l=n->list; l; l=l->next) {
|
|
|
|
r = l->n;
|
2008-12-18 22:59:12 -07:00
|
|
|
// build list of var[c] = expr
|
2009-08-03 12:58:52 -06:00
|
|
|
a = nod(OINDEX, var, r->left);
|
|
|
|
a = nod(OAS, a, r->right);
|
2009-07-30 17:53:08 -06:00
|
|
|
typecheck(&a, Etop);
|
2009-07-31 10:29:28 -06:00
|
|
|
walkexpr(&a, init); // add any assignments in r to top
|
2009-07-10 17:29:26 -06:00
|
|
|
*init = list(*init, a);
|
2009-05-23 16:34:29 -06:00
|
|
|
}
|
|
|
|
|
2009-08-03 12:58:52 -06:00
|
|
|
return var;
|
2009-05-23 16:34:29 -06:00
|
|
|
}
|
|
|
|
|
2008-09-03 15:40:22 -06:00
|
|
|
Node*
|
2009-07-17 02:00:44 -06:00
|
|
|
maplit(Node *n, Node *var, NodeList **init)
|
2008-09-03 15:40:22 -06:00
|
|
|
{
|
|
|
|
Type *t;
|
2009-02-13 15:48:16 -07:00
|
|
|
Node *r, *a;
|
2009-05-23 16:34:29 -06:00
|
|
|
Node* hash[101];
|
2009-07-17 02:00:44 -06:00
|
|
|
NodeList *l;
|
2009-05-31 14:02:24 -06:00
|
|
|
int nerr;
|
2008-09-03 15:40:22 -06:00
|
|
|
|
2009-05-31 14:02:24 -06:00
|
|
|
nerr = nerrors;
|
2008-09-03 15:40:22 -06:00
|
|
|
t = n->type;
|
2009-01-09 12:13:39 -07:00
|
|
|
if(t->etype != TMAP)
|
2008-12-19 04:05:54 -07:00
|
|
|
fatal("maplit: not map");
|
2008-09-03 15:40:22 -06:00
|
|
|
|
2009-02-13 15:48:16 -07:00
|
|
|
if(var == N) {
|
|
|
|
var = nod(OXXX, N, N);
|
|
|
|
tempname(var, t);
|
|
|
|
}
|
2008-09-03 15:40:22 -06:00
|
|
|
|
2009-07-17 02:00:44 -06:00
|
|
|
a = nod(OMAKE, N, N);
|
|
|
|
a->list = list1(typenod(t));
|
2008-09-03 15:40:22 -06:00
|
|
|
a = nod(OAS, var, a);
|
2009-07-30 17:53:08 -06:00
|
|
|
typecheck(&a, Etop);
|
2009-07-31 10:29:28 -06:00
|
|
|
walkexpr(&a, init);
|
2009-07-10 17:29:26 -06:00
|
|
|
*init = list(*init, a);
|
2008-09-03 15:40:22 -06:00
|
|
|
|
2009-05-23 16:34:29 -06:00
|
|
|
memset(hash, 0, sizeof(hash));
|
2009-07-17 02:00:44 -06:00
|
|
|
for(l=n->list; l; l=l->next) {
|
|
|
|
r = l->n;
|
2009-05-21 14:46:07 -06:00
|
|
|
// build list of var[c] = expr
|
|
|
|
a = nod(OINDEX, var, r->left);
|
|
|
|
a = nod(OAS, a, r->right);
|
2009-07-30 17:53:08 -06:00
|
|
|
typecheck(&a, Etop);
|
2009-07-31 10:29:28 -06:00
|
|
|
walkexpr(&a, init);
|
2009-05-31 14:02:24 -06:00
|
|
|
if(nerr != nerrors)
|
|
|
|
break;
|
|
|
|
|
2009-07-10 17:29:26 -06:00
|
|
|
*init = list(*init, a);
|
2009-05-21 14:46:07 -06:00
|
|
|
}
|
|
|
|
return var;
|
2008-09-03 15:40:22 -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.
|
|
|
|
*/
|
2009-07-17 02:00:44 -06:00
|
|
|
NodeList*
|
2009-01-29 18:38:58 -07:00
|
|
|
paramstoheap(Type **argin)
|
|
|
|
{
|
|
|
|
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;
|
2009-01-29 18:38:58 -07:00
|
|
|
if(v == N || !(v->class & PHEAP))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// generate allocation & copying code
|
|
|
|
nn = list(nn, nod(OAS, v->heapaddr, v->alloc));
|
|
|
|
nn = list(nn, nod(OAS, v, v->stackparam));
|
|
|
|
}
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
heapmoves(void)
|
|
|
|
{
|
2009-07-17 02:00:44 -06:00
|
|
|
NodeList *nn;
|
2009-01-29 18:38:58 -07:00
|
|
|
|
|
|
|
nn = paramstoheap(getthis(curfn->type));
|
2009-07-17 02:00:44 -06:00
|
|
|
nn = concat(nn, paramstoheap(getinarg(curfn->type)));
|
|
|
|
curfn->enter = concat(curfn->enter, nn);
|
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;
|
|
|
|
}
|