~john-koepi/ubuntu/trusty/golang/default

« back to all changes in this revision

Viewing changes to src/cmd/gc/swt.c

  • Committer: Bazaar Package Importer
  • Author(s): Ondřej Surý
  • Date: 2011-04-20 17:36:48 UTC
  • Revision ID: james.westby@ubuntu.com-20110420173648-ifergoxyrm832trd
Tags: upstream-2011.03.07.1
Import upstream version 2011.03.07.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2009 The Go Authors. All rights reserved.
 
2
// Use of this source code is governed by a BSD-style
 
3
// license that can be found in the LICENSE file.
 
4
 
 
5
#include        "go.h"
 
6
 
 
7
enum
 
8
{
 
9
        Snorm           = 0,
 
10
        Strue,
 
11
        Sfalse,
 
12
        Stype,
 
13
 
 
14
        Tdefault,       // default case
 
15
        Texprconst,     // normal constant case
 
16
        Texprvar,       // normal variable case
 
17
        Ttypenil,       // case nil
 
18
        Ttypeconst,     // type hashes
 
19
        Ttypevar,       // interface type
 
20
 
 
21
        Ncase   = 4,    // count needed to split
 
22
};
 
23
 
 
24
typedef struct  Case    Case;
 
25
struct  Case
 
26
{
 
27
        Node*   node;           // points at case statement
 
28
        uint32  hash;           // hash of a type switch
 
29
        uint8   type;           // type of case
 
30
        uint8   diag;           // suppress multiple diagnostics
 
31
        uint16  ordinal;        // position in switch
 
32
        Case*   link;           // linked list to link
 
33
};
 
34
#define C       ((Case*)nil)
 
35
 
 
36
void
 
37
dumpcase(Case *c0)
 
38
{
 
39
        Case *c;
 
40
 
 
41
        for(c=c0; c!=C; c=c->link) {
 
42
                switch(c->type) {
 
43
                case Tdefault:
 
44
                        print("case-default\n");
 
45
                        print(" ord=%d\n", c->ordinal);
 
46
                        break;
 
47
                case Texprconst:
 
48
                        print("case-exprconst\n");
 
49
                        print(" ord=%d\n", c->ordinal);
 
50
                        break;
 
51
                case Texprvar:
 
52
                        print("case-exprvar\n");
 
53
                        print(" ord=%d\n", c->ordinal);
 
54
                        print(" op=%O\n", c->node->left->op);
 
55
                        break;
 
56
                case Ttypenil:
 
57
                        print("case-typenil\n");
 
58
                        print(" ord=%d\n", c->ordinal);
 
59
                        break;
 
60
                case Ttypeconst:
 
61
                        print("case-typeconst\n");
 
62
                        print(" ord=%d\n", c->ordinal);
 
63
                        print(" hash=%ux\n", c->hash);
 
64
                        break;
 
65
                case Ttypevar:
 
66
                        print("case-typevar\n");
 
67
                        print(" ord=%d\n", c->ordinal);
 
68
                        break;
 
69
                default:
 
70
                        print("case-???\n");
 
71
                        print(" ord=%d\n", c->ordinal);
 
72
                        print(" op=%O\n", c->node->left->op);
 
73
                        print(" hash=%ux\n", c->hash);
 
74
                        break;
 
75
                }
 
76
        }
 
77
        print("\n");
 
78
}
 
79
 
 
80
static int
 
81
ordlcmp(Case *c1, Case *c2)
 
82
{
 
83
        // sort default first
 
84
        if(c1->type == Tdefault)
 
85
                return -1;
 
86
        if(c2->type == Tdefault)
 
87
                return +1;
 
88
 
 
89
        // sort nil second
 
90
        if(c1->type == Ttypenil)
 
91
                return -1;
 
92
        if(c2->type == Ttypenil)
 
93
                return +1;
 
94
 
 
95
        // sort by ordinal
 
96
        if(c1->ordinal > c2->ordinal)
 
97
                return +1;
 
98
        if(c1->ordinal < c2->ordinal)
 
99
                return -1;
 
100
        return 0;
 
101
}
 
102
 
 
103
static int
 
