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