xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/d/dmd/arrayop.c (revision 627f7eb200a4419d89b531d55fccd2ee3ffdcde0)
1*627f7eb2Smrg 
2*627f7eb2Smrg /* Compiler implementation of the D programming language
3*627f7eb2Smrg  * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved
4*627f7eb2Smrg  * written by Walter Bright
5*627f7eb2Smrg  * http://www.digitalmars.com
6*627f7eb2Smrg  * Distributed under the Boost Software License, Version 1.0.
7*627f7eb2Smrg  * http://www.boost.org/LICENSE_1_0.txt
8*627f7eb2Smrg  * https://github.com/D-Programming-Language/dmd/blob/master/src/arrayop.c
9*627f7eb2Smrg  */
10*627f7eb2Smrg 
11*627f7eb2Smrg #include "root/dsystem.h"
12*627f7eb2Smrg #include "root/rmem.h"
13*627f7eb2Smrg #include "root/aav.h"
14*627f7eb2Smrg 
15*627f7eb2Smrg #include "mars.h"
16*627f7eb2Smrg #include "expression.h"
17*627f7eb2Smrg #include "statement.h"
18*627f7eb2Smrg #include "mtype.h"
19*627f7eb2Smrg #include "declaration.h"
20*627f7eb2Smrg #include "scope.h"
21*627f7eb2Smrg #include "id.h"
22*627f7eb2Smrg #include "module.h"
23*627f7eb2Smrg #include "init.h"
24*627f7eb2Smrg #include "tokens.h"
25*627f7eb2Smrg 
26*627f7eb2Smrg void buildArrayIdent(Expression *e, OutBuffer *buf, Expressions *arguments);
27*627f7eb2Smrg Expression *buildArrayLoop(Expression *e, Parameters *fparams);
28*627f7eb2Smrg Expression *semantic(Expression *e, Scope *sc);
29*627f7eb2Smrg 
30*627f7eb2Smrg /**************************************
31*627f7eb2Smrg  * Hash table of array op functions already generated or known about.
32*627f7eb2Smrg  */
33*627f7eb2Smrg 
34*627f7eb2Smrg AA *arrayfuncs;
35*627f7eb2Smrg 
36*627f7eb2Smrg /**************************************
37*627f7eb2Smrg  * Structure to contain information needed to insert an array op call
38*627f7eb2Smrg  */
39*627f7eb2Smrg 
buildArrayOp(Identifier * ident,BinExp * exp,Scope * sc)40*627f7eb2Smrg FuncDeclaration *buildArrayOp(Identifier *ident, BinExp *exp, Scope *sc)
41*627f7eb2Smrg {
42*627f7eb2Smrg     Parameters *fparams = new Parameters();
43*627f7eb2Smrg     Expression *loopbody = buildArrayLoop(exp, fparams);
44*627f7eb2Smrg 
45*627f7eb2Smrg     /* Construct the function body:
46*627f7eb2Smrg      *  foreach (i; 0 .. p.length)    for (size_t i = 0; i < p.length; i++)
47*627f7eb2Smrg      *      loopbody;
48*627f7eb2Smrg      *  return p;
49*627f7eb2Smrg      */
50*627f7eb2Smrg 
51*627f7eb2Smrg     Parameter *p = (*fparams)[0];
52*627f7eb2Smrg     // foreach (i; 0 .. p.length)
53*627f7eb2Smrg     Statement *s1 = new ForeachRangeStatement(Loc(), TOKforeach,
54*627f7eb2Smrg         new Parameter(0, NULL, Id::p, NULL),
55*627f7eb2Smrg         new IntegerExp(Loc(), 0, Type::tsize_t),
56*627f7eb2Smrg         new ArrayLengthExp(Loc(), new IdentifierExp(Loc(), p->ident)),
57*627f7eb2Smrg         new ExpStatement(Loc(), loopbody),
58*627f7eb2Smrg         Loc());
59*627f7eb2Smrg     //printf("%s\n", s1->toChars());
60*627f7eb2Smrg     Statement *s2 = new ReturnStatement(Loc(), new IdentifierExp(Loc(), p->ident));
61*627f7eb2Smrg     //printf("s2: %s\n", s2->toChars());
62*627f7eb2Smrg     Statement *fbody = new CompoundStatement(Loc(), s1, s2);
63*627f7eb2Smrg 
64*627f7eb2Smrg     // Built-in array ops should be @trusted, pure, nothrow and nogc
65*627f7eb2Smrg     StorageClass stc = STCtrusted | STCpure | STCnothrow | STCnogc;
66*627f7eb2Smrg 
67*627f7eb2Smrg     /* Construct the function
68*627f7eb2Smrg      */
69*627f7eb2Smrg     TypeFunction *ftype = new TypeFunction(fparams, exp->e1->type, 0, LINKc, stc);
70*627f7eb2Smrg     //printf("fd: %s %s\n", ident->toChars(), ftype->toChars());
71*627f7eb2Smrg     FuncDeclaration *fd = new FuncDeclaration(Loc(), Loc(), ident, STCundefined, ftype);
72*627f7eb2Smrg     fd->fbody = fbody;
73*627f7eb2Smrg     fd->protection = Prot(PROTpublic);
74*627f7eb2Smrg     fd->linkage = LINKc;
75*627f7eb2Smrg     fd->isArrayOp = 1;
76*627f7eb2Smrg 
77*627f7eb2Smrg     sc->_module->importedFrom->members->push(fd);
78*627f7eb2Smrg 
79*627f7eb2Smrg     sc = sc->push();
80*627f7eb2Smrg     sc->parent = sc->_module->importedFrom;
81*627f7eb2Smrg     sc->stc = 0;
82*627f7eb2Smrg     sc->linkage = LINKc;
83*627f7eb2Smrg     fd->semantic(sc);
84*627f7eb2Smrg     fd->semantic2(sc);
85*627f7eb2Smrg     unsigned errors = global.startGagging();
86*627f7eb2Smrg     fd->semantic3(sc);
87*627f7eb2Smrg     if (global.endGagging(errors))
88*627f7eb2Smrg     {
89*627f7eb2Smrg         fd->type = Type::terror;
90*627f7eb2Smrg         fd->errors = true;
91*627f7eb2Smrg         fd->fbody = NULL;
92*627f7eb2Smrg     }
93*627f7eb2Smrg     sc->pop();
94*627f7eb2Smrg 
95*627f7eb2Smrg     return fd;
96*627f7eb2Smrg }
97*627f7eb2Smrg 
98*627f7eb2Smrg /**********************************************
99*627f7eb2Smrg  * Check that there are no uses of arrays without [].
100*627f7eb2Smrg  */
isArrayOpValid(Expression * e)101*627f7eb2Smrg bool isArrayOpValid(Expression *e)
102*627f7eb2Smrg {
103*627f7eb2Smrg     if (e->op == TOKslice)
104*627f7eb2Smrg         return true;
105*627f7eb2Smrg     if (e->op == TOKarrayliteral)
106*627f7eb2Smrg     {
107*627f7eb2Smrg         Type *t = e->type->toBasetype();
108*627f7eb2Smrg         while (t->ty == Tarray || t->ty == Tsarray)
109*627f7eb2Smrg             t = t->nextOf()->toBasetype();
110*627f7eb2Smrg         return (t->ty != Tvoid);
111*627f7eb2Smrg     }
112*627f7eb2Smrg     Type *tb = e->type->toBasetype();
113*627f7eb2Smrg     if (tb->ty == Tarray || tb->ty == Tsarray)
114*627f7eb2Smrg     {
115*627f7eb2Smrg         if (isUnaArrayOp(e->op))
116*627f7eb2Smrg         {
117*627f7eb2Smrg              return isArrayOpValid(((UnaExp *)e)->e1);
118*627f7eb2Smrg         }
119*627f7eb2Smrg         if (isBinArrayOp(e->op) ||
120*627f7eb2Smrg             isBinAssignArrayOp(e->op) ||
121*627f7eb2Smrg             e->op == TOKassign)
122*627f7eb2Smrg         {
123*627f7eb2Smrg             BinExp *be = (BinExp *)e;
124*627f7eb2Smrg             return isArrayOpValid(be->e1) && isArrayOpValid(be->e2);
125*627f7eb2Smrg         }
126*627f7eb2Smrg         if (e->op == TOKconstruct)
127*627f7eb2Smrg         {
128*627f7eb2Smrg             BinExp *be = (BinExp *)e;
129*627f7eb2Smrg             return be->e1->op == TOKslice && isArrayOpValid(be->e2);
130*627f7eb2Smrg         }
131*627f7eb2Smrg         if (e->op == TOKcall)
132*627f7eb2Smrg         {
133*627f7eb2Smrg              return false; // TODO: Decide if [] is required after arrayop calls.
134*627f7eb2Smrg         }
135*627f7eb2Smrg         else
136*627f7eb2Smrg         {
137*627f7eb2Smrg             return false;
138*627f7eb2Smrg         }
139*627f7eb2Smrg     }
140*627f7eb2Smrg     return true;
141*627f7eb2Smrg }
142*627f7eb2Smrg 
isNonAssignmentArrayOp(Expression * e)143*627f7eb2Smrg bool isNonAssignmentArrayOp(Expression *e)
144*627f7eb2Smrg {
145*627f7eb2Smrg     if (e->op == TOKslice)
146*627f7eb2Smrg         return isNonAssignmentArrayOp(((SliceExp *)e)->e1);
147*627f7eb2Smrg 
148*627f7eb2Smrg     Type *tb = e->type->toBasetype();
149*627f7eb2Smrg     if (tb->ty == Tarray || tb->ty == Tsarray)
150*627f7eb2Smrg     {
151*627f7eb2Smrg         return (isUnaArrayOp(e->op) || isBinArrayOp(e->op));
152*627f7eb2Smrg     }
153*627f7eb2Smrg     return false;
154*627f7eb2Smrg }
155*627f7eb2Smrg 
checkNonAssignmentArrayOp(Expression * e,bool suggestion)156*627f7eb2Smrg bool checkNonAssignmentArrayOp(Expression *e, bool suggestion)
157*627f7eb2Smrg {
158*627f7eb2Smrg     if (isNonAssignmentArrayOp(e))
159*627f7eb2Smrg     {
160*627f7eb2Smrg         const char *s = "";
161*627f7eb2Smrg         if (suggestion)
162*627f7eb2Smrg             s = " (possible missing [])";
163*627f7eb2Smrg         e->error("array operation %s without destination memory not allowed%s", e->toChars(), s);
164*627f7eb2Smrg         return true;
165*627f7eb2Smrg     }
166*627f7eb2Smrg     return false;
167*627f7eb2Smrg }
168*627f7eb2Smrg 
169*627f7eb2Smrg /***********************************
170*627f7eb2Smrg  * Construct the array operation expression.
171*627f7eb2Smrg  */
172*627f7eb2Smrg 
arrayOp(BinExp * e,Scope * sc)173*627f7eb2Smrg Expression *arrayOp(BinExp *e, Scope *sc)
174*627f7eb2Smrg {
175*627f7eb2Smrg     //printf("BinExp::arrayOp() %s\n", toChars());
176*627f7eb2Smrg 
177*627f7eb2Smrg     Type *tb = e->type->toBasetype();
178*627f7eb2Smrg     assert(tb->ty == Tarray || tb->ty == Tsarray);
179*627f7eb2Smrg     Type *tbn = tb->nextOf()->toBasetype();
180*627f7eb2Smrg     if (tbn->ty == Tvoid)
181*627f7eb2Smrg     {
182*627f7eb2Smrg         e->error("cannot perform array operations on void[] arrays");
183*627f7eb2Smrg         return new ErrorExp();
184*627f7eb2Smrg     }
185*627f7eb2Smrg     if (!isArrayOpValid(e))
186*627f7eb2Smrg     {
187*627f7eb2Smrg         e->error("invalid array operation %s (possible missing [])", e->toChars());
188*627f7eb2Smrg         return new ErrorExp();
189*627f7eb2Smrg     }
190*627f7eb2Smrg 
191*627f7eb2Smrg     Expressions *arguments = new Expressions();
192*627f7eb2Smrg 
193*627f7eb2Smrg     /* The expression to generate an array operation for is mangled
194*627f7eb2Smrg      * into a name to use as the array operation function name.
195*627f7eb2Smrg      * Mangle in the operands and operators in RPN order, and type.
196*627f7eb2Smrg      */
197*627f7eb2Smrg     OutBuffer buf;
198*627f7eb2Smrg     buf.writestring("_array");
199*627f7eb2Smrg     buildArrayIdent(e, &buf, arguments);
200*627f7eb2Smrg     buf.writeByte('_');
201*627f7eb2Smrg 
202*627f7eb2Smrg     /* Append deco of array element type
203*627f7eb2Smrg      */
204*627f7eb2Smrg     buf.writestring(e->type->toBasetype()->nextOf()->toBasetype()->mutableOf()->deco);
205*627f7eb2Smrg 
206*627f7eb2Smrg     char *name = buf.peekString();
207*627f7eb2Smrg     Identifier *ident = Identifier::idPool(name);
208*627f7eb2Smrg 
209*627f7eb2Smrg     FuncDeclaration **pFd = (FuncDeclaration **)dmd_aaGet(&arrayfuncs, (void *)ident);
210*627f7eb2Smrg     FuncDeclaration *fd = *pFd;
211*627f7eb2Smrg 
212*627f7eb2Smrg     if (!fd)
213*627f7eb2Smrg         fd = buildArrayOp(ident, e, sc);
214*627f7eb2Smrg 
215*627f7eb2Smrg     if (fd && fd->errors)
216*627f7eb2Smrg     {
217*627f7eb2Smrg         const char *fmt;
218*627f7eb2Smrg         if (tbn->ty == Tstruct || tbn->ty == Tclass)
219*627f7eb2Smrg             fmt = "invalid array operation '%s' because %s doesn't support necessary arithmetic operations";
220*627f7eb2Smrg         else if (!tbn->isscalar())
221*627f7eb2Smrg             fmt = "invalid array operation '%s' because %s is not a scalar type";
222*627f7eb2Smrg         else
223*627f7eb2Smrg             fmt = "invalid array operation '%s' for element type %s";
224*627f7eb2Smrg 
225*627f7eb2Smrg         e->error(fmt, e->toChars(), tbn->toChars());
226*627f7eb2Smrg         return new ErrorExp();
227*627f7eb2Smrg     }
228*627f7eb2Smrg 
229*627f7eb2Smrg     *pFd = fd;
230*627f7eb2Smrg 
231*627f7eb2Smrg     Expression *ev = new VarExp(e->loc, fd);
232*627f7eb2Smrg     Expression *ec = new CallExp(e->loc, ev, arguments);
233*627f7eb2Smrg 
234*627f7eb2Smrg     return semantic(ec, sc);
235*627f7eb2Smrg }
236*627f7eb2Smrg 
arrayOp(BinAssignExp * e,Scope * sc)237*627f7eb2Smrg Expression *arrayOp(BinAssignExp *e, Scope *sc)
238*627f7eb2Smrg {
239*627f7eb2Smrg     //printf("BinAssignExp::arrayOp() %s\n", toChars());
240*627f7eb2Smrg 
241*627f7eb2Smrg     /* Check that the elements of e1 can be assigned to
242*627f7eb2Smrg      */
243*627f7eb2Smrg     Type *tn = e->e1->type->toBasetype()->nextOf();
244*627f7eb2Smrg 
245*627f7eb2Smrg     if (tn && (!tn->isMutable() || !tn->isAssignable()))
246*627f7eb2Smrg     {
247*627f7eb2Smrg         e->error("slice %s is not mutable", e->e1->toChars());
248*627f7eb2Smrg         return new ErrorExp();
249*627f7eb2Smrg     }
250*627f7eb2Smrg     if (e->e1->op == TOKarrayliteral)
251*627f7eb2Smrg     {
252*627f7eb2Smrg         return e->e1->modifiableLvalue(sc, e->e1);
253*627f7eb2Smrg     }
254*627f7eb2Smrg 
255*627f7eb2Smrg     return arrayOp((BinExp *)e, sc);
256*627f7eb2Smrg }
257*627f7eb2Smrg 
258*627f7eb2Smrg /******************************************
259*627f7eb2Smrg  * Construct the identifier for the array operation function,
260*627f7eb2Smrg  * and build the argument list to pass to it.
261*627f7eb2Smrg  */
262*627f7eb2Smrg 
buildArrayIdent(Expression * e,OutBuffer * buf,Expressions * arguments)263*627f7eb2Smrg void buildArrayIdent(Expression *e, OutBuffer *buf, Expressions *arguments)
264*627f7eb2Smrg {
265*627f7eb2Smrg     class BuildArrayIdentVisitor : public Visitor
266*627f7eb2Smrg     {
267*627f7eb2Smrg         OutBuffer *buf;
268*627f7eb2Smrg         Expressions *arguments;
269*627f7eb2Smrg     public:
270*627f7eb2Smrg         BuildArrayIdentVisitor(OutBuffer *buf, Expressions *arguments)
271*627f7eb2Smrg             : buf(buf), arguments(arguments)
272*627f7eb2Smrg         {
273*627f7eb2Smrg         }
274*627f7eb2Smrg 
275*627f7eb2Smrg         void visit(Expression *e)
276*627f7eb2Smrg         {
277*627f7eb2Smrg             buf->writestring("Exp");
278*627f7eb2Smrg             arguments->shift(e);
279*627f7eb2Smrg         }
280*627f7eb2Smrg 
281*627f7eb2Smrg         void visit(CastExp *e)
282*627f7eb2Smrg         {
283*627f7eb2Smrg             Type *tb = e->type->toBasetype();
284*627f7eb2Smrg             if (tb->ty == Tarray || tb->ty == Tsarray)
285*627f7eb2Smrg             {
286*627f7eb2Smrg                 e->e1->accept(this);
287*627f7eb2Smrg             }
288*627f7eb2Smrg             else
289*627f7eb2Smrg                 visit((Expression *)e);
290*627f7eb2Smrg         }
291*627f7eb2Smrg 
292*627f7eb2Smrg         void visit(ArrayLiteralExp *e)
293*627f7eb2Smrg         {
294*627f7eb2Smrg             buf->writestring("Slice");
295*627f7eb2Smrg             arguments->shift(e);
296*627f7eb2Smrg         }
297*627f7eb2Smrg 
298*627f7eb2Smrg         void visit(SliceExp *e)
299*627f7eb2Smrg         {
300*627f7eb2Smrg             buf->writestring("Slice");
301*627f7eb2Smrg             arguments->shift(e);
302*627f7eb2Smrg         }
303*627f7eb2Smrg 
304*627f7eb2Smrg         void visit(AssignExp *e)
305*627f7eb2Smrg         {
306*627f7eb2Smrg             /* Evaluate assign expressions right to left
307*627f7eb2Smrg              */
308*627f7eb2Smrg             e->e2->accept(this);
309*627f7eb2Smrg             e->e1->accept(this);
310*627f7eb2Smrg             buf->writestring("Assign");
311*627f7eb2Smrg         }
312*627f7eb2Smrg 
313*627f7eb2Smrg         void visit(BinAssignExp *e)
314*627f7eb2Smrg         {
315*627f7eb2Smrg             /* Evaluate assign expressions right to left
316*627f7eb2Smrg              */
317*627f7eb2Smrg             e->e2->accept(this);
318*627f7eb2Smrg             e->e1->accept(this);
319*627f7eb2Smrg             const char *s;
320*627f7eb2Smrg             switch(e->op)
321*627f7eb2Smrg             {
322*627f7eb2Smrg             case TOKaddass: s = "Addass"; break;
323*627f7eb2Smrg             case TOKminass: s = "Minass"; break;
324*627f7eb2Smrg             case TOKmulass: s = "Mulass"; break;
325*627f7eb2Smrg             case TOKdivass: s = "Divass"; break;
326*627f7eb2Smrg             case TOKmodass: s = "Modass"; break;
327*627f7eb2Smrg             case TOKxorass: s = "Xorass"; break;
328*627f7eb2Smrg             case TOKandass: s = "Andass"; break;
329*627f7eb2Smrg             case TOKorass:  s = "Orass";  break;
330*627f7eb2Smrg             case TOKpowass: s = "Powass"; break;
331*627f7eb2Smrg             default: assert(0);
332*627f7eb2Smrg             }
333*627f7eb2Smrg             buf->writestring(s);
334*627f7eb2Smrg         }
335*627f7eb2Smrg 
336*627f7eb2Smrg         void visit(NegExp *e)
337*627f7eb2Smrg         {
338*627f7eb2Smrg             e->e1->accept(this);
339*627f7eb2Smrg             buf->writestring("Neg");
340*627f7eb2Smrg         }
341*627f7eb2Smrg 
342*627f7eb2Smrg         void visit(ComExp *e)
343*627f7eb2Smrg         {
344*627f7eb2Smrg             e->e1->accept(this);
345*627f7eb2Smrg             buf->writestring("Com");
346*627f7eb2Smrg         }
347*627f7eb2Smrg 
348*627f7eb2Smrg         void visit(BinExp *e)
349*627f7eb2Smrg         {
350*627f7eb2Smrg             /* Evaluate assign expressions left to right
351*627f7eb2Smrg              */
352*627f7eb2Smrg             const char *s = NULL;
353*627f7eb2Smrg             switch(e->op)
354*627f7eb2Smrg             {
355*627f7eb2Smrg             case TOKadd: s = "Add"; break;
356*627f7eb2Smrg             case TOKmin: s = "Min"; break;
357*627f7eb2Smrg             case TOKmul: s = "Mul"; break;
358*627f7eb2Smrg             case TOKdiv: s = "Div"; break;
359*627f7eb2Smrg             case TOKmod: s = "Mod"; break;
360*627f7eb2Smrg             case TOKxor: s = "Xor"; break;
361*627f7eb2Smrg             case TOKand: s = "And"; break;
362*627f7eb2Smrg             case TOKor:  s = "Or";  break;
363*627f7eb2Smrg             case TOKpow: s = "Pow"; break;
364*627f7eb2Smrg             default: break;
365*627f7eb2Smrg             }
366*627f7eb2Smrg             if (s)
367*627f7eb2Smrg             {
368*627f7eb2Smrg                 Type *tb = e->type->toBasetype();
369*627f7eb2Smrg                 Type *t1 = e->e1->type->toBasetype();
370*627f7eb2Smrg                 Type *t2 = e->e2->type->toBasetype();
371*627f7eb2Smrg                 e->e1->accept(this);
372*627f7eb2Smrg                 if (t1->ty == Tarray &&
373*627f7eb2Smrg                     ((t2->ty == Tarray && !t1->equivalent(tb)) ||
374*627f7eb2Smrg                      (t2->ty != Tarray && !t1->nextOf()->equivalent(e->e2->type))))
375*627f7eb2Smrg                 {
376*627f7eb2Smrg                     // Bugzilla 12780: if A is narrower than B
377*627f7eb2Smrg                     //  A[] op B[]
378*627f7eb2Smrg                     //  A[] op B
379*627f7eb2Smrg                     buf->writestring("Of");
380*627f7eb2Smrg                     buf->writestring(t1->nextOf()->mutableOf()->deco);
381*627f7eb2Smrg                 }
382*627f7eb2Smrg                 e->e2->accept(this);
383*627f7eb2Smrg                 if (t2->ty == Tarray &&
384*627f7eb2Smrg                     ((t1->ty == Tarray && !t2->equivalent(tb)) ||
385*627f7eb2Smrg                      (t1->ty != Tarray && !t2->nextOf()->equivalent(e->e1->type))))
386*627f7eb2Smrg                 {
387*627f7eb2Smrg                     // Bugzilla 12780: if B is narrower than A:
388*627f7eb2Smrg                     //  A[] op B[]
389*627f7eb2Smrg                     //  A op B[]
390*627f7eb2Smrg                     buf->writestring("Of");
391*627f7eb2Smrg                     buf->writestring(t2->nextOf()->mutableOf()->deco);
392*627f7eb2Smrg                 }
393*627f7eb2Smrg                 buf->writestring(s);
394*627f7eb2Smrg             }
395*627f7eb2Smrg             else
396*627f7eb2Smrg                 visit((Expression *)e);
397*627f7eb2Smrg         }
398*627f7eb2Smrg     };
399*627f7eb2Smrg 
400*627f7eb2Smrg     BuildArrayIdentVisitor v(buf, arguments);
401*627f7eb2Smrg     e->accept(&v);
402*627f7eb2Smrg }
403*627f7eb2Smrg 
404*627f7eb2Smrg /******************************************
405*627f7eb2Smrg  * Construct the inner loop for the array operation function,
406*627f7eb2Smrg  * and build the parameter list.
407*627f7eb2Smrg  */
408*627f7eb2Smrg 
buildArrayLoop(Expression * e,Parameters * fparams)409*627f7eb2Smrg Expression *buildArrayLoop(Expression *e, Parameters *fparams)
410*627f7eb2Smrg {
411*627f7eb2Smrg     class BuildArrayLoopVisitor : public Visitor
412*627f7eb2Smrg     {
413*627f7eb2Smrg         Parameters *fparams;
414*627f7eb2Smrg         Expression *result;
415*627f7eb2Smrg 
416*627f7eb2Smrg     public:
417*627f7eb2Smrg         BuildArrayLoopVisitor(Parameters *fparams)
418*627f7eb2Smrg             : fparams(fparams), result(NULL)
419*627f7eb2Smrg         {
420*627f7eb2Smrg         }
421*627f7eb2Smrg 
422*627f7eb2Smrg         void visit(Expression *e)
423*627f7eb2Smrg         {
424*627f7eb2Smrg             Identifier *id = Identifier::generateId("c", fparams->dim);
425*627f7eb2Smrg             Parameter *param = new Parameter(0, e->type, id, NULL);
426*627f7eb2Smrg             fparams->shift(param);
427*627f7eb2Smrg             result = new IdentifierExp(Loc(), id);
428*627f7eb2Smrg         }
429*627f7eb2Smrg 
430*627f7eb2Smrg         void visit(CastExp *e)
431*627f7eb2Smrg         {
432*627f7eb2Smrg             Type *tb = e->type->toBasetype();
433*627f7eb2Smrg             if (tb->ty == Tarray || tb->ty == Tsarray)
434*627f7eb2Smrg             {
435*627f7eb2Smrg                 e->e1->accept(this);
436*627f7eb2Smrg             }
437*627f7eb2Smrg             else
438*627f7eb2Smrg                 visit((Expression *)e);
439*627f7eb2Smrg         }
440*627f7eb2Smrg 
441*627f7eb2Smrg         void visit(ArrayLiteralExp *e)
442*627f7eb2Smrg         {
443*627f7eb2Smrg             Identifier *id = Identifier::generateId("p", fparams->dim);
444*627f7eb2Smrg             Parameter *param = new Parameter(STCconst, e->type, id, NULL);
445*627f7eb2Smrg             fparams->shift(param);
446*627f7eb2Smrg             Expression *ie = new IdentifierExp(Loc(), id);
447*627f7eb2Smrg             Expression *index = new IdentifierExp(Loc(), Id::p);
448*627f7eb2Smrg             result = new ArrayExp(Loc(), ie, index);
449*627f7eb2Smrg         }
450*627f7eb2Smrg 
451*627f7eb2Smrg         void visit(SliceExp *e)
452*627f7eb2Smrg         {
453*627f7eb2Smrg             Identifier *id = Identifier::generateId("p", fparams->dim);
454*627f7eb2Smrg             Parameter *param = new Parameter(STCconst, e->type, id, NULL);
455*627f7eb2Smrg             fparams->shift(param);
456*627f7eb2Smrg             Expression *ie = new IdentifierExp(Loc(), id);
457*627f7eb2Smrg             Expression *index = new IdentifierExp(Loc(), Id::p);
458*627f7eb2Smrg             result = new ArrayExp(Loc(), ie, index);
459*627f7eb2Smrg         }
460*627f7eb2Smrg 
461*627f7eb2Smrg         void visit(AssignExp *e)
462*627f7eb2Smrg         {
463*627f7eb2Smrg             /* Evaluate assign expressions right to left
464*627f7eb2Smrg              */
465*627f7eb2Smrg             Expression *ex2 = buildArrayLoop(e->e2);
466*627f7eb2Smrg             /* Need the cast because:
467*627f7eb2Smrg              *   b = c + p[i];
468*627f7eb2Smrg              * where b is a byte fails because (c + p[i]) is an int
469*627f7eb2Smrg              * which cannot be implicitly cast to byte.
470*627f7eb2Smrg              */
471*627f7eb2Smrg             ex2 = new CastExp(Loc(), ex2, e->e1->type->nextOf());
472*627f7eb2Smrg             Expression *ex1 = buildArrayLoop(e->e1);
473*627f7eb2Smrg             Parameter *param = (*fparams)[0];
474*627f7eb2Smrg             param->storageClass = 0;
475*627f7eb2Smrg             result = new AssignExp(Loc(), ex1, ex2);
476*627f7eb2Smrg         }
477*627f7eb2Smrg 
478*627f7eb2Smrg         void visit(BinAssignExp *e)
479*627f7eb2Smrg         {
480*627f7eb2Smrg             /* Evaluate assign expressions right to left
481*627f7eb2Smrg              */
482*627f7eb2Smrg             Expression *ex2 = buildArrayLoop(e->e2);
483*627f7eb2Smrg             Expression *ex1 = buildArrayLoop(e->e1);
484*627f7eb2Smrg             Parameter *param = (*fparams)[0];
485*627f7eb2Smrg             param->storageClass = 0;
486*627f7eb2Smrg             switch(e->op)
487*627f7eb2Smrg             {
488*627f7eb2Smrg             case TOKaddass: result = new AddAssignExp(e->loc, ex1, ex2); return;
489*627f7eb2Smrg             case TOKminass: result = new MinAssignExp(e->loc, ex1, ex2); return;
490*627f7eb2Smrg             case TOKmulass: result = new MulAssignExp(e->loc, ex1, ex2); return;
491*627f7eb2Smrg             case TOKdivass: result = new DivAssignExp(e->loc, ex1, ex2); return;
492*627f7eb2Smrg             case TOKmodass: result = new ModAssignExp(e->loc, ex1, ex2); return;
493*627f7eb2Smrg             case TOKxorass: result = new XorAssignExp(e->loc, ex1, ex2); return;
494*627f7eb2Smrg             case TOKandass: result = new AndAssignExp(e->loc, ex1, ex2); return;
495*627f7eb2Smrg             case TOKorass:  result = new OrAssignExp(e->loc, ex1, ex2); return;
496*627f7eb2Smrg             case TOKpowass: result = new PowAssignExp(e->loc, ex1, ex2); return;
497*627f7eb2Smrg             default:
498*627f7eb2Smrg                 assert(0);
499*627f7eb2Smrg             }
500*627f7eb2Smrg         }
501*627f7eb2Smrg 
502*627f7eb2Smrg         void visit(NegExp *e)
503*627f7eb2Smrg         {
504*627f7eb2Smrg             Expression *ex1 = buildArrayLoop(e->e1);
505*627f7eb2Smrg             result = new NegExp(Loc(), ex1);
506*627f7eb2Smrg         }
507*627f7eb2Smrg 
508*627f7eb2Smrg         void visit(ComExp *e)
509*627f7eb2Smrg         {
510*627f7eb2Smrg             Expression *ex1 = buildArrayLoop(e->e1);
511*627f7eb2Smrg             result = new ComExp(Loc(), ex1);
512*627f7eb2Smrg         }
513*627f7eb2Smrg 
514*627f7eb2Smrg         void visit(BinExp *e)
515*627f7eb2Smrg         {
516*627f7eb2Smrg             if (isBinArrayOp(e->op))
517*627f7eb2Smrg             {
518*627f7eb2Smrg                 /* Evaluate assign expressions left to right
519*627f7eb2Smrg                  */
520*627f7eb2Smrg                 BinExp *be = (BinExp *)e->copy();
521*627f7eb2Smrg                 be->e1 = buildArrayLoop(be->e1);
522*627f7eb2Smrg                 be->e2 = buildArrayLoop(be->e2);
523*627f7eb2Smrg                 be->type = NULL;
524*627f7eb2Smrg                 result = be;
525*627f7eb2Smrg                 return;
526*627f7eb2Smrg             }
527*627f7eb2Smrg             else
528*627f7eb2Smrg             {
529*627f7eb2Smrg                 visit((Expression *)e);
530*627f7eb2Smrg                 return;
531*627f7eb2Smrg             }
532*627f7eb2Smrg         }
533*627f7eb2Smrg 
534*627f7eb2Smrg         Expression *buildArrayLoop(Expression *e)
535*627f7eb2Smrg         {
536*627f7eb2Smrg             e->accept(this);
537*627f7eb2Smrg             return result;
538*627f7eb2Smrg         }
539*627f7eb2Smrg     };
540*627f7eb2Smrg 
541*627f7eb2Smrg     BuildArrayLoopVisitor v(fparams);
542*627f7eb2Smrg     return v.buildArrayLoop(e);
543*627f7eb2Smrg }
544*627f7eb2Smrg 
545*627f7eb2Smrg /***********************************************
546*627f7eb2Smrg  * Test if expression is a unary array op.
547*627f7eb2Smrg  */
548*627f7eb2Smrg 
isUnaArrayOp(TOK op)549*627f7eb2Smrg bool isUnaArrayOp(TOK op)
550*627f7eb2Smrg {
551*627f7eb2Smrg     switch (op)
552*627f7eb2Smrg     {
553*627f7eb2Smrg     case TOKneg:
554*627f7eb2Smrg     case TOKtilde:
555*627f7eb2Smrg         return true;
556*627f7eb2Smrg     default:
557*627f7eb2Smrg         break;
558*627f7eb2Smrg     }
559*627f7eb2Smrg     return false;
560*627f7eb2Smrg }
561*627f7eb2Smrg 
562*627f7eb2Smrg /***********************************************
563*627f7eb2Smrg  * Test if expression is a binary array op.
564*627f7eb2Smrg  */
565*627f7eb2Smrg 
isBinArrayOp(TOK op)566*627f7eb2Smrg bool isBinArrayOp(TOK op)
567*627f7eb2Smrg {
568*627f7eb2Smrg     switch (op)
569*627f7eb2Smrg     {
570*627f7eb2Smrg     case TOKadd:
571*627f7eb2Smrg     case TOKmin:
572*627f7eb2Smrg     case TOKmul:
573*627f7eb2Smrg     case TOKdiv:
574*627f7eb2Smrg     case TOKmod:
575*627f7eb2Smrg     case TOKxor:
576*627f7eb2Smrg     case TOKand:
577*627f7eb2Smrg     case TOKor:
578*627f7eb2Smrg     case TOKpow:
579*627f7eb2Smrg         return true;
580*627f7eb2Smrg     default:
581*627f7eb2Smrg         break;
582*627f7eb2Smrg     }
583*627f7eb2Smrg     return false;
584*627f7eb2Smrg }
585*627f7eb2Smrg 
586*627f7eb2Smrg /***********************************************
587*627f7eb2Smrg  * Test if expression is a binary assignment array op.
588*627f7eb2Smrg  */
589*627f7eb2Smrg 
isBinAssignArrayOp(TOK op)590*627f7eb2Smrg bool isBinAssignArrayOp(TOK op)
591*627f7eb2Smrg {
592*627f7eb2Smrg     switch (op)
593*627f7eb2Smrg     {
594*627f7eb2Smrg     case TOKaddass:
595*627f7eb2Smrg     case TOKminass:
596*627f7eb2Smrg     case TOKmulass:
597*627f7eb2Smrg     case TOKdivass:
598*627f7eb2Smrg     case TOKmodass:
599*627f7eb2Smrg     case TOKxorass:
600*627f7eb2Smrg     case TOKandass:
601*627f7eb2Smrg     case TOKorass:
602*627f7eb2Smrg     case TOKpowass:
603*627f7eb2Smrg         return true;
604*627f7eb2Smrg     default:
605*627f7eb2Smrg         break;
606*627f7eb2Smrg     }
607*627f7eb2Smrg     return false;
608*627f7eb2Smrg }
609*627f7eb2Smrg 
610*627f7eb2Smrg /***********************************************
611*627f7eb2Smrg  * Test if operand is a valid array op operand.
612*627f7eb2Smrg  */
613*627f7eb2Smrg 
isArrayOpOperand(Expression * e)614*627f7eb2Smrg bool isArrayOpOperand(Expression *e)
615*627f7eb2Smrg {
616*627f7eb2Smrg     //printf("Expression::isArrayOpOperand() %s\n", e->toChars());
617*627f7eb2Smrg     if (e->op == TOKslice)
618*627f7eb2Smrg         return true;
619*627f7eb2Smrg     if (e->op == TOKarrayliteral)
620*627f7eb2Smrg     {
621*627f7eb2Smrg         Type *t = e->type->toBasetype();
622*627f7eb2Smrg         while (t->ty == Tarray || t->ty == Tsarray)
623*627f7eb2Smrg             t = t->nextOf()->toBasetype();
624*627f7eb2Smrg         return (t->ty != Tvoid);
625*627f7eb2Smrg     }
626*627f7eb2Smrg     Type *tb = e->type->toBasetype();
627*627f7eb2Smrg     if (tb->ty == Tarray)
628*627f7eb2Smrg     {
629*627f7eb2Smrg         return (isUnaArrayOp(e->op) ||
630*627f7eb2Smrg                 isBinArrayOp(e->op) ||
631*627f7eb2Smrg                 isBinAssignArrayOp(e->op) ||
632*627f7eb2Smrg                 e->op == TOKassign);
633*627f7eb2Smrg     }
634*627f7eb2Smrg     return false;
635*627f7eb2Smrg }
636