104
exprcmp(Case *c1, Case *c2)
 
105
{
 
106
        int ct, n;
 
107
        Node *n1, *n2;
 
108
 
 
109
        // sort non-constants last
 
110
        if(c1->type != Texprconst)
 
111
                return +1;
 
112
        if(c2->type != Texprconst)
 
113
                return -1;
 
114
 
 
115
        n1 = c1->node->left;
 
116
        n2 = c2->node->left;
 
117
 
 
118
        ct = n1->val.ctype;
 
119
        if(ct != n2->val.ctype) {
 
120
                // invalid program, but return a sort
 
121
                // order so that we can give a better
 
122
                // error later.
 
123
                return ct - n2->val.ctype;
 
124
        }
 
125
 
 
126
        // sort by constant value
 
127
        n = 0;
 
128
        switch(ct) {
 
129
        case CTFLT:
 
130
                n = mpcmpfltflt(n1->val.u.fval, n2->val.u.fval);
 
131
                break;
 
132
        case CTINT:
 
133
                n = mpcmpfixfix(n1->val.u.xval, n2->val.u.xval);
 
134
                break;
 
135
        case CTSTR:
 
136
                n = cmpslit(n1, n2);
 
137
                break;
 
138
        }
 
139
 
 
140
        return n;
 
141
}
 
142
 
 
143
static int
 
144
typecmp(Case *c1, Case *c2)
 
145
{
 
146
 
 
147
        // sort non-constants last
 
148
        if(c1->type != Ttypeconst)
 
149
                return +1;
 
150
        if(c2->type != Ttypeconst)
 
151
                return -1;
 
152
 
 
153
        // sort by hash code
 
154
        if(c1->hash > c2->hash)
 
155
                return +1;
 
156
        if(c1->hash < c2->hash)
 
157
                return -1;
 
158
 
 
159
        // sort by ordinal so duplicate error
 
160
        // happens on later case.
 
161
        if(c1->ordinal > c2->ordinal)
 
162
                return +1;
 
163
        if(c1->ordinal < c2->ordinal)
 
164
                return -1;
 
165
        return 0;
 
166
}
 
167
 
 
168
static Case*
 
169
csort(Case *l, int(*f)(Case*, Case*))
 
170
{
 
171
        Case *l1, *l2, *le;
 
172
 
 
173
        if(l == C || l->link == C)
 
174
                return l;
 
175
 
 
176
        l1 = l;
 
177
        l2 = l;
 
178
        for(;;) {
 
179
                l2 = l2->link;
 
180
                if(l2 == C)
 
181
                        break;
 
182
                l2 = l2->link;
 
183
                if(l2 == C)
 
184
                        break;
 
185
                l1 = l1->link;
 
186
        }
 
187
 
 
188
        l2 = l1->link;
 
189
        l1->link = C;
 
190
        l1 = csort(l, f);
 
191
        l2 = csort(l2, f);
 
192
 
 
193
        /* set up lead element */
 
194
        if((*f)(l1, l2) < 0) {
 
195
                l = l1;
 
196
                l1 = l1->link;
 
197
        } else {
 
198
                l = l2;
 
199
                l2 = l2->link;
 
200
        }
 
201
        le = l;
 
202
 
 
203
        for(;;) {
 
204
                if(l1 == C) {
 
205
                        while(l2) {
 
206
                                le->link = l2;
 
207
                                le = l2;
 
208
                                l2 = l2->link;
 
209
                        }
 
210
                        le->link = C;
 
211
                        break;
 
212
                }
 
213
                if(l2 == C) {
 
214
                        while(l1) {
 
215
                                le->link = l1;
 
216
                                le = l1;
 
217
                                l1 = l1->link;
 
218
                        }
 
219
                        break;
 
220
                }
 
221
                if((*f)(l1, l2) < 0) {
 
222
                        le->link = l1;
 
223
                        le = l1;
 
224
                        l1 = l1->link;
 
225
                } else {
 
226
                        le->link = l2;
 
227
                        le = l2;
 
228
                        l2 = l2->link;
 
229
                }
 
230
        }
 
231
        le->link = C;
 
232
        return l;
 
233
}
 
234
 
 
235
static Node*
 
236
newlabel(void)
 
237
{
 
238
        static int label;
 
239
 
 
240
        label++;
 
241
        snprint(namebuf, sizeof(namebuf), "%.6d", label);
 
242
        return newname(lookup(namebuf));
 
243
}
 
244
 
 
245
/*
 
246
 * build separate list of statements and cases
 
247
 * make labels between cases and statements
 
248
 * deal with fallthrough, break, unreachable statements
 
249
 */
 
250
static void
 
251
casebody(Node *sw, Node *typeswvar)
 
252
{
 
253
        Node *os, *oc, *n, *c, *last;
 
254
        Node *def;
 
255
        NodeList *cas, *stat, *l, *lc;
 
256
        Node *go, *br;
 
257
        int32 lno, needvar;
 
258
 
 
259
        lno = setlineno(sw);
 
260
        if(sw->list == nil)
 
261
                return;
 
262
 
 
263
        cas = nil;      // cases
 
264
        stat = nil;     // statements
 
265
        def = N;        // defaults
 
266
        os = N;         // last statement
 
267
        oc = N;         // last case
 
268
        br = nod(OBREAK, N, N);
 
269
 
 
270
        for(l=sw->list; l; l=l->next) {
 
271
                n = l->n;
 
272
                lno = setlineno(n);
 
273
                if(n->op != OXCASE)
 
274
                        fatal("casebody %O", n->op);
 
275
                n->op = OCASE;
 
276
                needvar = count(n->list) != 1 || n->list->n->op == OLITERAL;
 
277
 
 
278
                go = nod(OGOTO, newlabel(), N);
 
279
                if(n->list == nil) {
 
280
                        if(def != N)
 
281
                                yyerror("more than one default case");
 
282
                        // reuse original default case
 
283
                        n->right = go;
 
284
                        def = n;
 
285
                }
 
286
 
 
287
                if(n->list != nil && n->list->next == nil) {
 
288
                        // one case - reuse OCASE node.
 
289
                        c = n->list->n;
 
290
                        n->left = c;
 
291
                        n->right = go;
 
292
                        n->list = nil;
 
293
                        cas = list(cas, n);
 
294
                } else {
 
295
                        // expand multi-valued cases
 
296
                        for(lc=n->list; lc; lc=lc->next) {
 
297
                                c = lc->n;
 
298
                                cas = list(cas, nod(OCASE, c, go));
 
299
                        }
 
300
                }
 
301
 
 
302
                stat = list(stat, nod(OLABEL, go->left, N));
 
303
                if(typeswvar && needvar && n->nname != N) {
 
304
                        NodeList *l;
 
305
 
 
306
                        l = list1(nod(ODCL, n->nname, N));
 
307
                        l = list(l, nod(OAS, n->nname, typeswvar));
 
308
                        typechecklist(l, Etop);
 
309
                        stat = concat(stat, l);
 
310
                }
 
311
                stat = concat(stat, n->nbody);
 
312
 
 
313
                // botch - shouldnt fall thru declaration
 
314
                last = stat->end->n;
 
315
                if(last->op == OXFALL) {
 
316
                        if(typeswvar) {
 
317
                                setlineno(last);
 
318
                                yyerror("cannot fallthrough in type switch");
 
319
                        }
 
320
                        last->op = OFALL;
 
321
                } else
 
322
                        stat = list(stat, br);
 
323
        }
 
324
 
 
325
        stat = list(stat, br);
 
326
        if(def)
 
327
                cas = list(cas, def);
 
328
 
 
329
        sw->list = cas;
 
330
        sw->nbody = stat;
 
331
        lineno = lno;
 
332
}
 
333
 
 
334
static Case*
 
335
mkcaselist(Node *sw, int arg)
 
336
{
 
337
        Node *n;
 
338
        Case *c, *c1, *c2;
 
339
        NodeList *l;
 
340
        int ord;
 
341
 
 
342
        c = C;
 
343
        ord = 0;
 
344
 
 
345
        for(l=sw->list; l; l=l->next) {
 
346
                n = l->n;
 
347
                c1 = mal(sizeof(*c1));
 
348
                c1->link = c;
 
349
                c = c1;
 
350
 
 
351
                ord++;
 
352
                c->ordinal = ord;
 
353
                c->node = n;
 
354
 
 
355
                if(n->left == N) {
 
356
                        c->type = Tdefault;
 
357
                        continue;
 
358
                }
 
359
 
 
360
                switch(arg) {
 
361
                case Stype:
 
362
                        c->hash = 0;
 
363
                        if(n->left->op == OLITERAL) {
 
364
                                c->type = Ttypenil;
 
365
                                continue;
 
366
                        }
 
367
                        if(istype(n->left->type, TINTER)) {
 
368
                                c->type = Ttypevar;
 
369
                                continue;
 
370
                        }
 
371
 
 
372
                        c->hash = typehash(n->left->type);
 
373
                        c->type = Ttypeconst;
 
374
                        continue;
 
375
 
 
376
                case Snorm:
 
377
                case Strue:
 
378
                case Sfalse:
 
379
                        c->type = Texprvar;
 
380
                        switch(consttype(n->left)) {
 
381
                        case CTFLT:
 
382
                        case CTINT:
 
383
                        case CTSTR:
 
384
                                c->type = Texprconst;
 
385
                        }
 
386
                        continue;
 
387
                }
 
388
        }
 
389
 
 
390
        if(c == C)
 
391
                return C;
 
392
 
 
393
        // sort by value and diagnose duplicate cases
 
394
        switch(arg) {
 
395
        case Stype:
 
396
                c = csort(c, typecmp);
 
397
                for(c1=c; c1!=C; c1=c1->link) {
 
398
                        for(c2=c1->link; c2!=C && c2->hash==c1->hash; c2=c2->link) {
 
399
                                if(c1->type == Ttypenil || c1->type == Tdefault)
 
400
                                        break;
 
401
                                if(c2->type == Ttypenil || c2->type == Tdefault)
 
402
                                        break;
 
403
                                if(!eqtype(c1->node->left->type, c2->node->left->type))
 
404
                                        continue;
 
405
                                yyerrorl(c2->node->lineno, "duplicate case in switch\n\tprevious case at %L", c1->node->lineno);
 
406
                        }
 
407
                }
 
408
                break;
 
409
        case Snorm:
 
410
        case Strue:
 
411
        case Sfalse:
 
412
                c = csort(c, exprcmp);
 
413
                for(c1=c; c1->link!=C; c1=c1->link) {
 
414
                        if(exprcmp(c1, c1->link) != 0)
 
415
                                continue;
 
416
                        setlineno(c1->link->node);
 
417
                        yyerror("duplicate case in switch\n\tprevious case at %L", c1->node->lineno);
 
418
                }
 
419
                break;
 
420
        }
 
421
 
 
422
        // put list back in processing order
 
423
        c = csort(c, ordlcmp);
 
424
        return c;
 
425
}
 
426
 
 
427
static  Node*   exprname;
 
428
 
 
429
static Node*
 
430
exprbsw(Case *c0, int ncase, int arg)
 
431
{
 
432
        NodeList *cas;
 
433
        Node *a, *n;
 
434
        Case *c;
 
435
        int i, half, lno;
 
436
 
 
437
        cas = nil;
 
438
        if(ncase < Ncase) {
 
439
                for(i=0; i<ncase; i++) {
 
440
                        n = c0->node;
 
441
                        lno = setlineno(n);
 
442
 
 
443
                        switch(arg) {
 
444
                        case Strue:
 
445
                                a = nod(OIF, N, N);
 
446
                                a->ntest = n->left;                     // if val
 
447
                                a->nbody = list1(n->right);                     // then goto l
 
448
                                break;
 
449
 
 
450
                        case Sfalse:
 
451
                                a = nod(OIF, N, N);
 
452
                                a->ntest = nod(ONOT, n->left, N);       // if !val
 
453
                                typecheck(&a->ntest, Erv);
 
454
                                a->nbody = list1(n->right);                     // then goto l
 
455
                                break;
 
456
 
 
457
                        default:
 
458
                                a = nod(OIF, N, N);
 
459
                                a->ntest = nod(OEQ, exprname, n->left); // if name == val
 
460
                                typecheck(&a->ntest, Erv);
 
461
                                a->nbody = list1(n->right);                     // then goto l
 
462
                                break;
 
463
                        }
 
464
 
 
465
                        cas = list(cas, a);
 
466
                        c0 = c0->link;
 
467
                        lineno = lno;
 
468
                }
 
469
                return liststmt(cas);
 
470
        }
 
471
 
 
472
        // find the middle and recur
 
473
        c = c0;
 
474
        half = ncase>>1;
 
475
        for(i=1; i<half; i++)
 
476
                c = c->link;
 
477
        a = nod(OIF, N, N);
 
478
        a->ntest = nod(OLE, exprname, c->node->left);
 
479
        typecheck(&a->ntest, Erv);
 
480
        a->nbody = list1(exprbsw(c0, half, arg));
 
481
        a->nelse = list1(exprbsw(c->link, ncase-half, arg));
 
482
        return a;
 
483
}
 
484
 
 
485
/*
 
486
 * normal (expression) switch.
 
487
 * rebulid case statements into if .. goto
 
488
 */
 
489
static void
 
490
exprswitch(Node *sw)
 
491
{
 
492
        Node *def;
 
493
        NodeList *cas;
 
494
        Node *a;
 
495
        Case *c0, *c, *c1;
 
496
        Type *t;
 
497
        int arg, ncase;
 
498
 
 
499
        casebody(sw, N);
 
500
 
 
501
        arg = Snorm;
 
502
        if(isconst(sw->ntest, CTBOOL)) {
 
503
                arg = Strue;
 
504
                if(sw->ntest->val.u.bval == 0)
 
505
                        arg = Sfalse;
 
506
        }
 
507
        walkexpr(&sw->ntest, &sw->ninit);
 
508
        t = sw->type;
 
509
        if(t == T)
 
510
                return;
 
511
 
 
512
        /*
 
513
         * convert the switch into OIF statements
 
514
         */
 
515
        exprname = N;
 
516
        cas = nil;
 
517
        if(arg != Strue && arg != Sfalse) {
 
518
                exprname = nod(OXXX, N, N);
 
519
                tempname(exprname, sw->ntest->type);
 
520
                cas = list1(nod(OAS, exprname, sw->ntest));
 
521
                typechecklist(cas, Etop);
 
522
        }
 
523
 
 
524
        c0 = mkcaselist(sw, arg);
 
525
        if(c0 != C && c0->type == Tdefault) {
 
526
                def = c0->node->right;
 
527
                c0 = c0->link;
 
528
        } else {
 
529
                def = nod(OBREAK, N, N);
 
530
        }
 
531
 
 
532
loop:
 
533
        if(c0 == C) {
 
534
                cas = list(cas, def);
 
535
                sw->nbody = concat(cas, sw->nbody);
 
536
                sw->list = nil;
 
537
                walkstmtlist(sw->nbody);
 
538
                return;
 
539
        }
 
540
 
 
541
        // deal with the variables one-at-a-time
 
542
        if(c0->type != Texprconst) {
 
543
                a = exprbsw(c0, 1, arg);
 
544
                cas = list(cas, a);
 
545
                c0 = c0->link;
 
546
                goto loop;
 
547
        }
 
548
 
 
549
        // do binary search on run of constants
 
550
        ncase = 1;
 
551
        for(c=c0; c->link!=C; c=c->link) {
 
552
                if(c->link->type != Texprconst)
 
553
                        break;
 
554
                ncase++;
 
555
        }
 
556
 
 
557
        // break the chain at the count
 
558
        c1 = c->link;
 
559
        c->link = C;
 
560
 
 
561
        // sort and compile constants
 
562
        c0 = csort(c0, exprcmp);
 
563
        a = exprbsw(c0, ncase, arg);
 
564
        cas = list(cas, a);
 
565
 
 
566
        c0 = c1;
 
567
        goto loop;
 
568
 
 
569
}
 
570
 
 
571
static  Node*   hashname;
 
572
static  Node*   facename;
 
573
static  Node*   boolname;
 
574
 
 
575
static Node*
 
576
typeone(Node *t)
 
577
{
 
578
        NodeList *init;
 
579
        Node *a, *b, *var;
 
580
 
 
581
        var = t->nname;
 
582
        init = nil;
 
583
        if(var == N) {
 
584
                typecheck(&nblank, Erv | Easgn);
 
585
                var = nblank;
 
586
        } else
 
587
                init = list1(nod(ODCL, var, N));
 
588
 
 
589
        a = nod(OAS2, N, N);
 
590
        a->list = list(list1(var), boolname);   // var,bool =
 
591
        b = nod(ODOTTYPE, facename, N);
 
592
        b->type = t->left->type;                // interface.(type)
 
593
        a->rlist = list1(b);
 
594
        typecheck(&a, Etop);
 
595
        init = list(init, a);
 
596
 
 
597
        b = nod(OIF, N, N);
 
598
        b->ntest = boolname;
 
599
        b->nbody = list1(t->right);             // if bool { goto l }
 
600
        a = liststmt(list(init, b));
 
601
        return a;
 
602
}
 
603
 
 
604
static Node*
 
605
typebsw(Case *c0, int ncase)
 
606
{
 
607
        NodeList *cas;
 
608
        Node *a, *n;
 
609
        Case *c;
 
610
        int i, half;
 
611
 
 
612
        cas = nil;
 
613
 
 
614
        if(ncase < Ncase) {
 
615
                for(i=0; i<ncase; i++) {
 
616
                        n = c0->node;
 
617
                        if(c0->type != Ttypeconst)
 
618
                                fatal("typebsw");
 
619
                        a = nod(OIF, N, N);
 
620
                        a->ntest = nod(OEQ, hashname, nodintconst(c0->hash));
 
621
                        typecheck(&a->ntest, Erv);
 
622
                        a->nbody = list1(n->right);
 
623
                        cas = list(cas, a);
 
624
                        c0 = c0->link;
 
625
                }
 
626
                return liststmt(cas);
 
627
        }
 
628
 
 
629
        // find the middle and recur
 
630
        c = c0;
 
631
        half = ncase>>1;
 
632
        for(i=1; i<half; i++)
 
633
                c = c->link;
 
634
        a = nod(OIF, N, N);
 
635
        a->ntest = nod(OLE, hashname, nodintconst(c->hash));
 
636
        typecheck(&a->ntest, Erv);
 
637
        a->nbody = list1(typebsw(c0, half));
 
638
        a->nelse = list1(typebsw(c->link, ncase-half));
 
639
        return a;
 
640
}
 
641
 
 
642
/*
 
643
 * convert switch of the form
 
644
 *      switch v := i.(type) { case t1: ..; case t2: ..; }
 
645
 * into if statements
 
646
 */
 
647
static void
 
648
typeswitch(Node *sw)
 
649
{
 
650
        Node *def;
 
651
        NodeList *cas, *hash;
 
652
        Node *a, *n;
 
653
        Case *c, *c0, *c1;
 
654
        int ncase;
 
655
        Type *t;
 
656
        Val v;
 
657
 
 
658
        if(sw->ntest == nil)
 
659
                return;
 
660
        if(sw->ntest->right == nil) {
 
661
                setlineno(sw);
 
662
                yyerror("type switch must have an assignment");
 
663
                return;
 
664
        }
 
665
        walkexpr(&sw->ntest->right, &sw->ninit);
 
666
        if(!istype(sw->ntest->right->type, TINTER)) {
 
667
                yyerror("type switch must be on an interface");
 
668
                return;
 
669
        }
 
670
        cas = nil;
 
671
 
 
672
        /*
 
673
         * predeclare temporary variables
 
674
         * and the boolean var
 
675
         */
 
676
        facename = nod(OXXX, N, N);
 
677
        tempname(facename, sw->ntest->right->type);
 
678
        a = nod(OAS, facename, sw->ntest->right);
 
679
        typecheck(&a, Etop);
 
680
        cas = list(cas, a);
 
681
 
 
682
        casebody(sw, facename);
 
683
 
 
684
        boolname = nod(OXXX, N, N);
 
685
        tempname(boolname, types[TBOOL]);
 
686
        typecheck(&boolname, Erv);
 
687
 
 
688
        hashname = nod(OXXX, N, N);
 
689
        tempname(hashname, types[TUINT32]);
 
690
        typecheck(&hashname, Erv);
 
691
 
 
692
        t = sw->ntest->right->type;
 
693
        if(isnilinter(t))
 
694
                a = syslook("efacethash", 1);
 
695
        else
 
696
                a = syslook("ifacethash", 1);
 
697
        argtype(a, t);
 
698
        a = nod(OCALL, a, N);
 
699
        a->list = list1(facename);
 
700
        a = nod(OAS, hashname, a);
 
701
        typecheck(&a, Etop);
 
702
        cas = list(cas, a);
 
703
 
 
704
        c0 = mkcaselist(sw, Stype);
 
705
        if(c0 != C && c0->type == Tdefault) {
 
706
                def = c0->node->right;
 
707
                c0 = c0->link;
 
708
        } else {
 
709
                def = nod(OBREAK, N, N);
 
710
        }
 
711
        
 
712
        /*
 
713
         * insert if statement into each case block
 
714
         */
 
715
        for(c=c0; c!=C; c=c->link) {
 
716
                n = c->node;
 
717
                switch(c->type) {
 
718
 
 
719
                case Ttypenil:
 
720
                        v.ctype = CTNIL;
 
721
                        a = nod(OIF, N, N);
 
722
                        a->ntest = nod(OEQ, facename, nodlit(v));
 
723
                        typecheck(&a->ntest, Erv);
 
724
                        a->nbody = list1(n->right);             // if i==nil { goto l }
 
725
                        n->right = a;
 
726
                        break;
 
727
                
 
728
                case Ttypevar:
 
729
                case Ttypeconst:
 
730
                        n->right = typeone(n);
 
731
                        break;
 
732
                }
 
733
        }
 
734
 
 
735
        /*
 
736
         * generate list of if statements, binary search for constant sequences
 
737
         */
 
738
        while(c0 != C) {
 
739
                if(c0->type != Ttypeconst) {
 
740
                        n = c0->node;
 
741
                        cas = list(cas, n->right);
 
742
                        c0=c0->link;
 
743
                        continue;
 
744
                }
 
745
                
 
746
                // identify run of constants
 
747
                c1 = c = c0;
 
748
                while(c->link!=C && c->link->type==Ttypeconst)
 
749
                        c = c->link;
 
750
                c0 = c->link;
 
751
                c->link = nil;
 
752
 
 
753
                // sort by hash
 
754
                c1 = csort(c1, typecmp);
 
755
                
 
756
                // for debugging: linear search
 
757
                if(0) {
 
758
                        for(c=c1; c!=C; c=c->link) {
 
759
                                n = c->node;
 
760
                                cas = list(cas, n->right);
 
761
                        }
 
762
                        continue;
 
763
                }
 
764
 
 
765
                // combine adjacent cases with the same hash
 
766
                ncase = 0;
 
767
                for(c=c1; c!=C; c=c->link) {
 
768
                        ncase++;
 
769
                        hash = list1(c->node->right);
 
770
                        while(c->link != C && c->link->hash == c->hash) {
 
771
                                hash = list(hash, c->link->node->right);
 
772
                                c->link = c->link->link;
 
773
                        }
 
774
                        c->node->right = liststmt(hash);
 
775
                }
 
776
                
 
777
                // binary search among cases to narrow by hash
 
778
                cas = list(cas, typebsw(c1, ncase));
 
779
        }
 
780
        if(nerrors == 0) {
 
781
                cas = list(cas, def);
 
782
                sw->nbody = concat(cas, sw->nbody);
 
783
                sw->list = nil;
 
784
                walkstmtlist(sw->nbody);
 
785
        }
 
786
}
 
787
 
 
788
void
 
789
walkswitch(Node *sw)
 
790
{
 
791
 
 
792
        /*
 
793
         * reorder the body into (OLIST, cases, statements)
 
794
         * cases have OGOTO into statements.
 
795
         * both have inserted OBREAK statements
 
796
         */
 
797
        walkstmtlist(sw->ninit);
 
798
        if(sw->ntest == N) {
 
799
                sw->ntest = nodbool(1);
 
800
                typecheck(&sw->ntest, Erv);
 
801
        }
 
802
 
 
803
        if(sw->ntest->op == OTYPESW) {
 
804
                typeswitch(sw);
 
805
//dump("sw", sw);
 
806
                return;
 
807
        }
 
808
        exprswitch(sw);
 
809
}
 
810
 
 
811
/*
 
812
 * type check switch statement
 
813
 */
 
814
void
 
815
typecheckswitch(Node *n)
 
816
{
 
817
        int top, lno;
 
818
        Type *t;
 
819
        NodeList *l, *ll;
 
820
        Node *ncase, *nvar;
 
821
        Node *def;
 
822
 
 
823
        lno = lineno;
 
824
        typechecklist(n->ninit, Etop);
 
825
 
 
826
        if(n->ntest != N && n->ntest->op == OTYPESW) {
 
827
                // type switch
 
828
                top = Etype;
 
829
                typecheck(&n->ntest->right, Erv);
 
830
                t = n->ntest->right->type;
 
831
                if(t != T && t->etype != TINTER)
 
832
                        yyerror("cannot type switch on non-interface value %+N", n->ntest->right);
 
833
        } else {
 
834
                // value switch
 
835
                top = Erv;
 
836
                if(n->ntest) {
 
837
                        typecheck(&n->ntest, Erv);
 
838
                        defaultlit(&n->ntest, T);
 
839
                        t = n->ntest->type;
 
840
                } else
 
841
                        t = types[TBOOL];
 
842
        }
 
843
        n->type = t;
 
844
 
 
845
        def = N;
 
846
        for(l=n->list; l; l=l->next) {
 
847
                ncase = l->n;
 
848
                setlineno(n);
 
849
                if(ncase->list == nil) {
 
850
                        // default
 
851
                        if(def != N)
 
852
                                yyerror("multiple defaults in switch (first at %L)", def->lineno);
 
853
                        else
 
854
                                def = ncase;
 
855
                } else {
 
856
                        for(ll=ncase->list; ll; ll=ll->next) {
 
857
                                setlineno(ll->n);
 
858
                                typecheck(&ll->n, Erv | Etype);
 
859
                                if(ll->n->type == T || t == T)
 
860
                                        continue;
 
861
                                switch(top) {
 
862
                                case Erv:       // expression switch
 
863
                                        defaultlit(&ll->n, t);
 
864
                                        if(ll->n->op == OTYPE)
 
865
                                                yyerror("type %T is not an expression", ll->n->type);
 
866
                                        else if(ll->n->type != T && !eqtype(ll->n->type, t))
 
867
                                                yyerror("case %+N in %T switch", ll->n, t);
 
868
                                        break;
 
869
                                case Etype:     // type switch
 
870
                                        if(ll->n->op == OLITERAL && istype(ll->n->type, TNIL))
 
871
                                                ;
 
872
                                        else if(ll->n->op != OTYPE && ll->n->type != T)
 
873
                                                yyerror("%#N is not a type", ll->n);
 
874
                                        break;
 
875
                                }
 
876
                        }
 
877
                }
 
878
                if(top == Etype && n->type != T) {
 
879
                        ll = ncase->list;
 
880
                        nvar = ncase->nname;
 
881
                        if(nvar != N) {
 
882
                                if(ll && ll->next == nil && ll->n->type != T && !istype(ll->n->type, TNIL)) {
 
883
                                        // single entry type switch
 
884
                                        nvar->ntype = typenod(ll->n->type);
 
885
                                } else {
 
886
                                        // multiple entry type switch or default
 
887
                                        nvar->ntype = typenod(n->type);
 
888
                                }
 
889
                        }
 
890
                }
 
891
                typechecklist(ncase->nbody, Etop);
 
892
        }
 
893
 
 
894
        lineno = lno;
 
895
}